Add Offscreen Framebuffer support

This commit is contained in:
Thraix
2023-02-05 01:04:07 +01:00
parent 9de2ff594b
commit 708b81c571
25 changed files with 597 additions and 219 deletions
+1
View File
@@ -5,3 +5,4 @@ Release/
*/Release/ */Release/
bin/ bin/
.ycm_extra_conf.py .ycm_extra_conf.py
.cache
+9 -4
View File
@@ -130,7 +130,8 @@
</Command> </Command>
</PreBuildEvent> </PreBuildEvent>
<PostBuildEvent> <PostBuildEvent>
<Command>glslc res/shaders/shader.vert -o res/shaders/vert.spv &amp;&amp; glslc res/shaders/shader.frag -o res/shaders/frag.spv</Command> <Command>
</Command>
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -157,12 +158,14 @@
</Command> </Command>
</PreBuildEvent> </PreBuildEvent>
<PostBuildEvent> <PostBuildEvent>
<Command>glslc res/shaders/shader.vert -o res/shaders/vert.spv &amp;&amp; glslc res/shaders/shader.frag -o res/shaders/frag.spv</Command> <Command>
</Command>
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\main.cpp" /> <ClCompile Include="src\main.cpp" />
<ClCompile Include="src\SwapChain.cpp" /> <ClCompile Include="src\SwapChain.cpp" />
<ClCompile Include="src\Texture2D.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\Buffer.h" /> <ClInclude Include="src\Buffer.h" />
@@ -172,6 +175,7 @@
<ClInclude Include="src\DescriptorSet.h" /> <ClInclude Include="src\DescriptorSet.h" />
<ClInclude Include="src\DescriptorPool.h" /> <ClInclude Include="src\DescriptorPool.h" />
<ClInclude Include="src\FileSystem.h" /> <ClInclude Include="src\FileSystem.h" />
<ClInclude Include="src\Framebuffer.h" />
<ClInclude Include="src\Image.h" /> <ClInclude Include="src\Image.h" />
<ClInclude Include="src\IndexBuffer.h" /> <ClInclude Include="src\IndexBuffer.h" />
<ClInclude Include="src\Pipeline.h" /> <ClInclude Include="src\Pipeline.h" />
@@ -189,13 +193,14 @@
<ClInclude Include="src\VertexDescriptor.h" /> <ClInclude Include="src\VertexDescriptor.h" />
<ClInclude Include="src\VulkanException.h" /> <ClInclude Include="src\VulkanException.h" />
<ClInclude Include="src\Window.h" /> <ClInclude Include="src\Window.h" />
<ClInclude Include="src\VertexPassthrough.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="compile.bat" /> <None Include="compile.bat" />
<None Include="res\shaders\frag.spv" /> <None Include="res\shaders\passthrough.frag" />
<None Include="res\shaders\passthrough.vert" />
<None Include="res\shaders\shader.frag" /> <None Include="res\shaders\shader.frag" />
<None Include="res\shaders\shader.vert" /> <None Include="res\shaders\shader.vert" />
<None Include="res\shaders\vert.spv" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
+11 -2
View File
@@ -21,6 +21,9 @@
<ClCompile Include="src\SwapChain.cpp"> <ClCompile Include="src\SwapChain.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\Texture2D.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\DebugMessenger.h"> <ClInclude Include="src\DebugMessenger.h">
@@ -95,6 +98,12 @@
<ClInclude Include="src\Image.h"> <ClInclude Include="src\Image.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Framebuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\VertexPassthrough.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="res\shaders\shader.frag" /> <None Include="res\shaders\shader.frag" />
@@ -102,7 +111,7 @@
<None Include="compile.bat"> <None Include="compile.bat">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</None> </None>
<None Include="res\shaders\frag.spv" /> <None Include="res\shaders\passthrough.frag" />
<None Include="res\shaders\vert.spv" /> <None Include="res\shaders\passthrough.vert" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+11
View File
@@ -0,0 +1,11 @@
#version 450
layout(set = 0, binding = 0) uniform sampler2D texSampler;
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor;
void main()
{
outColor = texture(texSampler, fragTexCoord);
}
+11
View File
@@ -0,0 +1,11 @@
#version 450
layout(location = 0) in vec2 inPosition;
layout(location = 0) out vec2 fragTexCoord;
void main()
{
gl_Position = vec4(inPosition* 0.5, 0.999, 1.0);
fragTexCoord = inPosition * 0.5 + 0.5;
}
+1 -1
View File
@@ -100,7 +100,7 @@ public:
mappedData = nullptr; mappedData = nullptr;
} }
virtual void Bind(VkCommandBuffer commandBuffer) { CP_UNIMPLEMENTED(); }; virtual void Bind(const CommandBuffer& commandBuffer) { CP_UNIMPLEMENTED(); };
void BindAsVertexBuffer(VkCommandBuffer commandBuffer) void BindAsVertexBuffer(VkCommandBuffer commandBuffer)
{ {
+6 -1
View File
@@ -41,6 +41,11 @@ public:
vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), commandBuffers.size(), commandBuffers.data()); vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), commandBuffers.size(), commandBuffers.data());
} }
operator VkCommandBuffer() const
{
return currentCommandBuffer;
}
// TODO: Test as constexpr function to see if it avoids the switch case // TODO: Test as constexpr function to see if it avoids the switch case
void Begin() void Begin()
{ {
@@ -87,7 +92,7 @@ public:
instance.SubmitGraphicsQueue({currentCommandBuffer}); instance.SubmitGraphicsQueue({currentCommandBuffer});
} }
VkCommandBuffer GetHandle() VkCommandBuffer GetHandle() const
{ {
return currentCommandBuffer; return currentCommandBuffer;
} }
+6
View File
@@ -21,6 +21,12 @@
#define CP_ERR_CONT(format, ...) std::cout << TERM_RED << " " << StringFormat(format, __VA_ARGS__) << TERM_CLEAR << std::endl #define CP_ERR_CONT(format, ...) std::cout << TERM_RED << " " << StringFormat(format, __VA_ARGS__) << TERM_CLEAR << std::endl
#define CP_UNIMPLEMENTED() CP_WARN("%s is unimplemented", __FUNCTION__) #define CP_UNIMPLEMENTED() CP_WARN("%s is unimplemented", __FUNCTION__)
#define CP_ABORT(format, ...) \
do \
{ \
CP_ERR(format, __VA_ARGS__); \
throw std::runtime_error(StringFormat(format, __VA_ARGS__)); \
} while(false)
#define CP_ASSERT(Function, format, ...) \ #define CP_ASSERT(Function, format, ...) \
do \ do \
{ \ { \
+3 -3
View File
@@ -49,11 +49,11 @@ public:
void AddTexture2D(const Texture2D& texture2D, uint32_t binding) void AddTexture2D(const Texture2D& texture2D, uint32_t binding)
{ {
VkDescriptorImageInfo imageInfo = texture2D.GetDescriptorImageInfo(); for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
for (auto&& descriptorSet : descriptorSets) { VkDescriptorImageInfo imageInfo = texture2D.GetDescriptorImageInfo(i);
VkWriteDescriptorSet descriptorWrite{}; VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = descriptorSet; descriptorWrite.dstSet = descriptorSets[i];
descriptorWrite.dstBinding = binding; descriptorWrite.dstBinding = binding;
descriptorWrite.dstArrayElement = 0; descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+3
View File
@@ -2,6 +2,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <filesystem>
#include "Common.h" #include "Common.h"
@@ -48,6 +49,8 @@ namespace FileSystem
static void WriteFile(const std::string& filename, const char* data, size_t size) static void WriteFile(const std::string& filename, const char* data, size_t size)
{ {
std::filesystem::path path{filename};
std::filesystem::create_directories(path.parent_path());
std::ofstream file(filename, std::ios::binary); std::ofstream file(filename, std::ios::binary);
CP_ASSERT(file.is_open(), "Failed to open file"); CP_ASSERT(file.is_open(), "Failed to open file");
+174
View File
@@ -0,0 +1,174 @@
#pragma once
#include "Common.h"
#include "Image.h"
#include "Instance.h"
#include "Texture2D.h"
#include <vulkan/vulkan.hpp>
// TODO: Add resizing (recreate image, depthImage, framebuffers)
class Framebuffer
{
CP_DELETE_COPY_AND_MOVE_CTOR(Framebuffer);
private:
Instance& instance;
std::unique_ptr<Texture2D> image;
std::unique_ptr<Texture2D> depthImage;
std::vector<VkFramebuffer> framebuffers;
VkRenderPass renderPass;
uint32_t width;
uint32_t height;
public:
Framebuffer(Instance& instance, uint32_t width, uint32_t height)
: instance{instance}, width{width}, height{height}
{
InitializeImages();
InitializeDepthBuffer();
InitializeRenderPass();
InitializeFramebuffers();
}
~Framebuffer()
{
for (auto& framebuffer : framebuffers)
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
}
void Bind(const CommandBuffer& commandBuffer)
{
std::vector<VkClearValue> clearValues{2};
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0};
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.framebuffer = framebuffers[instance.GetFlightIndex()];
renderPassBeginInfo.renderArea.offset = {0, 0};
renderPassBeginInfo.renderArea.extent = {width, height};
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
void Unbind(const CommandBuffer& commandBuffer)
{
vkCmdEndRenderPass(commandBuffer);
}
VkRenderPass GetRenderPass() const
{
return renderPass;
}
VkFramebuffer GetFramebuffer() const
{
return framebuffers[instance.GetFlightIndex()];
}
const Texture2D& GetTexture2D() const
{
return *image;
}
private:
void InitializeImages()
{
image = std::make_unique<Texture2D>(instance, width, height, Texture2D::Type::Dynamic, Texture2D::Format::Color);
}
void InitializeDepthBuffer()
{
depthImage = std::make_unique<Texture2D>(instance, width, height, Texture2D::Type::Static, Texture2D::Format::Depth);
}
void InitializeRenderPass()
{
VkAttachmentDescription colorAttachment{};
colorAttachment.format = VK_FORMAT_R8G8B8A8_SRGB;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentDescription depthAttachment{};
depthAttachment.format = Image::SelectDepthFormat(instance);
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference colorAttachmentRef{};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference depthAttachmentRef{};
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
std::vector<VkSubpassDependency> dependencies{2};
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
std::vector<VkAttachmentDescription> attachments{colorAttachment, depthAttachment};
VkRenderPassCreateInfo renderPassCreateInfo{};
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCreateInfo.attachmentCount = attachments.size();
renderPassCreateInfo.pAttachments = attachments.data();
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpass;
renderPassCreateInfo.dependencyCount = dependencies.size();
renderPassCreateInfo.pDependencies = dependencies.data();
CP_VK_ASSERT(vkCreateRenderPass(instance.GetDevice(), &renderPassCreateInfo, nullptr, &renderPass), "InitializeRenderPass : Failed to initialze render pass");
}
void InitializeFramebuffers()
{
framebuffers.resize(instance.GetMaxFramesInFlight());
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i)
{
std::vector<VkImageView> attachments{image->GetImageView(i), depthImage->GetImageView()};
VkFramebufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
createInfo.renderPass = renderPass;
createInfo.attachmentCount = attachments.size();
createInfo.pAttachments = attachments.data();
createInfo.width = width;
createInfo.height = height;
createInfo.layers = 1;
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "InitializeFramebuffers : Failed to initialize swap chain framebuffer");
}
}
};
+37 -6
View File
@@ -28,7 +28,7 @@ public:
createInfo.samples = VK_SAMPLE_COUNT_1_BIT; createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
createInfo.flags = 0; createInfo.flags = 0;
CP_VK_ASSERT(vkCreateImage(instance.GetDevice(), &createInfo, nullptr, image), "Failed to initialize image"); CP_VK_ASSERT(vkCreateImage(instance.GetDevice(), &createInfo, nullptr, image), "InitializeImage : Failed to initialize image");
VkMemoryRequirements memoryRequirements; VkMemoryRequirements memoryRequirements;
vkGetImageMemoryRequirements(instance.GetDevice(), *image, &memoryRequirements); vkGetImageMemoryRequirements(instance.GetDevice(), *image, &memoryRequirements);
@@ -38,7 +38,7 @@ public:
allocateInfo.allocationSize = memoryRequirements.size; allocateInfo.allocationSize = memoryRequirements.size;
allocateInfo.memoryTypeIndex = instance.FindMemoryType(memoryRequirements.memoryTypeBits, properties); allocateInfo.memoryTypeIndex = instance.FindMemoryType(memoryRequirements.memoryTypeBits, properties);
CP_VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, imageMemory), "Failed to initiallizse image memory"); CP_VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, imageMemory), "InitializeImage : Failed to initiallizse image memory");
vkBindImageMemory(instance.GetDevice(), *image, *imageMemory, 0); vkBindImageMemory(instance.GetDevice(), *image, *imageMemory, 0);
} }
@@ -60,7 +60,7 @@ public:
createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.levelCount = 1;
createInfo.subresourceRange.baseArrayLayer = 0; createInfo.subresourceRange.baseArrayLayer = 0;
createInfo.subresourceRange.layerCount = 1; createInfo.subresourceRange.layerCount = 1;
CP_VK_ASSERT(vkCreateImageView(instance.GetDevice(), &createInfo, nullptr, &imageView), "Failed to initialize image view"); CP_VK_ASSERT(vkCreateImageView(instance.GetDevice(), &createInfo, nullptr, &imageView), "InitializeImageView : Failed to initialize image view");
return imageView; return imageView;
} }
@@ -115,12 +115,19 @@ public:
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
} }
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
else else
{ {
throw std::invalid_argument("Unsupported layout transition"); CP_ABORT("TransitioinImageLayout : Unsupported layout transition");
} }
vkCmdPipelineBarrier(commandBuffer.GetHandle(), srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); vkCmdPipelineBarrier(commandBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
} }
static void CopyBufferToImage(Instance& instance, const Buffer& buffer, VkImage image, uint32_t width, uint32_t height) static void CopyBufferToImage(Instance& instance, const Buffer& buffer, VkImage image, uint32_t width, uint32_t height)
@@ -140,7 +147,13 @@ public:
region.imageOffset = {0, 0, 0}; region.imageOffset = {0, 0, 0};
region.imageExtent = {width, height, 1}; region.imageExtent = {width, height, 1};
vkCmdCopyBufferToImage(commandBuffer.GetHandle(), buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region); vkCmdCopyBufferToImage(commandBuffer, buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
}
static VkFormat SelectDepthFormat(Instance& instance)
{
return SelectSupportedFormat(instance, {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
} }
private: private:
@@ -148,4 +161,22 @@ private:
{ {
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT; return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
} }
static VkFormat SelectSupportedFormat(Instance& instance, const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
{
for (VkFormat format : candidates)
{
VkFormatProperties properties;
vkGetPhysicalDeviceFormatProperties(instance.GetPhysicalDevice(), format, &properties);
if(tiling == VK_IMAGE_TILING_LINEAR && (properties.linearTilingFeatures & features) == features)
{
return format;
}
else if (tiling == VK_IMAGE_TILING_OPTIMAL && (properties.optimalTilingFeatures & features) == features)
{
return format;
}
}
CP_ABORT("SelectSupportedFormat : Failed to select supported format");
}
}; };
+2 -2
View File
@@ -12,12 +12,12 @@ public:
: Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexCount * sizeof(uint16_t), 1}, indexCount{indexCount} : Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexCount * sizeof(uint16_t), 1}, indexCount{indexCount}
{} {}
void Bind(VkCommandBuffer commandBuffer) override void Bind(const CommandBuffer& commandBuffer) override
{ {
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16); vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
} }
void Draw(VkCommandBuffer commandBuffer) void Draw(const CommandBuffer& commandBuffer)
{ {
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0); vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
} }
+3 -2
View File
@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Common.h" #include "Common.h"
#include "CommandBuffer.h"
#include "Instance.h" #include "Instance.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "DescriptorSet.h" #include "DescriptorSet.h"
@@ -40,7 +41,7 @@ public:
} }
} }
void Bind(VkCommandBuffer commandBuffer) void Bind(const CommandBuffer& commandBuffer)
{ {
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
@@ -231,7 +232,7 @@ private:
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo; graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
graphicsPipelineCreateInfo.layout = pipelineLayout; graphicsPipelineCreateInfo.layout = pipelineLayout;
graphicsPipelineCreateInfo.renderPass = instance.GetSwapChain().GetRenderPass(); graphicsPipelineCreateInfo.renderPass = creator.renderPass;
graphicsPipelineCreateInfo.subpass = 0; graphicsPipelineCreateInfo.subpass = 0;
graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
graphicsPipelineCreateInfo.basePipelineIndex = -1; graphicsPipelineCreateInfo.basePipelineIndex = -1;
+4 -3
View File
@@ -25,10 +25,11 @@ private:
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT; VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE; VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
VkRenderPass renderPass = VK_NULL_HANDLE;
public: public:
PipelineCreator(const std::string& vertexShader, const std::string& fragmentShader) PipelineCreator(VkRenderPass renderPass, const std::string& vertexShader, const std::string& fragmentShader)
: vertexShader{vertexShader}, fragmentShader{fragmentShader} : vertexShader{vertexShader}, fragmentShader{fragmentShader}, renderPass{renderPass}
{} {}
void SetVertexDescriptor(const VertexDescriptor& descriptor) void SetVertexDescriptor(const VertexDescriptor& descriptor)
@@ -38,7 +39,7 @@ public:
void AddDescriptorSetLayoutBinding(uint32_t set, uint32_t binding, VkDescriptorType type, uint32_t count, VkShaderStageFlags stageFlags) void AddDescriptorSetLayoutBinding(uint32_t set, uint32_t binding, VkDescriptorType type, uint32_t count, VkShaderStageFlags stageFlags)
{ {
CP_ASSERT(set <= descriptorSetLayouts.size(), "Cannot add descriptor set with set number greater than the current set count"); CP_ASSERT(set <= descriptorSetLayouts.size(), "AddDescriptorSetLayoutBinding : Cannot add descriptor set with set number greater than the current set count");
descriptorSetLayouts[set].emplace_back(DescriptorSetBinding{binding, type, count, stageFlags}); descriptorSetLayouts[set].emplace_back(DescriptorSetBinding{binding, type, count, stageFlags});
} }
+1 -1
View File
@@ -89,7 +89,7 @@ private:
VkShaderModule InitializeShaderModuleFromGlslFile(const std::string& filename, shaderc_shader_kind shaderType) VkShaderModule InitializeShaderModuleFromGlslFile(const std::string& filename, shaderc_shader_kind shaderType)
{ {
std::string spvFilename = filename + ".spv"; std::string spvFilename = ".cache/" + filename + ".spv";
try try
{ {
if (FileSystem::FileExists(spvFilename)) if (FileSystem::FileExists(spvFilename))
+27 -33
View File
@@ -1,8 +1,10 @@
#include "SwapChain.h" #include "SwapChain.h"
#include "CommandBuffer.h"
#include "Image.h" #include "Image.h"
#include "Instance.h" #include "Instance.h"
#include "QueueFamilies.h" #include "QueueFamilies.h"
#include "Texture2D.h"
#include <glfw/glfw3.h> #include <glfw/glfw3.h>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
@@ -50,6 +52,28 @@ SwapChain::~SwapChain()
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr); vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
} }
void SwapChain::BeginFrameBuffer(const CommandBuffer& commandBuffer) const
{
std::vector<VkClearValue> clearValues{2};
clearValues[0].color = {{0.02f, 0.02f, 0.02f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0};
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.framebuffer = framebuffers[imageIndex];
renderPassBeginInfo.renderArea.offset = {0, 0};
renderPassBeginInfo.renderArea.extent = extent;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
void SwapChain::EndFrameBuffer(const CommandBuffer& commandBuffer) const
{
vkCmdEndRenderPass(commandBuffer);
}
VkSwapchainKHR SwapChain::GetHandle() const VkSwapchainKHR SwapChain::GetHandle() const
{ {
return handle; return handle;
@@ -182,11 +206,7 @@ void SwapChain::InitializeImageViews()
void SwapChain::InitializeDepthBuffer() void SwapChain::InitializeDepthBuffer()
{ {
VkFormat depthFormat = SelectDepthFormat(); depthImage = std::make_unique<Texture2D>(instance, extent.width, extent.height, Texture2D::Type::Static, Texture2D::Format::Depth);
Image::InitializeImage(instance, extent.width, extent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &depthImage, &depthImageMemory);
Image::TransitionImageLayout(instance, depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
depthImageView = Image::InitializeImageView(instance, depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
} }
void SwapChain::InitializeRenderPass() void SwapChain::InitializeRenderPass()
@@ -202,7 +222,7 @@ void SwapChain::InitializeRenderPass()
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentDescription depthAttachment{}; VkAttachmentDescription depthAttachment{};
depthAttachment.format = SelectDepthFormat(); depthAttachment.format = Image::SelectDepthFormat(instance);
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@@ -252,7 +272,7 @@ void SwapChain::InitializeFramebuffers()
for (size_t i = 0; i < imageViews.size(); ++i) for (size_t i = 0; i < imageViews.size(); ++i)
{ {
std::vector<VkImageView> attachments{imageViews[i], depthImageView}; std::vector<VkImageView> attachments{imageViews[i], depthImage->GetImageView()};
VkFramebufferCreateInfo createInfo{}; VkFramebufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
@@ -269,9 +289,6 @@ void SwapChain::InitializeFramebuffers()
void SwapChain::Destroy() void SwapChain::Destroy()
{ {
vkDestroyImage(instance.GetDevice(), depthImage, nullptr);
vkFreeMemory(instance.GetDevice(), depthImageMemory, nullptr);
vkDestroyImageView(instance.GetDevice(), depthImageView, nullptr);
for (auto&& framebuffer : framebuffers) for (auto&& framebuffer : framebuffers)
{ {
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr); vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
@@ -295,29 +312,6 @@ VkSurfaceFormatKHR SwapChain::SelectSwapSurfaceFormat(const std::vector<VkSurfac
return availableFormats[0]; return availableFormats[0];
} }
VkFormat SwapChain::SelectDepthFormat()
{
return SelectSupportedFormat({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
}
VkFormat SwapChain::SelectSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
{
for (VkFormat format : candidates)
{
VkFormatProperties properties;
vkGetPhysicalDeviceFormatProperties(instance.GetPhysicalDevice(), format, &properties);
if(tiling == VK_IMAGE_TILING_LINEAR && (properties.linearTilingFeatures & features) == features)
{
return format;
}
else if (tiling == VK_IMAGE_TILING_OPTIMAL && (properties.optimalTilingFeatures & features) == features)
{
return format;
}
}
throw std::runtime_error("Failed to select supported format");
}
VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
{ {
return VK_PRESENT_MODE_FIFO_KHR; return VK_PRESENT_MODE_FIFO_KHR;
+5 -7
View File
@@ -7,6 +7,8 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
class Instance; class Instance;
class CommandBuffer;
class Texture2D;
struct SwapChainSupportDetails struct SwapChainSupportDetails
{ {
@@ -24,24 +26,22 @@ class SwapChain final
private: private:
Instance& instance; Instance& instance;
// Created by the class
VkSwapchainKHR handle; VkSwapchainKHR handle;
VkRenderPass renderPass; VkRenderPass renderPass;
VkFormat imageFormat; VkFormat imageFormat;
VkExtent2D extent; VkExtent2D extent;
VkImage depthImage; std::unique_ptr<Texture2D> depthImage;
VkImageView depthImageView;
VkDeviceMemory depthImageMemory;
std::vector<VkImageView> imageViews; std::vector<VkImageView> imageViews;
std::vector<VkImage> images; std::vector<VkImage> images;
std::vector<VkFramebuffer> framebuffers; std::vector<VkFramebuffer> framebuffers;
uint32_t imageIndex; uint32_t imageIndex;
public: public:
SwapChain(Instance& instance); SwapChain(Instance& instance);
~SwapChain(); ~SwapChain();
void BeginFrameBuffer(const CommandBuffer& commandBuffer) const;
void EndFrameBuffer(const CommandBuffer& commandBuffer) const;
VkSwapchainKHR GetHandle() const; VkSwapchainKHR GetHandle() const;
VkRenderPass GetRenderPass() const; VkRenderPass GetRenderPass() const;
VkExtent2D GetExtent() const; VkExtent2D GetExtent() const;
@@ -60,8 +60,6 @@ private:
void Destroy(); void Destroy();
VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats); VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
VkFormat SelectDepthFormat();
VkFormat SelectSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
VkPresentModeKHR SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes); VkPresentModeKHR SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities); VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities);
}; };
+150
View File
@@ -0,0 +1,150 @@
#include "Texture2D.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
Texture2D::Texture2D(Instance& instance, const std::string& filename)
: instance{instance}, type{Type::Static}, format{Format::Image}
{
InitializeTextureImage(filename);
InitializeSampler();
}
Texture2D::Texture2D(Instance& instance, int width, int height, Type type, Format format)
: instance{instance}, type{type}, format{format}
{
InitializeTexture(width, height);
InitializeSampler();
}
Texture2D::~Texture2D()
{
for(auto&& image : images)
vkDestroyImage(instance.GetDevice(), image, nullptr);
for(auto&& imageMemory : imageMemories)
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
for(auto&& imageView : imageViews)
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
}
VkDescriptorImageInfo Texture2D::GetDescriptorImageInfo(int index) const
{
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.sampler = sampler;
switch (type) {
case Type::Static:
imageInfo.imageView = imageViews.front();
break;
case Type::Dynamic:
CP_ASSERT(index >= 0 && index < imageViews.size(), "GetDescriptorImageInfo : index out of bound for dynamic texture");
imageInfo.imageView = imageViews[index];
break;
default:
CP_ABORT("GetDescriptorImageInfo : Unreachable switch case");
}
return imageInfo;
}
VkImageView Texture2D::GetImageView() const
{
CP_ASSERT(type == Type::Static, "GetImageView : Texture2D is not static");
return imageViews.front();
}
VkImageView Texture2D::GetImageView(int index)
{
CP_ASSERT(type == Type::Dynamic && index >= 0 && index < imageViews.size(), "GetImageView : Texture2D is not dynamic or index out of bound for SystemTexture");
return imageViews[index];
}
void Texture2D::InitializeTextureImage(const std::string& filename)
{
int texWidth;
int texHeight;
int texChannels;
stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
CP_ASSERT(pixels, "InitializeTextureImage : Failed to load texture image");
VkDeviceSize bufferSize = texWidth * texHeight * 4;
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
void* data = stagingBuffer.Map();
memcpy(data, pixels, bufferSize);
stagingBuffer.Unmap();
stbi_image_free(pixels);
images.resize(1);
imageMemories.resize(1);
imageViews.resize(1);
Image::InitializeImage(instance, texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images.front(), &imageMemories.front());
Image::TransitionImageLayout(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
Image::CopyBufferToImage(instance, stagingBuffer, images.front(), texWidth, texHeight);
Image::TransitionImageLayout(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
imageViews[0] = Image::InitializeImageView(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
}
void Texture2D::InitializeTexture(int width, int height)
{
int count = 1;
if (type == Type::Dynamic)
count = instance.GetMaxFramesInFlight();
images.resize(count);
imageMemories.resize(count);
imageViews.resize(count);
for (size_t i = 0; i < images.size(); i++)
{
switch (format)
{
case Format::Color:
{
Image::InitializeImage(instance, width, height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images[i], &imageMemories[i]);
// Image::TransitionImageLayout(instance, images[i], VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
imageViews[i] = Image::InitializeImageView(instance, images[i], VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
break;
}
case Format::Depth:
{
VkFormat depthFormat = Image::SelectDepthFormat(instance);
Image::InitializeImage(instance, width, height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images[i], &imageMemories[i]);
// Image::TransitionImageLayout(instance, images[i], depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
imageViews[i] = Image::InitializeImageView(instance, images[i], depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
break;
}
case Format::Image:
{
CP_ABORT("InitializeTexture : Image format currently not supported");
}
default:
CP_ABORT("InitializeTexture : Unreachable switch case");
}
}
}
void Texture2D::InitializeSampler()
{
VkPhysicalDeviceProperties properties{};
vkGetPhysicalDeviceProperties(instance.GetPhysicalDevice(), &properties);
VkSamplerCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
createInfo.magFilter = VK_FILTER_LINEAR;
createInfo.minFilter = VK_FILTER_LINEAR;
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
createInfo.anisotropyEnable = VK_TRUE;
createInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
createInfo.unnormalizedCoordinates = VK_FALSE;
createInfo.compareEnable = VK_FALSE;
createInfo.compareOp = VK_COMPARE_OP_ALWAYS;
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
createInfo.mipLodBias = 0.0f;
createInfo.minLod = 0.0f;
createInfo.maxLod = 0.0f;
CP_VK_ASSERT(vkCreateSampler(instance.GetDevice(), &createInfo, nullptr, &sampler), "InitializeSampler : Failed to initialize texture sampler");
}
+25 -95
View File
@@ -6,110 +6,40 @@
#include "Image.h" #include "Image.h"
#include "Instance.h" #include "Instance.h"
#define STB_IMAGE_IMPLEMENTATION // TODO: Separate Texture2D and Framebuffer Attachments
#include <stb/stb_image.h>
class Texture2D class Texture2D
{ {
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D); CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D);
public:
enum class Type
{
Static, Dynamic
};
enum class Format
{
Image, Color, Depth
};
private: private:
Instance& instance; Instance& instance;
VkImage image; std::vector<VkImage> images;
VkDeviceMemory imageMemory; std::vector<VkDeviceMemory> imageMemories;
VkImageView imageView; std::vector<VkImageView> imageViews;
VkSampler sampler; VkSampler sampler;
Type type;
Format format;
public: public:
Texture2D(Instance& instance, const std::string& filename) Texture2D(Instance& instance, const std::string& filename);
: instance{instance} Texture2D(Instance& instance, int width, int height, Type type, Format format);
{ ~Texture2D();
InitializeTextureImage(filename);
InitializeSampler();
}
~Texture2D() VkDescriptorImageInfo GetDescriptorImageInfo(int index) const;
{ VkImageView GetImageView() const;
vkDestroyImage(instance.GetDevice(), image, nullptr); VkImageView GetImageView(int index);
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
}
VkDescriptorImageInfo GetDescriptorImageInfo() const
{
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.imageView = imageView;
imageInfo.sampler = sampler;
return imageInfo;
}
private: private:
void InitializeTextureImage(const std::string& filename) void InitializeTextureImage(const std::string& filename);
{ void InitializeTexture(int width, int height);
int texWidth; void InitializeSampler();
int texHeight;
int texChannels;
stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
CP_ASSERT(pixels, "Failed to load texture image");
VkDeviceSize bufferSize = texWidth * texHeight * 4;
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
void* data = stagingBuffer.Map();
memcpy(data, pixels, bufferSize);
stagingBuffer.Unmap();
stbi_image_free(pixels);
Image::InitializeImage(instance, texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &image, &imageMemory);
Image::TransitionImageLayout(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
Image::CopyBufferToImage(instance, stagingBuffer, image, texWidth, texHeight);
Image::TransitionImageLayout(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
imageView = Image::InitializeImageView(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
}
void InitializeSampler()
{
VkPhysicalDeviceProperties properties{};
vkGetPhysicalDeviceProperties(instance.GetPhysicalDevice(), &properties);
VkSamplerCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
createInfo.magFilter = VK_FILTER_LINEAR;
createInfo.minFilter = VK_FILTER_LINEAR;
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
createInfo.anisotropyEnable = VK_TRUE;
createInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
createInfo.unnormalizedCoordinates = VK_FALSE;
createInfo.compareEnable = VK_FALSE;
createInfo.compareOp = VK_COMPARE_OP_ALWAYS;
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
createInfo.mipLodBias = 0.0f;
createInfo.minLod = 0.0f;
createInfo.maxLod = 0.0f;
CP_VK_ASSERT(vkCreateSampler(instance.GetDevice(), &createInfo, nullptr, &sampler), "Failed to initialize texture sampler");
}
VkImageView CreateImageView(VkImage image)
{
VkImageView imageView;
VkImageViewCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
createInfo.image = image;
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
createInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
createInfo.subresourceRange.baseMipLevel = 0;
createInfo.subresourceRange.levelCount = 1;
createInfo.subresourceRange.baseArrayLayer = 0;
createInfo.subresourceRange.layerCount = 1;
CP_VK_ASSERT(vkCreateImageView(instance.GetDevice(), &createInfo, nullptr, &imageView), "Failed to initialize ImageView");
return imageView;
}
}; };
+1 -1
View File
@@ -22,7 +22,7 @@ public:
} }
} }
void Bind(VkCommandBuffer commandBuffer) override void Bind(const CommandBuffer& commandBuffer) override
{ {
std::vector<VkBuffer> buffers{bindingOffsets.size(), handle}; std::vector<VkBuffer> buffers{bindingOffsets.size(), handle};
vkCmdBindVertexBuffers(commandBuffer, 0, bindingOffsets.size(), buffers.data(), bindingOffsets.data()); vkCmdBindVertexBuffers(commandBuffer, 0, bindingOffsets.size(), buffers.data(), bindingOffsets.data());
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <glm/glm.hpp>
#include <vulkan/vulkan.hpp>
#include "VertexDescriptor.h"
struct VertexPassthrough {
glm::vec2 texCoord;
static VertexDescriptor GetDescriptor()
{
VertexDescriptor descriptor{};
descriptor.AddAttribute<VertexPassthrough>(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(VertexPassthrough , texCoord));
return descriptor;
}
};
+64 -32
View File
@@ -1,6 +1,7 @@
#include "Buffer.h" #include "Buffer.h"
#include "DescriptorPool.h" #include "DescriptorPool.h"
#include "DescriptorSet.h" #include "DescriptorSet.h"
#include "Framebuffer.h"
#include "IndexBuffer.h" #include "IndexBuffer.h"
#include "Instance.h" #include "Instance.h"
#include "Pipeline.h" #include "Pipeline.h"
@@ -9,6 +10,7 @@
#include "UniformBuffer.h" #include "UniformBuffer.h"
#include "Vertex.h" #include "Vertex.h"
#include "VertexBuffer.h" #include "VertexBuffer.h"
#include "VertexPassthrough.h"
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <chrono> #include <chrono>
@@ -35,6 +37,17 @@ const std::vector<uint16_t> indices = {
4, 5, 6, 6, 7, 4 4, 5, 6, 6, 7, 4
}; };
const std::vector<VertexPassthrough> verticesPassthrough = {
VertexPassthrough{{-1.0f, -1.0f}},
VertexPassthrough{{ 1.0f, -1.0f}},
VertexPassthrough{{ 1.0f, 1.0f}},
VertexPassthrough{{-1.0f, 1.0f}},
};
const std::vector<uint16_t> indicesPassthrough = {
0, 1, 2, 2, 3, 0,
};
struct alignas(64) ShaderUniform struct alignas(64) ShaderUniform
{ {
alignas(16) glm::mat4 projection; alignas(16) glm::mat4 projection;
@@ -56,10 +69,17 @@ private:
std::unique_ptr<IndexBuffer> indexBuffer; std::unique_ptr<IndexBuffer> indexBuffer;
std::unique_ptr<CommandBuffer> commandBuffer; std::unique_ptr<CommandBuffer> commandBuffer;
std::unique_ptr<Framebuffer> framebuffer;
std::unique_ptr<Pipeline> graphicsPipelinePassthrough;
std::unique_ptr<VertexBuffer> vertexBufferPassthrough;
std::unique_ptr<IndexBuffer> indexBufferPassthrough;
std::unique_ptr<DescriptorSet> descriptorSetPassthrough;
public: public:
Application() Application()
{ {
InitializeInstance(); InitializeInstance();
InitializeFrameBuffer();
InitializeGraphicsPipeline(); InitializeGraphicsPipeline();
InitializeTextureSampler(); InitializeTextureSampler();
InitializeUniformBuffer(); InitializeUniformBuffer();
@@ -94,7 +114,12 @@ private:
void InitializeInstance() void InitializeInstance()
{ {
instance = std::make_unique<Instance>("Vulkan Tutorial"); instance = std::make_unique<Instance>("Copium Engine");
}
void InitializeFrameBuffer()
{
framebuffer = std::make_unique<Framebuffer>(*instance, instance->GetSwapChain().GetExtent().width, instance->GetSwapChain().GetExtent().height);
} }
void InitializeTextureSampler() void InitializeTextureSampler()
@@ -114,29 +139,43 @@ private:
descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0)); descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
descriptorSet->AddUniform(*shaderUniformBuffer, 0); descriptorSet->AddUniform(*shaderUniformBuffer, 0);
descriptorSet->AddTexture2D(*texture2D, 1); descriptorSet->AddTexture2D(*texture2D, 1);
descriptorSetPassthrough = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipelinePassthrough->GetDescriptorSetLayout(0));
descriptorSetPassthrough->AddTexture2D(framebuffer->GetTexture2D(), 0);
} }
void InitializeGraphicsPipeline() void InitializeGraphicsPipeline()
{ {
PipelineCreator creator{"res/shaders/shader.vert", "res/shaders/shader.frag"}; PipelineCreator creator{framebuffer->GetRenderPass(), "res/shaders/shader.vert", "res/shaders/shader.frag"};
creator.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT); creator.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
creator.AddDescriptorSetLayoutBinding(0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); creator.AddDescriptorSetLayoutBinding(0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
creator.SetVertexDescriptor(Vertex::GetDescriptor()); creator.SetVertexDescriptor(Vertex::GetDescriptor());
creator.SetCullMode(VK_CULL_MODE_NONE); creator.SetCullMode(VK_CULL_MODE_NONE);
graphicsPipeline = std::make_unique<Pipeline>(*instance, creator); graphicsPipeline = std::make_unique<Pipeline>(*instance, creator);
PipelineCreator creatorPassthrough{instance->GetSwapChain().GetRenderPass(), "res/shaders/passthrough.vert", "res/shaders/passthrough.frag"};
creatorPassthrough.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
creatorPassthrough.SetVertexDescriptor(VertexPassthrough::GetDescriptor());
creatorPassthrough.SetCullMode(VK_CULL_MODE_NONE);
graphicsPipelinePassthrough = std::make_unique<Pipeline>(*instance, creatorPassthrough);
} }
void InitializeVertexBuffer() void InitializeVertexBuffer()
{ {
vertexBuffer = std::make_unique<VertexBuffer>(*instance, Vertex::GetDescriptor(), vertices.size()); vertexBuffer = std::make_unique<VertexBuffer>(*instance, Vertex::GetDescriptor(), vertices.size());
vertexBuffer->Update(0, (void*)vertices.data()); vertexBuffer->Update(0, (void*)vertices.data());
vertexBufferPassthrough = std::make_unique<VertexBuffer>(*instance, VertexPassthrough::GetDescriptor(), verticesPassthrough.size());
vertexBufferPassthrough->Update(0, (void*)verticesPassthrough.data());
} }
void InitializeIndexBuffer() void InitializeIndexBuffer()
{ {
VkDeviceSize bufferSize = sizeof(uint16_t) * indices.size();
indexBuffer = std::make_unique<IndexBuffer>(*instance, indices.size()); indexBuffer = std::make_unique<IndexBuffer>(*instance, indices.size());
indexBuffer->UpdateStaging((void*)indices.data()); indexBuffer->UpdateStaging((void*)indices.data());
indexBufferPassthrough = std::make_unique<IndexBuffer>(*instance, indicesPassthrough.size());
indexBufferPassthrough->UpdateStaging((void*)indicesPassthrough.data());
} }
void InitializeCommandBuffer() void InitializeCommandBuffer()
@@ -151,30 +190,32 @@ private:
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0}; clearValues[1].depthStencil = {1.0f, 0};
// TODO: framebuffer->Bind();
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = instance->GetSwapChain().GetRenderPass();
renderPassBeginInfo.framebuffer = instance->GetSwapChain().GetFramebuffer();
renderPassBeginInfo.renderArea.offset = {0, 0};
renderPassBeginInfo.renderArea.extent = instance->GetSwapChain().GetExtent();
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer->GetHandle(), &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
graphicsPipeline->Bind(commandBuffer->GetHandle());
framebuffer->Bind(*commandBuffer);
graphicsPipeline->Bind(*commandBuffer);
UpdateUniformBuffer(); UpdateUniformBuffer();
vertexBuffer->Bind(commandBuffer->GetHandle()); vertexBuffer->Bind(*commandBuffer);
indexBuffer->Bind(commandBuffer->GetHandle()); indexBuffer->Bind(*commandBuffer);
graphicsPipeline->SetDescriptorSet(0, *descriptorSet); graphicsPipeline->SetDescriptorSet(0, *descriptorSet);
graphicsPipeline->BindDescriptorSets(commandBuffer->GetHandle()); graphicsPipeline->BindDescriptorSets(commandBuffer->GetHandle());
indexBuffer->Draw(commandBuffer->GetHandle()); indexBuffer->Draw(*commandBuffer);
framebuffer->Unbind(*commandBuffer);
vkCmdEndRenderPass(commandBuffer->GetHandle()); instance->GetSwapChain().BeginFrameBuffer(*commandBuffer);
graphicsPipelinePassthrough->Bind(*commandBuffer);
graphicsPipelinePassthrough->SetDescriptorSet(0, *descriptorSetPassthrough);
graphicsPipelinePassthrough->BindDescriptorSets(commandBuffer->GetHandle());
vertexBufferPassthrough->Bind(*commandBuffer);
indexBufferPassthrough->Bind(*commandBuffer);
indexBufferPassthrough->Draw(*commandBuffer);
instance->GetSwapChain().EndFrameBuffer(*commandBuffer);
commandBuffer->End(); commandBuffer->End();
} }
@@ -192,24 +233,15 @@ private:
shaderUniformBuffer->Update(shaderUniform); shaderUniformBuffer->Update(shaderUniform);
} }
VkShaderModule InitializeShaderModule(const std::vector<char>& code)
{
VkShaderModuleCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
VkShaderModule shaderModule;
CP_VK_ASSERT(vkCreateShaderModule(instance->GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
return shaderModule;
}
}; };
void func(const int* ptr) {
*const_cast<int*>(ptr) = 20;
}
int main() int main()
{ {
CP_ASSERT(glfwInit() == GLFW_TRUE, "Failed to initialize the glfw context"); CP_ASSERT(glfwInit() == GLFW_TRUE, "main : Failed to initialize the glfw context");
{ {
Application application; Application application;
Timer timer; Timer timer;