diff --git a/examples/multisampling/multisampling.cpp b/examples/multisampling/multisampling.cpp index 32c9039b..3916d3a8 100644 --- a/examples/multisampling/multisampling.cpp +++ b/examples/multisampling/multisampling.cpp @@ -1,5 +1,8 @@ /* -* Vulkan Example - Multisampling using resolve attachments +* Vulkan Example - Multisampling using resolve attachments (MSAA) +* +* This sample shows how to do multisampled anti aliasing using built-in hardware via resolve attachments +* These are special attachments that a multi-sampled is resolved to using a fixed sample pattern * * Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de * @@ -9,19 +12,6 @@ #include "vulkanexamplebase.h" #include "VulkanglTFModel.h" -struct { - struct { - VkImage image; - VkImageView view; - VkDeviceMemory memory; - } color; - struct { - VkImage image; - VkImageView view; - VkDeviceMemory memory; - } depth; -} multisampleTarget; - class VulkanExample : public VulkanExampleBase { public: @@ -30,23 +20,36 @@ public: vkglTF::Model model; - vks::Buffer uniformBuffer; - - struct UBOVS { + struct UniformData { glm::mat4 projection; glm::mat4 model; glm::vec4 lightPos = glm::vec4(5.0f, -5.0f, 5.0f, 1.0f); - } uboVS; + } uniformData; + vks::Buffer uniformBuffer; struct { - VkPipeline MSAA; - VkPipeline MSAASampleShading; + VkPipeline MSAA{ VK_NULL_HANDLE }; + VkPipeline MSAASampleShading{ VK_NULL_HANDLE }; } pipelines; - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; - VkDescriptorSetLayout descriptorSetLayout; - VkExtent2D attachmentSize; + VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE }; + VkDescriptorSet descriptorSet{ VK_NULL_HANDLE }; + VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE }; + VkExtent2D attachmentSize{}; + + // Holds the Vulkan resources required for the final multi sample output target + struct MultiSampleTarget { + struct { + VkImage image{ VK_NULL_HANDLE }; + VkImageView view{ VK_NULL_HANDLE }; + VkDeviceMemory memory{ VK_NULL_HANDLE }; + } color; + struct { + VkImage image{ VK_NULL_HANDLE }; + VkImageView view{ VK_NULL_HANDLE }; + VkDeviceMemory memory{ VK_NULL_HANDLE }; + } depth; + } multisampleTarget; VulkanExample() : VulkanExampleBase() { @@ -59,23 +62,23 @@ public: ~VulkanExample() { - // Clean up used Vulkan resources - // Note : Inherited destructor cleans up resources stored in base class - vkDestroyPipeline(device, pipelines.MSAA, nullptr); - vkDestroyPipeline(device, pipelines.MSAASampleShading, nullptr); + if (device) { + vkDestroyPipeline(device, pipelines.MSAA, nullptr); + vkDestroyPipeline(device, pipelines.MSAASampleShading, nullptr); - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - // Destroy MSAA target - vkDestroyImage(device, multisampleTarget.color.image, nullptr); - vkDestroyImageView(device, multisampleTarget.color.view, nullptr); - vkFreeMemory(device, multisampleTarget.color.memory, nullptr); - vkDestroyImage(device, multisampleTarget.depth.image, nullptr); - vkDestroyImageView(device, multisampleTarget.depth.view, nullptr); - vkFreeMemory(device, multisampleTarget.depth.memory, nullptr); + // Destroy MSAA target + vkDestroyImage(device, multisampleTarget.color.image, nullptr); + vkDestroyImageView(device, multisampleTarget.color.view, nullptr); + vkFreeMemory(device, multisampleTarget.color.memory, nullptr); + vkDestroyImage(device, multisampleTarget.depth.image, nullptr); + vkDestroyImageView(device, multisampleTarget.depth.view, nullptr); + vkFreeMemory(device, multisampleTarget.depth.memory, nullptr); - uniformBuffer.destroy(); + uniformBuffer.destroy(); + } } // Enable physical device features required for this example @@ -384,21 +387,17 @@ public: model.loadFromFile(getAssetPath() + "models/voyager.gltf", vulkanDevice, queue, vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::FlipY); } - void setupDescriptorPool() + void setupDescriptors() { - // Example uses one ubo and one combined image sampler - std::vector poolSizes = - { + // Pool + std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1), }; - VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - void setupDescriptorSetLayout() - { + // Layout const std::vector setLayoutBindings = { // Binding 0 : Vertex shader uniform buffer vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), @@ -406,17 +405,7 @@ public: VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - // Layout uses set 0 for passing vertex shader ubo and set 1 for fragment shader images (taken from glTF model) - const std::vector setLayouts = { - descriptorSetLayout, - vkglTF::descriptorSetLayoutImage, - }; - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), 2); - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - } - - void setupDescriptorSet() - { + // Set VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); std::vector writeDescriptorSets = { @@ -428,6 +417,15 @@ public: void preparePipelines() { + // Layout uses set 0 for passing vertex shader ubo and set 1 for fragment shader images (taken from glTF model) + const std::vector setLayouts = { + descriptorSetLayout, + vkglTF::descriptorSetLayoutImage, + }; + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), 2); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + + // Pipeline VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0); VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); @@ -479,32 +477,16 @@ public: void prepareUniformBuffers() { // Vertex shader uniform buffer block - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBuffer, - sizeof(uboVS))); - + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffer, sizeof(UniformData))); // Map persistent VK_CHECK_RESULT(uniformBuffer.map()); - - updateUniformBuffers(); } void updateUniformBuffers() { - uboVS.projection = camera.matrices.perspective; - uboVS.model = camera.matrices.view; - memcpy(uniformBuffer.mapped, &uboVS, sizeof(uboVS)); - } - - void draw() - { - VulkanExampleBase::prepareFrame(); - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - VulkanExampleBase::submitFrame(); + uniformData.projection = camera.matrices.perspective; + uniformData.model = camera.matrices.view; + memcpy(uniformBuffer.mapped, &uniformData, sizeof(UniformData)); } // Select the highest sample count usable by the platform @@ -530,27 +512,27 @@ public: VulkanExampleBase::prepare(); loadAssets(); prepareUniformBuffers(); - setupDescriptorSetLayout(); + setupDescriptors(); preparePipelines(); - setupDescriptorPool(); - setupDescriptorSet(); buildCommandBuffers(); prepared = true; } + void draw() + { + VulkanExampleBase::prepareFrame(); + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + VulkanExampleBase::submitFrame(); + } + virtual void render() { if (!prepared) return; - draw(); - if (camera.updated) { - updateUniformBuffers(); - } - } - - virtual void viewChanged() - { updateUniformBuffers(); + draw(); } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)