From 708b81c57192f516856c674cb6fd7fbafaab3e3e Mon Sep 17 00:00:00 2001 From: Thraix Date: Sun, 5 Feb 2023 01:04:07 +0100 Subject: [PATCH] Add Offscreen Framebuffer support --- .gitignore | 1 + Vulkan/Vulkan.vcxproj | 13 ++- Vulkan/Vulkan.vcxproj.filters | 13 ++- Vulkan/res/shaders/passthrough.frag | 11 ++ Vulkan/res/shaders/passthrough.vert | 11 ++ Vulkan/res/shaders/shader.frag | 4 +- Vulkan/res/shaders/shader.vert | 18 +-- Vulkan/src/Buffer.h | 2 +- Vulkan/src/CommandBuffer.h | 7 +- Vulkan/src/Common.h | 20 ++-- Vulkan/src/DescriptorSet.h | 6 +- Vulkan/src/FileSystem.h | 3 + Vulkan/src/Framebuffer.h | 174 ++++++++++++++++++++++++++++ Vulkan/src/Image.h | 43 ++++++- Vulkan/src/IndexBuffer.h | 4 +- Vulkan/src/Pipeline.h | 5 +- Vulkan/src/PipelineCreator.h | 7 +- Vulkan/src/Shader.h | 2 +- Vulkan/src/SwapChain.cpp | 60 +++++----- Vulkan/src/SwapChain.h | 12 +- Vulkan/src/Texture2D.cpp | 150 ++++++++++++++++++++++++ Vulkan/src/Texture2D.h | 120 ++++--------------- Vulkan/src/VertexBuffer.h | 2 +- Vulkan/src/VertexPassthrough.h | 16 +++ Vulkan/src/main.cpp | 112 +++++++++++------- 25 files changed, 597 insertions(+), 219 deletions(-) create mode 100644 Vulkan/res/shaders/passthrough.frag create mode 100644 Vulkan/res/shaders/passthrough.vert create mode 100644 Vulkan/src/Framebuffer.h create mode 100644 Vulkan/src/Texture2D.cpp create mode 100644 Vulkan/src/VertexPassthrough.h diff --git a/.gitignore b/.gitignore index 516effa..0a2c069 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ Release/ */Release/ bin/ .ycm_extra_conf.py +.cache diff --git a/Vulkan/Vulkan.vcxproj b/Vulkan/Vulkan.vcxproj index 8708a94..8b10657 100644 --- a/Vulkan/Vulkan.vcxproj +++ b/Vulkan/Vulkan.vcxproj @@ -130,7 +130,8 @@ - glslc res/shaders/shader.vert -o res/shaders/vert.spv && glslc res/shaders/shader.frag -o res/shaders/frag.spv + + @@ -157,12 +158,14 @@ - glslc res/shaders/shader.vert -o res/shaders/vert.spv && glslc res/shaders/shader.frag -o res/shaders/frag.spv + + + @@ -172,6 +175,7 @@ + @@ -189,13 +193,14 @@ + - + + - diff --git a/Vulkan/Vulkan.vcxproj.filters b/Vulkan/Vulkan.vcxproj.filters index 841e1ff..b63afde 100644 --- a/Vulkan/Vulkan.vcxproj.filters +++ b/Vulkan/Vulkan.vcxproj.filters @@ -21,6 +21,9 @@ Source Files + + Source Files + @@ -95,6 +98,12 @@ Header Files + + Header Files + + + Header Files + @@ -102,7 +111,7 @@ Source Files - - + + \ No newline at end of file diff --git a/Vulkan/res/shaders/passthrough.frag b/Vulkan/res/shaders/passthrough.frag new file mode 100644 index 0000000..886651e --- /dev/null +++ b/Vulkan/res/shaders/passthrough.frag @@ -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); +} \ No newline at end of file diff --git a/Vulkan/res/shaders/passthrough.vert b/Vulkan/res/shaders/passthrough.vert new file mode 100644 index 0000000..544e962 --- /dev/null +++ b/Vulkan/res/shaders/passthrough.vert @@ -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; +} \ No newline at end of file diff --git a/Vulkan/res/shaders/shader.frag b/Vulkan/res/shaders/shader.frag index 27f1330..5b6e065 100644 --- a/Vulkan/res/shaders/shader.frag +++ b/Vulkan/res/shaders/shader.frag @@ -10,6 +10,6 @@ layout(location = 3) in vec3 fragLightPos; layout(location = 0) out vec4 outColor; void main() { - float scale = 0.45 + max(dot(vec3(0, 1, 0), normalize(fragLightPos - fragPosition)), 0.0); - outColor = vec4(fragColor, 1.0) * texture(texSampler, fragTexCoord) * scale; + float scale = 0.45 + max(dot(vec3(0, 1, 0), normalize(fragLightPos - fragPosition)), 0.0); + outColor = vec4(fragColor, 1.0) * texture(texSampler, fragTexCoord) * scale; } diff --git a/Vulkan/res/shaders/shader.vert b/Vulkan/res/shaders/shader.vert index e2f1a3a..86e76e9 100644 --- a/Vulkan/res/shaders/shader.vert +++ b/Vulkan/res/shaders/shader.vert @@ -2,10 +2,10 @@ layout(set = 0, binding = 0) uniform SceneUniformBufferObject { - mat4 projection; - mat4 view; - mat4 model; - vec3 lightPos; + mat4 projection; + mat4 view; + mat4 model; + vec3 lightPos; } ubo; layout(location = 0) in vec3 inPosition; @@ -18,9 +18,9 @@ layout(location = 2) out vec3 fragPosition; layout(location = 3) out vec3 fragLightPos; void main() { - gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition, 1.0); - fragColor = inColor; - fragTexCoord = inTexCoord; - fragPosition = vec3(ubo.model * vec4(inPosition, 1.0)); - fragLightPos = ubo.lightPos; + gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition, 1.0); + fragColor = inColor; + fragTexCoord = inTexCoord; + fragPosition = vec3(ubo.model * vec4(inPosition, 1.0)); + fragLightPos = ubo.lightPos; } \ No newline at end of file diff --git a/Vulkan/src/Buffer.h b/Vulkan/src/Buffer.h index 9298bb8..b6252ef 100644 --- a/Vulkan/src/Buffer.h +++ b/Vulkan/src/Buffer.h @@ -100,7 +100,7 @@ public: mappedData = nullptr; } - virtual void Bind(VkCommandBuffer commandBuffer) { CP_UNIMPLEMENTED(); }; + virtual void Bind(const CommandBuffer& commandBuffer) { CP_UNIMPLEMENTED(); }; void BindAsVertexBuffer(VkCommandBuffer commandBuffer) { diff --git a/Vulkan/src/CommandBuffer.h b/Vulkan/src/CommandBuffer.h index c417a4f..1050e4d 100644 --- a/Vulkan/src/CommandBuffer.h +++ b/Vulkan/src/CommandBuffer.h @@ -41,6 +41,11 @@ public: 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 void Begin() { @@ -87,7 +92,7 @@ public: instance.SubmitGraphicsQueue({currentCommandBuffer}); } - VkCommandBuffer GetHandle() + VkCommandBuffer GetHandle() const { return currentCommandBuffer; } diff --git a/Vulkan/src/Common.h b/Vulkan/src/Common.h index 2788b96..c98a280 100644 --- a/Vulkan/src/Common.h +++ b/Vulkan/src/Common.h @@ -21,11 +21,17 @@ #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_ABORT(format, ...) \ + do \ + { \ + CP_ERR(format, __VA_ARGS__); \ + throw std::runtime_error(StringFormat(format, __VA_ARGS__)); \ + } while(false) #define CP_ASSERT(Function, format, ...) \ - do \ + do \ { \ if(!(Function)) \ - { \ + { \ CP_ERR(format, __VA_ARGS__); \ throw std::runtime_error(StringFormat(format, __VA_ARGS__)); \ } \ @@ -40,16 +46,16 @@ } \ } while(false) #define CP_DELETE_COPY_AND_MOVE_CTOR(ClassName) \ - ClassName(ClassName&&) = delete; \ - ClassName(const ClassName&) = delete; \ - ClassName& operator=(ClassName&&) = delete; \ - ClassName& operator=(const ClassName&) = delete + ClassName(ClassName&&) = delete; \ + ClassName(const ClassName&) = delete; \ + ClassName& operator=(ClassName&&) = delete; \ + ClassName& operator=(const ClassName&) = delete template std::string StringFormat(const std::string& format, Args... args) { int size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; - CP_ASSERT(size > 0, "Error during formatting"); + CP_ASSERT(size > 0, "Error during formatting"); std::unique_ptr buf(new char[size]); std::snprintf(buf.get(), size, format.c_str(), args...); return std::string(buf.get(), buf.get() + size - 1); diff --git a/Vulkan/src/DescriptorSet.h b/Vulkan/src/DescriptorSet.h index b4dd783..8d12ac7 100644 --- a/Vulkan/src/DescriptorSet.h +++ b/Vulkan/src/DescriptorSet.h @@ -49,11 +49,11 @@ public: void AddTexture2D(const Texture2D& texture2D, uint32_t binding) { - VkDescriptorImageInfo imageInfo = texture2D.GetDescriptorImageInfo(); - for (auto&& descriptorSet : descriptorSets) { + for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) { + VkDescriptorImageInfo imageInfo = texture2D.GetDescriptorImageInfo(i); VkWriteDescriptorSet descriptorWrite{}; descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = descriptorSet; + descriptorWrite.dstSet = descriptorSets[i]; descriptorWrite.dstBinding = binding; descriptorWrite.dstArrayElement = 0; descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; diff --git a/Vulkan/src/FileSystem.h b/Vulkan/src/FileSystem.h index bb3eff8..f5fb64e 100644 --- a/Vulkan/src/FileSystem.h +++ b/Vulkan/src/FileSystem.h @@ -2,6 +2,7 @@ #include #include +#include #include "Common.h" @@ -48,6 +49,8 @@ namespace FileSystem 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); CP_ASSERT(file.is_open(), "Failed to open file"); diff --git a/Vulkan/src/Framebuffer.h b/Vulkan/src/Framebuffer.h new file mode 100644 index 0000000..b9c7a06 --- /dev/null +++ b/Vulkan/src/Framebuffer.h @@ -0,0 +1,174 @@ +#pragma once + +#include "Common.h" +#include "Image.h" +#include "Instance.h" +#include "Texture2D.h" + +#include + +// TODO: Add resizing (recreate image, depthImage, framebuffers) +class Framebuffer +{ + CP_DELETE_COPY_AND_MOVE_CTOR(Framebuffer); +private: + Instance& instance; + + std::unique_ptr image; + std::unique_ptr depthImage; + std::vector 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 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(instance, width, height, Texture2D::Type::Dynamic, Texture2D::Format::Color); + } + + void InitializeDepthBuffer() + { + depthImage = std::make_unique(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 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 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 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"); + } + } +}; \ No newline at end of file diff --git a/Vulkan/src/Image.h b/Vulkan/src/Image.h index 024071b..a4a9963 100644 --- a/Vulkan/src/Image.h +++ b/Vulkan/src/Image.h @@ -28,7 +28,7 @@ public: createInfo.samples = VK_SAMPLE_COUNT_1_BIT; 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; vkGetImageMemoryRequirements(instance.GetDevice(), *image, &memoryRequirements); @@ -38,7 +38,7 @@ public: allocateInfo.allocationSize = memoryRequirements.size; 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); } @@ -60,7 +60,7 @@ public: createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.baseArrayLayer = 0; 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; } @@ -115,12 +115,19 @@ public: srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_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 { - 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) @@ -140,7 +147,13 @@ public: region.imageOffset = {0, 0, 0}; region.imageExtent = {width, height, 1}; - vkCmdCopyBufferToImage(commandBuffer.GetHandle(), buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + vkCmdCopyBufferToImage(commandBuffer, buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + } + + + 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: @@ -148,4 +161,22 @@ private: { return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT; } + + static VkFormat SelectSupportedFormat(Instance& instance, const std::vector& 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"); + } }; \ No newline at end of file diff --git a/Vulkan/src/IndexBuffer.h b/Vulkan/src/IndexBuffer.h index 590e883..b626cb4 100644 --- a/Vulkan/src/IndexBuffer.h +++ b/Vulkan/src/IndexBuffer.h @@ -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} {} - void Bind(VkCommandBuffer commandBuffer) override + void Bind(const CommandBuffer& commandBuffer) override { vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16); } - void Draw(VkCommandBuffer commandBuffer) + void Draw(const CommandBuffer& commandBuffer) { vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0); } diff --git a/Vulkan/src/Pipeline.h b/Vulkan/src/Pipeline.h index ac66894..8d0a25c 100644 --- a/Vulkan/src/Pipeline.h +++ b/Vulkan/src/Pipeline.h @@ -1,6 +1,7 @@ #pragma once #include "Common.h" +#include "CommandBuffer.h" #include "Instance.h" #include "FileSystem.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); @@ -231,7 +232,7 @@ private: graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo; graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; graphicsPipelineCreateInfo.layout = pipelineLayout; - graphicsPipelineCreateInfo.renderPass = instance.GetSwapChain().GetRenderPass(); + graphicsPipelineCreateInfo.renderPass = creator.renderPass; graphicsPipelineCreateInfo.subpass = 0; graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; graphicsPipelineCreateInfo.basePipelineIndex = -1; diff --git a/Vulkan/src/PipelineCreator.h b/Vulkan/src/PipelineCreator.h index a57d343..e5b584c 100644 --- a/Vulkan/src/PipelineCreator.h +++ b/Vulkan/src/PipelineCreator.h @@ -25,10 +25,11 @@ private: VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT; VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE; + VkRenderPass renderPass = VK_NULL_HANDLE; public: - PipelineCreator(const std::string& vertexShader, const std::string& fragmentShader) - : vertexShader{vertexShader}, fragmentShader{fragmentShader} + PipelineCreator(VkRenderPass renderPass, const std::string& vertexShader, const std::string& fragmentShader) + : vertexShader{vertexShader}, fragmentShader{fragmentShader}, renderPass{renderPass} {} 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) { - 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}); } diff --git a/Vulkan/src/Shader.h b/Vulkan/src/Shader.h index c5a4726..836618d 100644 --- a/Vulkan/src/Shader.h +++ b/Vulkan/src/Shader.h @@ -89,7 +89,7 @@ private: VkShaderModule InitializeShaderModuleFromGlslFile(const std::string& filename, shaderc_shader_kind shaderType) { - std::string spvFilename = filename + ".spv"; + std::string spvFilename = ".cache/" + filename + ".spv"; try { if (FileSystem::FileExists(spvFilename)) diff --git a/Vulkan/src/SwapChain.cpp b/Vulkan/src/SwapChain.cpp index c54699f..0392d22 100644 --- a/Vulkan/src/SwapChain.cpp +++ b/Vulkan/src/SwapChain.cpp @@ -1,8 +1,10 @@ #include "SwapChain.h" +#include "CommandBuffer.h" #include "Image.h" #include "Instance.h" #include "QueueFamilies.h" +#include "Texture2D.h" #include #include @@ -50,6 +52,28 @@ SwapChain::~SwapChain() vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr); } +void SwapChain::BeginFrameBuffer(const CommandBuffer& commandBuffer) const +{ + std::vector 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 { return handle; @@ -182,11 +206,7 @@ void SwapChain::InitializeImageViews() void SwapChain::InitializeDepthBuffer() { - VkFormat depthFormat = SelectDepthFormat(); - 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); + depthImage = std::make_unique(instance, extent.width, extent.height, Texture2D::Type::Static, Texture2D::Format::Depth); } void SwapChain::InitializeRenderPass() @@ -202,7 +222,7 @@ void SwapChain::InitializeRenderPass() colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentDescription depthAttachment{}; - depthAttachment.format = SelectDepthFormat(); + 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; @@ -252,7 +272,7 @@ void SwapChain::InitializeFramebuffers() for (size_t i = 0; i < imageViews.size(); ++i) { - std::vector attachments{imageViews[i], depthImageView}; + std::vector attachments{imageViews[i], depthImage->GetImageView()}; VkFramebufferCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; @@ -269,9 +289,6 @@ void SwapChain::InitializeFramebuffers() void SwapChain::Destroy() { - vkDestroyImage(instance.GetDevice(), depthImage, nullptr); - vkFreeMemory(instance.GetDevice(), depthImageMemory, nullptr); - vkDestroyImageView(instance.GetDevice(), depthImageView, nullptr); for (auto&& framebuffer : framebuffers) { vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr); @@ -295,29 +312,6 @@ VkSurfaceFormatKHR SwapChain::SelectSwapSurfaceFormat(const std::vector& 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& availablePresentModes) { return VK_PRESENT_MODE_FIFO_KHR; diff --git a/Vulkan/src/SwapChain.h b/Vulkan/src/SwapChain.h index a150ef5..7b4364c 100644 --- a/Vulkan/src/SwapChain.h +++ b/Vulkan/src/SwapChain.h @@ -7,6 +7,8 @@ #include class Instance; +class CommandBuffer; +class Texture2D; struct SwapChainSupportDetails { @@ -24,24 +26,22 @@ class SwapChain final private: Instance& instance; - // Created by the class VkSwapchainKHR handle; VkRenderPass renderPass; VkFormat imageFormat; VkExtent2D extent; - VkImage depthImage; - VkImageView depthImageView; - VkDeviceMemory depthImageMemory; + std::unique_ptr depthImage; std::vector imageViews; std::vector images; std::vector framebuffers; - uint32_t imageIndex; public: SwapChain(Instance& instance); ~SwapChain(); + void BeginFrameBuffer(const CommandBuffer& commandBuffer) const; + void EndFrameBuffer(const CommandBuffer& commandBuffer) const; VkSwapchainKHR GetHandle() const; VkRenderPass GetRenderPass() const; VkExtent2D GetExtent() const; @@ -60,8 +60,6 @@ private: void Destroy(); VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector& availableFormats); - VkFormat SelectDepthFormat(); - VkFormat SelectSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features); VkPresentModeKHR SelectSwapPresentMode(const std::vector& availablePresentModes); VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities); }; diff --git a/Vulkan/src/Texture2D.cpp b/Vulkan/src/Texture2D.cpp new file mode 100644 index 0000000..5b89074 --- /dev/null +++ b/Vulkan/src/Texture2D.cpp @@ -0,0 +1,150 @@ +#include "Texture2D.h" + +#define STB_IMAGE_IMPLEMENTATION +#include + +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"); +} diff --git a/Vulkan/src/Texture2D.h b/Vulkan/src/Texture2D.h index caa8b66..b512619 100644 --- a/Vulkan/src/Texture2D.h +++ b/Vulkan/src/Texture2D.h @@ -6,110 +6,40 @@ #include "Image.h" #include "Instance.h" -#define STB_IMAGE_IMPLEMENTATION -#include - +// TODO: Separate Texture2D and Framebuffer Attachments class Texture2D { CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D); +public: + enum class Type + { + Static, Dynamic + }; + + enum class Format + { + Image, Color, Depth + }; private: Instance& instance; - VkImage image; - VkDeviceMemory imageMemory; - VkImageView imageView; + std::vector images; + std::vector imageMemories; + std::vector imageViews; VkSampler sampler; + Type type; + Format format; public: - Texture2D(Instance& instance, const std::string& filename) - : instance{instance} - { - InitializeTextureImage(filename); - InitializeSampler(); - } + Texture2D(Instance& instance, const std::string& filename); + Texture2D(Instance& instance, int width, int height, Type type, Format format); + ~Texture2D(); - ~Texture2D() - { - vkDestroyImage(instance.GetDevice(), image, nullptr); - 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; - } + VkDescriptorImageInfo GetDescriptorImageInfo(int index) const; + VkImageView GetImageView() const; + VkImageView GetImageView(int index); private: - void 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, "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; - } - + void InitializeTextureImage(const std::string& filename); + void InitializeTexture(int width, int height); + void InitializeSampler(); }; diff --git a/Vulkan/src/VertexBuffer.h b/Vulkan/src/VertexBuffer.h index 00530c8..902170e 100644 --- a/Vulkan/src/VertexBuffer.h +++ b/Vulkan/src/VertexBuffer.h @@ -22,7 +22,7 @@ public: } } - void Bind(VkCommandBuffer commandBuffer) override + void Bind(const CommandBuffer& commandBuffer) override { std::vector buffers{bindingOffsets.size(), handle}; vkCmdBindVertexBuffers(commandBuffer, 0, bindingOffsets.size(), buffers.data(), bindingOffsets.data()); diff --git a/Vulkan/src/VertexPassthrough.h b/Vulkan/src/VertexPassthrough.h new file mode 100644 index 0000000..e47c549 --- /dev/null +++ b/Vulkan/src/VertexPassthrough.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include "VertexDescriptor.h" + +struct VertexPassthrough { + glm::vec2 texCoord; + + static VertexDescriptor GetDescriptor() + { + VertexDescriptor descriptor{}; + descriptor.AddAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(VertexPassthrough , texCoord)); + return descriptor; + } +}; diff --git a/Vulkan/src/main.cpp b/Vulkan/src/main.cpp index 0f03519..1685def 100644 --- a/Vulkan/src/main.cpp +++ b/Vulkan/src/main.cpp @@ -1,6 +1,7 @@ #include "Buffer.h" #include "DescriptorPool.h" #include "DescriptorSet.h" +#include "Framebuffer.h" #include "IndexBuffer.h" #include "Instance.h" #include "Pipeline.h" @@ -9,6 +10,7 @@ #include "UniformBuffer.h" #include "Vertex.h" #include "VertexBuffer.h" +#include "VertexPassthrough.h" #include #include @@ -20,13 +22,13 @@ #include const std::vector vertices = { - Vertex{{-0.5f, 0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, - Vertex{{ 0.5f, 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, - Vertex{{ 0.5f, 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, + Vertex{{-0.5f, 0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, + Vertex{{ 0.5f, 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, + Vertex{{ 0.5f, 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, Vertex{{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}, - Vertex{{-0.5f, 0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, - Vertex{{ 0.5f, 0.0f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, - Vertex{{ 0.5f, 0.0f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, + Vertex{{-0.5f, 0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, + Vertex{{ 0.5f, 0.0f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, + Vertex{{ 0.5f, 0.0f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, Vertex{{-0.5f, 0.0f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}, }; @@ -35,6 +37,17 @@ const std::vector indices = { 4, 5, 6, 6, 7, 4 }; +const std::vector verticesPassthrough = { + VertexPassthrough{{-1.0f, -1.0f}}, + VertexPassthrough{{ 1.0f, -1.0f}}, + VertexPassthrough{{ 1.0f, 1.0f}}, + VertexPassthrough{{-1.0f, 1.0f}}, +}; + +const std::vector indicesPassthrough = { + 0, 1, 2, 2, 3, 0, +}; + struct alignas(64) ShaderUniform { alignas(16) glm::mat4 projection; @@ -56,10 +69,17 @@ private: std::unique_ptr indexBuffer; std::unique_ptr commandBuffer; + std::unique_ptr framebuffer; + std::unique_ptr graphicsPipelinePassthrough; + std::unique_ptr vertexBufferPassthrough; + std::unique_ptr indexBufferPassthrough; + std::unique_ptr descriptorSetPassthrough; + public: Application() { InitializeInstance(); + InitializeFrameBuffer(); InitializeGraphicsPipeline(); InitializeTextureSampler(); InitializeUniformBuffer(); @@ -94,7 +114,12 @@ private: void InitializeInstance() { - instance = std::make_unique("Vulkan Tutorial"); + instance = std::make_unique("Copium Engine"); + } + + void InitializeFrameBuffer() + { + framebuffer = std::make_unique(*instance, instance->GetSwapChain().GetExtent().width, instance->GetSwapChain().GetExtent().height); } void InitializeTextureSampler() @@ -114,30 +139,44 @@ private: descriptorSet = std::make_unique(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0)); descriptorSet->AddUniform(*shaderUniformBuffer, 0); descriptorSet->AddTexture2D(*texture2D, 1); + + descriptorSetPassthrough = std::make_unique(*instance, *descriptorPool, graphicsPipelinePassthrough->GetDescriptorSetLayout(0)); + descriptorSetPassthrough->AddTexture2D(framebuffer->GetTexture2D(), 0); } 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, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); creator.SetVertexDescriptor(Vertex::GetDescriptor()); creator.SetCullMode(VK_CULL_MODE_NONE); graphicsPipeline = std::make_unique(*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(*instance, creatorPassthrough); } void InitializeVertexBuffer() { vertexBuffer = std::make_unique(*instance, Vertex::GetDescriptor(), vertices.size()); vertexBuffer->Update(0, (void*)vertices.data()); - } + + vertexBufferPassthrough = std::make_unique(*instance, VertexPassthrough::GetDescriptor(), verticesPassthrough.size()); + vertexBufferPassthrough->Update(0, (void*)verticesPassthrough.data()); + } void InitializeIndexBuffer() { - VkDeviceSize bufferSize = sizeof(uint16_t) * indices.size(); indexBuffer = std::make_unique(*instance, indices.size()); indexBuffer->UpdateStaging((void*)indices.data()); - } + + indexBufferPassthrough = std::make_unique(*instance, indicesPassthrough.size()); + indexBufferPassthrough->UpdateStaging((void*)indicesPassthrough.data()); + } void InitializeCommandBuffer() { @@ -151,30 +190,32 @@ private: clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; 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(); - vertexBuffer->Bind(commandBuffer->GetHandle()); - indexBuffer->Bind(commandBuffer->GetHandle()); + vertexBuffer->Bind(*commandBuffer); + indexBuffer->Bind(*commandBuffer); graphicsPipeline->SetDescriptorSet(0, *descriptorSet); 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(); } @@ -192,24 +233,15 @@ private: shaderUniformBuffer->Update(shaderUniform); } - - VkShaderModule InitializeShaderModule(const std::vector& code) - { - VkShaderModuleCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = code.size(); - createInfo.pCode = reinterpret_cast(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(ptr) = 20; +} + 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; Timer timer;