diff --git a/shaders/shader.vert b/shaders/shader.vert index 97811c9..4c94107 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -6,7 +6,7 @@ layout(set = 0, binding = 0) uniform UniformBufferObject{ mat4 proj; }ubo; -layout(location = 0) in vec2 inPosition; +layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inColor; layout(location = 2) in vec2 inTexCoord; @@ -14,10 +14,7 @@ layout(location = 0) out vec3 fragColor; layout(location = 1) out vec2 fragTexCoord; void main(){ - // gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - // fragColor = colors[gl_VertexIndex]; - // gl_Position = vec4(inPosition, 0.0, 1.0); - gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0); fragColor = inColor; fragTexCoord = inTexCoord; } diff --git a/vulkan/vulkan_app.cpp b/vulkan/vulkan_app.cpp index c289ddb..0338212 100644 --- a/vulkan/vulkan_app.cpp +++ b/vulkan/vulkan_app.cpp @@ -408,7 +408,7 @@ namespace vapp{ swapChainImageViews.resize(swapChainImages.size()); for(uint32_t i = 0; i < swapChainImages.size(); i++){ - swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat); + swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT); } } @@ -439,14 +439,13 @@ namespace vapp{ } void Vulkan::createGraphicsPipeline(){ - // TODO: find solution for file location std::vector vertShaderCode; std::vector fragShaderCode; try{ vertShaderCode = readFile("shaders/shader.vert.spv"); fragShaderCode = readFile("shaders/shader.frag.spv"); } - catch(std::exception e){ + catch(const std::exception &e){ std::cout << "Failed to read ./shaders/...\nTrying fallback folders!\n"; vertShaderCode = readFile("../shaders/shader.vert.spv"); fragShaderCode = readFile("../shaders/shader.frag.spv"); @@ -553,6 +552,18 @@ namespace vapp{ colorBlending.attachmentCount = 1; colorBlending.pAttachments = &colorBlendAttachment; + VkPipelineDepthStencilStateCreateInfo depthStencil{}; + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + depthStencil.depthBoundsTestEnable = VK_FALSE; + depthStencil.minDepthBounds = 0.0f; + depthStencil.maxDepthBounds = 1.0f; + depthStencil.stencilTestEnable = VK_FALSE; + depthStencil.front = {}; + depthStencil.back = {}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; @@ -575,6 +586,7 @@ namespace vapp{ pipelineInfo.pDepthStencilState = nullptr; // Optional because {} as initializer pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDynamicState = &dynamicState; + pipelineInfo.pDepthStencilState = &depthStencil; pipelineInfo.layout = pipelineLayout; pipelineInfo.renderPass = renderPass; pipelineInfo.subpass = 0; @@ -608,6 +620,20 @@ namespace vapp{ } void Vulkan::createRenderPass(){ + VkAttachmentDescription depthAttachment{}; + depthAttachment.format = findDepthFormat(); + depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkAttachmentReference depthAttachmentRef{}; + depthAttachmentRef.attachment = 1; + depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + VkAttachmentDescription colorAttachment{}; colorAttachment.format = swapChainImageFormat; colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; @@ -626,19 +652,22 @@ namespace vapp{ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; + subpass.pDepthStencilAttachment = &depthAttachmentRef; VkSubpassDependency dependency{}; dependency.srcSubpass = VK_SUBPASS_EXTERNAL; dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; dependency.srcAccessMask = 0; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;; + + std::array attachments = { colorAttachment, depthAttachment }; VkRenderPassCreateInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassInfo.attachmentCount = 1; - renderPassInfo.pAttachments = &colorAttachment; + renderPassInfo.attachmentCount = static_cast(attachments.size()); + renderPassInfo.pAttachments = attachments.data(); renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; renderPassInfo.dependencyCount = 1; @@ -649,23 +678,23 @@ namespace vapp{ } } - void Vulkan::createFrameBuffers(){ + void Vulkan::createFramebuffers(){ swapChainFramebuffers.resize(swapChainImageViews.size()); for(size_t i = 0; i < swapChainImageViews.size(); i++){ - VkImageView attachements[] = {swapChainImageViews[i]}; + std::array attachments = { swapChainImageViews[i], depthImageView }; VkFramebufferCreateInfo framebufferInfo{}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = renderPass; - framebufferInfo.attachmentCount = 1; - framebufferInfo.pAttachments = attachements; + framebufferInfo.attachmentCount = static_cast(attachments.size()); + framebufferInfo.pAttachments = attachments.data(); framebufferInfo.width = swapChainExtent.width; framebufferInfo.height = swapChainExtent.height; framebufferInfo.layers = 1; if(vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS){ - throw std::runtime_error("Func: createFrameBuffers\nError: Failed to create Framebuffer!\n"); + throw std::runtime_error("Func: createFramebuffers\nError: Failed to create Framebuffer!\n"); } } } @@ -682,6 +711,44 @@ namespace vapp{ } } + VkFormat Vulkan::findSupportedFormat(const std::vector &candidates, VkImageTiling tiling, VkFormatFeatureFlags features){ + for(VkFormat format : candidates){ + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props); + + if(tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features){ + return format; + } + if(tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features){ + return format; + } + + throw std::runtime_error("Func: findSupportedFormat\nError: Failed to find supported Format!\n"); + } + } + + VkFormat Vulkan::findDepthFormat(){ + return findSupportedFormat( + { 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 + ); + } + + bool hasStencilComponent(VkFormat format){ + return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT; + } + + void Vulkan::createDepthResources(){ + VkFormat depthFormat = findDepthFormat(); + createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory); + depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT); + + transitionImageLayout(depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + + + } + VkCommandBuffer Vulkan::beginSingleTimeCommands(){ VkCommandBufferAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -737,7 +804,18 @@ namespace vapp{ barrier.image = image; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + if(newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL){ + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + + if(hasStencilComponent(format)){ + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + + } + else{ + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + barrier.subresourceRange.baseMipLevel = 0; barrier.subresourceRange.levelCount = 1; barrier.subresourceRange.baseArrayLayer = 0; @@ -760,6 +838,13 @@ namespace vapp{ sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; } + else if(oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL){ + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + + sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + } else{ throw std::invalid_argument("Func: transitionImageLayout\nError: Unsupported Layout Transition!\n"); } @@ -788,7 +873,7 @@ namespace vapp{ endSingleTimeCommands(commandBuffer); } - void Vulkan::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory &imageMemory){ + void Vulkan::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &imageMemory){ VkImageCreateInfo imageInfo{}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; // 3D is used to store voxel volumes @@ -851,13 +936,13 @@ namespace vapp{ vkFreeMemory(device, stagingBufferMemory, nullptr); } - VkImageView Vulkan::createImageView(VkImage image, VkFormat format){ + VkImageView Vulkan::createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags){ VkImageViewCreateInfo viewInfo{}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = image; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = VK_FORMAT_R8G8B8A8_SRGB; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.format = format; + viewInfo.subresourceRange.aspectMask = aspectFlags; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.baseArrayLayer = 0; @@ -872,7 +957,7 @@ namespace vapp{ } void Vulkan::createTextureImageView(){ - textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB); + textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT); } void Vulkan::createTextureSampler(){ @@ -1128,9 +1213,12 @@ namespace vapp{ renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.extent = swapChainExtent; - VkClearValue clearColor = {{{0.01f, 0.01f, 0.01f, 1.0f}}}; // Background color after clear (Black 100%) - renderPassInfo.clearValueCount = 1; - renderPassInfo.pClearValues = &clearColor; + std::array clearValues{}; + clearValues[0].color = {{0.01f, 0.01f, 0.01f, 1.0f}}; // Background color after clear (Black 100%) + clearValues[1].depthStencil = { 1.0f, 0 }; + + renderPassInfo.clearValueCount = static_cast(clearValues.size()); + renderPassInfo.pClearValues = clearValues.data(); vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); @@ -1268,6 +1356,10 @@ namespace vapp{ } void Vulkan::cleanupSwapChain(){ + vkDestroyImageView(device, depthImageView, nullptr); + vkDestroyImage(device, depthImage, nullptr); + vkFreeMemory(device, depthImageMemory, nullptr); + for(const auto & swapChainFramebuffer : swapChainFramebuffers) { vkDestroyFramebuffer(device, swapChainFramebuffer, nullptr); } for(const auto & swapChainImageView : swapChainImageViews) @@ -1278,7 +1370,6 @@ namespace vapp{ void Vulkan::recreateSwapChain(){ int width = 0, height = 0; - glfwGetFramebufferSize(window, &width, &height); while(width == 0 || height == 0){ glfwGetFramebufferSize(window, &width, &height); glfwPollEvents(); @@ -1290,7 +1381,8 @@ namespace vapp{ createSwapChain(); createImageViews(); - createFrameBuffers(); + createDepthResources(); + createFramebuffers(); } static void framebufferResizeCallback(GLFWwindow *window, int width, int height){ @@ -1318,8 +1410,9 @@ namespace vapp{ createRenderPass(); createDescriptorSetLayout(); createGraphicsPipeline(); - createFrameBuffers(); createCommandPool(); + createDepthResources(); + createFramebuffers(); createTextureImage(); createTextureImageView(); createTextureSampler(); diff --git a/vulkan/vulkan_app.hpp b/vulkan/vulkan_app.hpp index 129d1b5..2ba4272 100644 --- a/vulkan/vulkan_app.hpp +++ b/vulkan/vulkan_app.hpp @@ -10,6 +10,7 @@ #define GLM_FORCE_RADIANS #define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +#define GLM_FORCE_DEPTH_ZERO_TO_ONE #include #include @@ -32,7 +33,7 @@ namespace vapp{ const VkPresentModeKHR WISHED_PRESENT_MODE = VK_PRESENT_MODE_MAILBOX_KHR; struct Vertex{ - glm::vec2 pos; + glm::vec3 pos; glm::vec3 color; glm::vec2 texCoord; @@ -51,7 +52,7 @@ namespace vapp{ attributeDescriptions[0].binding = 0; attributeDescriptions[0].location = 0; - attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; + attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; attributeDescriptions[0].offset = offsetof(Vertex, pos); attributeDescriptions[1].binding = 0; @@ -68,16 +69,23 @@ namespace vapp{ } }; - // TODO: Remove const std::vector vertices = { - {{-0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, - {{0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {0.0f, 0.0f}}, -{{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f}}, -{{-0.5f, 0.5f}, {1.0f, 0.0f, 0.0f}, {1.0f, 1.0f}} + {{-0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}}, + {{0.5f, -0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}}, + {{0.5f, 0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}}, + {{-0.5f, 0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}}, + + {{-0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}}, + {{0.5f, -0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}}, + {{0.5f, 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}}, + {{-0.5f, 0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}} }; // uint16_t also possible -> change in vkCmdBindIndexBuffer also - const std::vector indices = { 0, 1, 2, 2, 3, 0 }; + const std::vector indices = { + 0, 1, 2, 2, 3, 0, + 4, 5, 6, 6, 7, 4 + }; // END Remove struct UniformBufferObject{ @@ -163,6 +171,10 @@ namespace vapp{ VkImageView textureImageView; VkSampler textureSampler; + + VkImage depthImage; + VkDeviceMemory depthImageMemory; + VkImageView depthImageView; #pragma endregion bool checkValidationLayerSupport(); @@ -186,15 +198,18 @@ namespace vapp{ void createGraphicsPipeline(); VkShaderModule createShaderModule(const std::vector& code); void createRenderPass(); - void createFrameBuffers(); + void createFramebuffers(); void createCommandPool(); + VkFormat findSupportedFormat(const std::vector &candidates, VkImageTiling tiling, VkFormatFeatureFlags features); + VkFormat findDepthFormat(); + void createDepthResources(); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer commandBuffer); void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout); void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height); void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory &imageMemory); void createTextureImage(); - VkImageView createImageView(VkImage image, VkFormat format); + VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags); void createTextureImageView(); void createTextureSampler(); uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);