diff --git a/src/main.cpp b/src/main.cpp index b19c06f..c15f4f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,13 @@ #include #include #include -#include -#include #include #include +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include +#include + #define STB_IMAGE_IMPLEMENTATION #include @@ -42,7 +44,7 @@ constexpr bool enableValidationLayers = true; #endif struct Vertex { - glm::vec2 pos; + glm::vec3 pos; glm::vec3 color; glm::vec2 tex_coord; @@ -52,21 +54,30 @@ struct Vertex { static fn getAttributeDescriptions() -> std::array { return { - { { 0, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, pos) }, + { { 0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, pos) }, { 1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, color) }, { 2, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, tex_coord) } } }; } }; -constexpr std::array vertices = { - { { { -0.5F, -0.5F }, { 1.0F, 0.0F, 0.0F }, { 1.0F, 0.0F } }, - { { 0.5F, -0.5F }, { 0.0F, 1.0F, 0.0F }, { 0.0F, 0.0F } }, - { { 0.5F, 0.5F }, { 0.0F, 0.0F, 1.0F }, { 0.0F, 1.0F } }, - { { -0.5F, 0.5F }, { 1.0F, 1.0F, 1.0F }, { 1.0F, 1.0F } } } +constexpr std::array vertices = { + { { { -0.5F, -0.5F, 0.0F }, { 1.0F, 0.0F, 0.0F }, { 0.0F, 0.0F } }, + { { 0.5F, -0.5F, 0.0F }, { 0.0F, 1.0F, 0.0F }, { 1.0F, 0.0F } }, + { { 0.5F, 0.5F, 0.0F }, { 0.0F, 0.0F, 1.0F }, { 1.0F, 1.0F } }, + { { -0.5F, 0.5F, 0.0F }, { 1.0F, 1.0F, 1.0F }, { 0.0F, 1.0F } }, + { { -0.5F, -0.5F, -0.5F }, { 1.0F, 0.0F, 0.0F }, { 0.0F, 0.0F } }, + { { 0.5F, -0.5F, -0.5F }, { 0.0F, 1.0F, 0.0F }, { 1.0F, 0.0F } }, + { { 0.5F, 0.5F, -0.5F }, { 0.0F, 0.0F, 1.0F }, { 1.0F, 1.0F } }, + { { -0.5F, 0.5F, -0.5F }, { 1.0F, 1.0F, 1.0F }, { 0.0F, 1.0F } } } }; -constexpr std::array indices = { 0, 1, 2, 2, 3, 0 }; +// clang-format off +constexpr std::array indices = { + 0, 1, 2, 2, 3, 0, + 4, 5, 6, 6, 7, 4 +}; +// clang-format on class VulkanApp { public: @@ -105,6 +116,10 @@ class VulkanApp { vk::UniqueCommandPool mCommandPool; + vk::UniqueImage mDepthImage; + vk::UniqueDeviceMemory mDepthImageMemory; + vk::UniqueImageView mDepthImageView; + vk::UniqueImage mTextureImage; vk::UniqueDeviceMemory mTextureImageMemory; vk::UniqueImageView mTextureImageView; @@ -196,8 +211,9 @@ class VulkanApp { createRenderPass(); createDescriptorSetLayout(); createGraphicsPipeline(); - createFramebuffers(); createCommandPool(); + createDepthResources(); + createFramebuffers(); createTextureImage(); createTextureImageView(); createTextureSampler(); @@ -220,10 +236,8 @@ class VulkanApp { } fn cleanupSwapChain() -> void { - for (vk::UniqueFramebuffer& mSwapChainFramebuffer : mSwapChainFramebuffers) { - mSwapChainFramebuffer.reset(); - } - for (vk::UniqueImageView& mSwapChainImageView : mSwapChainImageViews) { mSwapChainImageView.reset(); } + for (vk::UniqueFramebuffer& mSwapChainFramebuffer : mSwapChainFramebuffers) mSwapChainFramebuffer.reset(); + for (vk::UniqueImageView& mSwapChainImageView : mSwapChainImageViews) mSwapChainImageView.reset(); mSwapChain.reset(); } @@ -243,6 +257,7 @@ class VulkanApp { createSwapChain(); createImageViews(); + createDepthResources(); createFramebuffers(); } @@ -415,26 +430,9 @@ class VulkanApp { fn createImageViews() -> void { mSwapChainImageViews.resize(mSwapChainImages.size()); - for (u32 i = 0; i < mSwapChainImages.size(); i++) { - vk::ImageViewCreateInfo createInfo { - .image = mSwapChainImages[i], - .viewType = vk::ImageViewType::e2D, - .format = mSwapChainImageFormat, - // clang-format off - .components = { .r = vk::ComponentSwizzle::eIdentity, - .g = vk::ComponentSwizzle::eIdentity, - .b = vk::ComponentSwizzle::eIdentity, - .a = vk::ComponentSwizzle::eIdentity }, - .subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1 }, - // clang-format on - }; - - mSwapChainImageViews[i] = mDevice->createImageViewUnique(createInfo); - } + for (u32 i = 0; i < mSwapChainImages.size(); i++) + mSwapChainImageViews[i] = + createImageView(mSwapChainImages[i], mSwapChainImageFormat, vk::ImageAspectFlagBits::eColor); } fn createRenderPass() -> void { @@ -449,23 +447,47 @@ class VulkanApp { .finalLayout = vk::ImageLayout::ePresentSrcKHR, }; + vk::AttachmentDescription depthAttachment { .format = findDepthFormat(), + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eDontCare, + .stencilLoadOp = vk::AttachmentLoadOp::eDontCare, + .stencilStoreOp = vk::AttachmentStoreOp::eDontCare, + .initialLayout = vk::ImageLayout::eUndefined, + .finalLayout = + vk::ImageLayout::eDepthStencilAttachmentOptimal }; + vk::AttachmentReference colorAttachmentRef { .attachment = 0, .layout = vk::ImageLayout::eColorAttachmentOptimal, }; - vk::SubpassDescription subpass { - .pipelineBindPoint = vk::PipelineBindPoint::eGraphics, - .colorAttachmentCount = 1, - .pColorAttachments = &colorAttachmentRef, - }; + vk::AttachmentReference depthAttachmentRef { .attachment = 1, + .layout = vk::ImageLayout::eDepthStencilAttachmentOptimal }; - vk::RenderPassCreateInfo renderPassInfo { - .attachmentCount = 1, - .pAttachments = &colorAttachment, - .subpassCount = 1, - .pSubpasses = &subpass, - }; + vk::SubpassDescription subpass { .pipelineBindPoint = vk::PipelineBindPoint::eGraphics, + .colorAttachmentCount = 1, + .pColorAttachments = &colorAttachmentRef, + .pDepthStencilAttachment = &depthAttachmentRef }; + + vk::SubpassDependency dependency { .srcSubpass = vk::SubpassExternal, + .dstSubpass = {}, + .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | + vk::PipelineStageFlagBits::eEarlyFragmentTests, + .dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | + vk::PipelineStageFlagBits::eEarlyFragmentTests, + .srcAccessMask = {}, + .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | + vk::AccessFlagBits::eDepthStencilAttachmentWrite }; + + std::array attachments = { colorAttachment, depthAttachment }; + + vk::RenderPassCreateInfo renderPassInfo { .attachmentCount = static_cast(attachments.size()), + .pAttachments = attachments.data(), + .subpassCount = 1, + .pSubpasses = &subpass, + .dependencyCount = 1, + .pDependencies = &dependency }; mRenderPass = mDevice->createRenderPassUnique(renderPassInfo); } @@ -504,17 +526,13 @@ class VulkanApp { vk::UniqueShaderModule vertShaderModule = createShaderModule(vertShaderCode); vk::UniqueShaderModule fragShaderModule = createShaderModule(fragShaderCode); - vk::PipelineShaderStageCreateInfo vertShaderStageInfo { - .stage = vk::ShaderStageFlagBits::eVertex, - .module = vertShaderModule.get(), - .pName = "main", - }; + vk::PipelineShaderStageCreateInfo vertShaderStageInfo { .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertShaderModule.get(), + .pName = "main" }; - vk::PipelineShaderStageCreateInfo fragShaderStageInfo { - .stage = vk::ShaderStageFlagBits::eFragment, - .module = fragShaderModule.get(), - .pName = "main", - }; + vk::PipelineShaderStageCreateInfo fragShaderStageInfo { .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragShaderModule.get(), + .pName = "main" }; std::array shaderStages = { vertShaderStageInfo, fragShaderStageInfo }; @@ -527,38 +545,36 @@ class VulkanApp { .vertexBindingDescriptionCount = 1, .pVertexBindingDescriptions = &bindingDescription, .vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()), - .pVertexAttributeDescriptions = attributeDescriptions.data(), + .pVertexAttributeDescriptions = attributeDescriptions.data() }; - vk::PipelineInputAssemblyStateCreateInfo inputAssembly { - .topology = vk::PrimitiveTopology::eTriangleList, - .primitiveRestartEnable = vk::False, - }; + vk::PipelineInputAssemblyStateCreateInfo inputAssembly { .topology = vk::PrimitiveTopology::eTriangleList, + .primitiveRestartEnable = vk::False }; - vk::PipelineViewportStateCreateInfo viewportState { - .viewportCount = 1, - .scissorCount = 1, - }; + vk::PipelineViewportStateCreateInfo viewportState { .viewportCount = 1, .scissorCount = 1 }; - vk::PipelineRasterizationStateCreateInfo rasterizer { - .depthClampEnable = vk::False, - .rasterizerDiscardEnable = vk::False, - .polygonMode = vk::PolygonMode::eFill, - .cullMode = vk::CullModeFlagBits::eBack, - .frontFace = vk::FrontFace::eCounterClockwise, - .depthBiasEnable = vk::False, - .lineWidth = 1.0F, - }; + vk::PipelineRasterizationStateCreateInfo rasterizer { .depthClampEnable = vk::False, + .rasterizerDiscardEnable = vk::False, + .polygonMode = vk::PolygonMode::eFill, + .cullMode = vk::CullModeFlagBits::eBack, + .frontFace = vk::FrontFace::eCounterClockwise, + .depthBiasEnable = vk::False, + .lineWidth = 1.0F }; - vk::PipelineMultisampleStateCreateInfo multisampling { - .rasterizationSamples = vk::SampleCountFlagBits::e1, - .sampleShadingEnable = vk::False, - }; + vk::PipelineMultisampleStateCreateInfo multisampling { .rasterizationSamples = + vk::SampleCountFlagBits::e1, + .sampleShadingEnable = vk::False }; + + vk::PipelineDepthStencilStateCreateInfo depthStencil { .depthTestEnable = vk::True, + .depthWriteEnable = vk::True, + .depthCompareOp = vk::CompareOp::eLess, + .depthBoundsTestEnable = vk::False, + .stencilTestEnable = vk::False }; vk::PipelineColorBlendAttachmentState colorBlendAttachment { .blendEnable = vk::False, .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | - vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA }; vk::PipelineColorBlendStateCreateInfo colorBlending { @@ -566,37 +582,33 @@ class VulkanApp { .logicOp = vk::LogicOp::eCopy, .attachmentCount = 1, .pAttachments = &colorBlendAttachment, - .blendConstants = std::array { 0.0F, 0.0F, 0.0F, 0.0F }, + .blendConstants = std::array { 0.0F, 0.0F, 0.0F, 0.0F } }; std::vector dynamicStates = { vk::DynamicState::eViewport, vk::DynamicState::eScissor }; - vk::PipelineDynamicStateCreateInfo dynamicState { - .dynamicStateCount = static_cast(dynamicStates.size()), - .pDynamicStates = dynamicStates.data(), - }; + vk::PipelineDynamicStateCreateInfo dynamicState { .dynamicStateCount = + static_cast(dynamicStates.size()), + .pDynamicStates = dynamicStates.data() }; - vk::PipelineLayoutCreateInfo pipelineLayoutInfo { - .setLayoutCount = 1, - .pSetLayouts = &mDescriptorSetLayout.get(), - }; + vk::PipelineLayoutCreateInfo pipelineLayoutInfo { .setLayoutCount = 1, + .pSetLayouts = &mDescriptorSetLayout.get() }; mPipelineLayout = mDevice->createPipelineLayoutUnique(pipelineLayoutInfo); - vk::GraphicsPipelineCreateInfo pipelineInfo { - .stageCount = static_cast(shaderStages.size()), - .pStages = shaderStages.data(), - .pVertexInputState = &vertexInputInfo, - .pInputAssemblyState = &inputAssembly, - .pViewportState = &viewportState, - .pRasterizationState = &rasterizer, - .pMultisampleState = &multisampling, - .pColorBlendState = &colorBlending, - .pDynamicState = &dynamicState, - .layout = mPipelineLayout.get(), - .renderPass = mRenderPass.get(), - .subpass = 0, - }; + vk::GraphicsPipelineCreateInfo pipelineInfo { .stageCount = static_cast(shaderStages.size()), + .pStages = shaderStages.data(), + .pVertexInputState = &vertexInputInfo, + .pInputAssemblyState = &inputAssembly, + .pViewportState = &viewportState, + .pRasterizationState = &rasterizer, + .pMultisampleState = &multisampling, + .pDepthStencilState = &depthStencil, + .pColorBlendState = &colorBlending, + .pDynamicState = &dynamicState, + .layout = mPipelineLayout.get(), + .renderPass = mRenderPass.get(), + .subpass = 0 }; vk::Result graphicsPipelineResult = vk::Result::eSuccess; vk::UniquePipeline graphicsPipelineValue; @@ -614,14 +626,14 @@ class VulkanApp { mSwapChainFramebuffers.resize(mSwapChainImageViews.size()); for (usize i = 0; i < mSwapChainImageViews.size(); i++) { - vk::FramebufferCreateInfo framebufferInfo { - .renderPass = mRenderPass.get(), - .attachmentCount = 1, - .pAttachments = &mSwapChainImageViews[i].get(), - .width = mSwapChainExtent.width, - .height = mSwapChainExtent.height, - .layers = 1, - }; + std::array attachments = { mSwapChainImageViews[i].get(), mDepthImageView.get() }; + + vk::FramebufferCreateInfo framebufferInfo { .renderPass = mRenderPass.get(), + .attachmentCount = static_cast(attachments.size()), + .pAttachments = attachments.data(), + .width = mSwapChainExtent.width, + .height = mSwapChainExtent.height, + .layers = 1 }; mSwapChainFramebuffers[i] = mDevice->createFramebufferUnique(framebufferInfo); } @@ -638,6 +650,51 @@ class VulkanApp { mCommandPool = mDevice->createCommandPoolUnique(poolInfo); } + fn createDepthResources() -> void { + vk::Format depthFormat = findDepthFormat(); + + createImage( + mSwapChainExtent.width, + mSwapChainExtent.height, + depthFormat, + vk::ImageTiling::eOptimal, + vk::ImageUsageFlagBits::eDepthStencilAttachment, + vk::MemoryPropertyFlagBits::eDeviceLocal, + mDepthImage, + mDepthImageMemory + ); + + mDepthImageView = createImageView(mDepthImage.get(), depthFormat, vk::ImageAspectFlagBits::eDepth); + } + + fn findSupportedFormat( + const std::vector& candidates, + vk::ImageTiling tiling, + vk::FormatFeatureFlags features + ) -> vk::Format { + for (vk::Format format : candidates) { + vk::FormatProperties props = mPhysicalDevice.getFormatProperties(format); + if (tiling == vk::ImageTiling::eLinear && (props.linearTilingFeatures & features) == features) + return format; + if (tiling == vk::ImageTiling::eOptimal && (props.optimalTilingFeatures & features) == features) + return format; + } + + throw std::runtime_error("Failed to find supported format!"); + } + + fn findDepthFormat() -> vk::Format { + return findSupportedFormat( + { vk::Format::eD32Sfloat, vk::Format::eD32SfloatS8Uint, vk::Format::eD24UnormS8Uint }, + vk::ImageTiling::eOptimal, + vk::FormatFeatureFlagBits::eDepthStencilAttachment + ); + } + + static fn hasStencilComponent(vk::Format format) { + return format == vk::Format::eD32SfloatS8Uint || format == vk::Format::eD24UnormS8Uint; + } + fn createTextureImage() -> void { i32 texWidth = 0, texHeight = 0, texChannels = 0; u8* pixels = stbi_load("src/textures/texture.jpg", &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); @@ -783,8 +840,6 @@ class VulkanApp { vk::UniqueCommandBuffer commandBuffer = beginSingleTimeCommands(); vk::ImageMemoryBarrier barrier { - .srcAccessMask = { }, - .dstAccessMask = { }, .oldLayout = oldLayout, .newLayout = newLayout, .srcQueueFamilyIndex = vk::QueueFamilyIgnored, @@ -795,7 +850,7 @@ class VulkanApp { .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, - .layerCount = 1 }, + .layerCount = 1 } // clang-format on }; @@ -1080,14 +1135,17 @@ class VulkanApp { commandBuffer.begin(beginInfo); - vk::ClearValue clearColor { .color = { .float32 = std::array { 0.0F, 0.0F, 0.0F, 1.0F } } }; + std::array clearValues { + { { .color = { .float32 = std::array { 0.0F, 0.0F, 0.0F, 1.0F } } }, + { .depthStencil = { .depth = 1.0F, .stencil = 0 } } } + }; vk::RenderPassBeginInfo renderPassInfo { .renderPass = mRenderPass.get(), .framebuffer = mSwapChainFramebuffers[imageIndex].get(), .renderArea = { .offset = { .x = 0, .y = 0 }, .extent = mSwapChainExtent }, - .clearValueCount = 1, - .pClearValues = &clearColor, + .clearValueCount = static_cast(clearValues.size()), + .pClearValues = clearValues.data() }; commandBuffer.beginRenderPass(renderPassInfo, vk::SubpassContents::eInline); @@ -1226,8 +1284,6 @@ class VulkanApp { vk::Result presentResult = mPresentQueue.presentKHR(presentInfo); - fmt::println("Present result: {}", vk::to_string(presentResult)); - if (presentResult == vk::Result::eErrorOutOfDateKHR || presentResult == vk::Result::eSuboptimalKHR || mFramebufferResized) { mFramebufferResized = false; diff --git a/src/shaders/shader.vert b/src/shaders/shader.vert index 5510aa3..840711c 100644 --- a/src/shaders/shader.vert +++ b/src/shaders/shader.vert @@ -6,7 +6,7 @@ layout(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,7 +14,7 @@ layout(location = 0) out vec3 fragColor; layout(location = 1) out vec2 fragTexCoord; void main() { - 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/src/shaders/vert.spv b/src/shaders/vert.spv index 9ded648..99280dc 100644 Binary files a/src/shaders/vert.spv and b/src/shaders/vert.spv differ