From b92e210bbe54589579865239b86b2ce83960511f Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 20 Jan 2024 13:05:02 +0100 Subject: [PATCH] Code cleanup, simplification --- examples/hdr/hdr.cpp | 263 +++++++----------- examples/multithreading/multithreading.cpp | 99 +++---- examples/ssao/ssao.cpp | 301 ++++++++++----------- shaders/glsl/hdr/composition.vert | 5 - shaders/glsl/hdr/gbuffer.frag | 7 +- shaders/glsl/hdr/gbuffer.frag.spv | Bin 6256 -> 6364 bytes shaders/glsl/hdr/gbuffer.vert | 6 +- shaders/glsl/hdr/gbuffer.vert.spv | Bin 3332 -> 3584 bytes 8 files changed, 285 insertions(+), 396 deletions(-) diff --git a/examples/hdr/hdr.cpp b/examples/hdr/hdr.cpp index 9601f08c..4687e11e 100644 --- a/examples/hdr/hdr.cpp +++ b/examples/hdr/hdr.cpp @@ -1,6 +1,11 @@ /* -* Vulkan Example - High dynamic range rendering +* Vulkan Example - High dynamic range rendering pipeline * +* This sample implements a HDR rendering pipeline that uses a wider range of possible colors via float component image formats +* It also does a bloom filter on the HDR image +* The final output is standard definition range (SDR) +* Note: Does not make use of HDR display capability. HDR is only internally used for offscreen rendering. +* * Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) @@ -22,48 +27,43 @@ public: struct Models { vkglTF::Model skybox; std::vector objects; - int32_t objectIndex = 1; + int32_t index{ 1 }; } models; + std::vector modelNames{}; - struct { - vks::Buffer matrices; - vks::Buffer params; - } uniformBuffers; - - struct UBOVS { + struct UniformData { glm::mat4 projection; glm::mat4 modelview; glm::mat4 inverseModelview; - } uboVS; - - struct UBOParams { - float exposure = 1.0f; - } uboParams; + float exposure{ 1.0f }; + } uniformData; + vks::Buffer uniformBuffer; struct { - VkPipeline skybox; - VkPipeline reflect; - VkPipeline composition; - VkPipeline bloom[2]; + VkPipeline skybox{ VK_NULL_HANDLE }; + VkPipeline reflect{ VK_NULL_HANDLE }; + VkPipeline composition{ VK_NULL_HANDLE }; + // Bloom is a two pass filter (one pass for vertical and horizontal blur) + VkPipeline bloom[2]{ VK_NULL_HANDLE }; } pipelines; struct { - VkPipelineLayout models; - VkPipelineLayout composition; - VkPipelineLayout bloomFilter; + VkPipelineLayout models{ VK_NULL_HANDLE }; + VkPipelineLayout composition{ VK_NULL_HANDLE }; + VkPipelineLayout bloomFilter{ VK_NULL_HANDLE }; } pipelineLayouts; struct { - VkDescriptorSet object; - VkDescriptorSet skybox; - VkDescriptorSet composition; - VkDescriptorSet bloomFilter; + VkDescriptorSet object{ VK_NULL_HANDLE }; + VkDescriptorSet skybox{ VK_NULL_HANDLE }; + VkDescriptorSet composition{ VK_NULL_HANDLE }; + VkDescriptorSet bloomFilter{ VK_NULL_HANDLE }; } descriptorSets; struct { - VkDescriptorSetLayout models; - VkDescriptorSetLayout composition; - VkDescriptorSetLayout bloomFilter; + VkDescriptorSetLayout models{ VK_NULL_HANDLE }; + VkDescriptorSetLayout composition{ VK_NULL_HANDLE }; + VkDescriptorSetLayout bloomFilter{ VK_NULL_HANDLE }; } descriptorSetLayouts; // Framebuffer for offscreen rendering @@ -96,8 +96,6 @@ public: VkSampler sampler; } filterPass; - std::vector objectNames; - VulkanExample() : VulkanExampleBase() { title = "High dynamic range rendering"; @@ -109,38 +107,31 @@ public: ~VulkanExample() { - vkDestroyPipeline(device, pipelines.skybox, nullptr); - vkDestroyPipeline(device, pipelines.reflect, nullptr); - vkDestroyPipeline(device, pipelines.composition, nullptr); - vkDestroyPipeline(device, pipelines.bloom[0], nullptr); - vkDestroyPipeline(device, pipelines.bloom[1], nullptr); - - vkDestroyPipelineLayout(device, pipelineLayouts.models, nullptr); - vkDestroyPipelineLayout(device, pipelineLayouts.composition, nullptr); - vkDestroyPipelineLayout(device, pipelineLayouts.bloomFilter, nullptr); - - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.models, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.composition, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.bloomFilter, nullptr); - - vkDestroyRenderPass(device, offscreen.renderPass, nullptr); - vkDestroyRenderPass(device, filterPass.renderPass, nullptr); - - vkDestroyFramebuffer(device, offscreen.frameBuffer, nullptr); - vkDestroyFramebuffer(device, filterPass.frameBuffer, nullptr); - - vkDestroySampler(device, offscreen.sampler, nullptr); - vkDestroySampler(device, filterPass.sampler, nullptr); - - offscreen.depth.destroy(device); - offscreen.color[0].destroy(device); - offscreen.color[1].destroy(device); - - filterPass.color[0].destroy(device); - - uniformBuffers.matrices.destroy(); - uniformBuffers.params.destroy(); - textures.envmap.destroy(); + if (device) { + vkDestroyPipeline(device, pipelines.skybox, nullptr); + vkDestroyPipeline(device, pipelines.reflect, nullptr); + vkDestroyPipeline(device, pipelines.composition, nullptr); + vkDestroyPipeline(device, pipelines.bloom[0], nullptr); + vkDestroyPipeline(device, pipelines.bloom[1], nullptr); + vkDestroyPipelineLayout(device, pipelineLayouts.models, nullptr); + vkDestroyPipelineLayout(device, pipelineLayouts.composition, nullptr); + vkDestroyPipelineLayout(device, pipelineLayouts.bloomFilter, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.models, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.composition, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.bloomFilter, nullptr); + vkDestroyRenderPass(device, offscreen.renderPass, nullptr); + vkDestroyRenderPass(device, filterPass.renderPass, nullptr); + vkDestroyFramebuffer(device, offscreen.frameBuffer, nullptr); + vkDestroyFramebuffer(device, filterPass.frameBuffer, nullptr); + vkDestroySampler(device, offscreen.sampler, nullptr); + vkDestroySampler(device, filterPass.sampler, nullptr); + offscreen.depth.destroy(device); + offscreen.color[0].destroy(device); + offscreen.color[1].destroy(device); + filterPass.color[0].destroy(device); + uniformBuffer.destroy(); + textures.envmap.destroy(); + } } void buildCommandBuffers() @@ -202,10 +193,10 @@ public: // 3D object vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.models, 0, 1, &descriptorSets.object, 0, NULL); - vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.objects[models.objectIndex].vertices.buffer, offsets); - vkCmdBindIndexBuffer(drawCmdBuffers[i], models.objects[models.objectIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.objects[models.index].vertices.buffer, offsets); + vkCmdBindIndexBuffer(drawCmdBuffers[i], models.objects[models.index].indices.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.reflect); - models.objects[models.objectIndex].draw(drawCmdBuffers[i]); + models.objects[models.index].draw(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]); } @@ -567,7 +558,7 @@ public: const uint32_t glTFLoadingFlags = vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::FlipY; models.skybox.loadFromFile(getAssetPath() + "models/cube.gltf", vulkanDevice, queue, glTFLoadingFlags); std::vector filenames = { "sphere.gltf", "teapot.gltf", "torusknot.gltf", "venus.gltf" }; - objectNames = { "Sphere", "Teapot", "Torusknot", "Venus" }; + modelNames = { "Sphere", "Teapot", "Torusknot", "Venus" }; models.objects.resize(filenames.size()); for (size_t i = 0; i < filenames.size(); i++) { models.objects[i].loadFromFile(getAssetPath() + "models/" + filenames[i], vulkanDevice, queue, glTFLoadingFlags); @@ -576,38 +567,25 @@ public: textures.envmap.loadFromFile(getAssetPath() + "textures/hdr/uffizi_cube.ktx", VK_FORMAT_R16G16B16A16_SFLOAT, vulkanDevice, queue); } - void setupDescriptorPool() + void setupDescriptors() { + // Pool std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 4), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 6) }; - uint32_t numDescriptorSets = 4; - VkDescriptorPoolCreateInfo descriptorPoolInfo = - vks::initializers::descriptorPoolCreateInfo(static_cast(poolSizes.size()), poolSizes.data(), numDescriptorSets); + const uint32_t numDescriptorSets = 4; + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(static_cast(poolSizes.size()), poolSizes.data(), numDescriptorSets); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - void setupDescriptorSetLayout() - { + // Layouts std::vector setLayoutBindings = { vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0), vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1), - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 2), }; - - VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo = - vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size())); - + VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size())); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutInfo, nullptr, &descriptorSetLayouts.models)); - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo( - &descriptorSetLayouts.models, - 1); - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.models)); - // Bloom filter setLayoutBindings = { vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0), @@ -617,8 +595,6 @@ public: descriptorLayoutInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size())); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutInfo, nullptr, &descriptorSetLayouts.bloomFilter)); - pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.bloomFilter, 1); - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.bloomFilter)); // G-Buffer composition setLayoutBindings = { @@ -629,71 +605,65 @@ public: descriptorLayoutInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size())); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutInfo, nullptr, &descriptorSetLayouts.composition)); - pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.composition, 1); - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.composition)); - } - - void setupDescriptorSets() - { - VkDescriptorSetAllocateInfo allocInfo = - vks::initializers::descriptorSetAllocateInfo( - descriptorPool, - &descriptorSetLayouts.models, - 1); + // Sets + VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.models, 1); // 3D object descriptor set VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.object)); - std::vector writeDescriptorSets = { - vks::initializers::writeDescriptorSet(descriptorSets.object, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.matrices.descriptor), + vks::initializers::writeDescriptorSet(descriptorSets.object, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), vks::initializers::writeDescriptorSet(descriptorSets.object, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textures.envmap.descriptor), - vks::initializers::writeDescriptorSet(descriptorSets.object, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &uniformBuffers.params.descriptor), }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); // Sky box descriptor set VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.skybox)); - writeDescriptorSets = { - vks::initializers::writeDescriptorSet(descriptorSets.skybox, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0,&uniformBuffers.matrices.descriptor), + vks::initializers::writeDescriptorSet(descriptorSets.skybox, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0,&uniformBuffer.descriptor), vks::initializers::writeDescriptorSet(descriptorSets.skybox, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textures.envmap.descriptor), - vks::initializers::writeDescriptorSet(descriptorSets.skybox, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &uniformBuffers.params.descriptor), }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); // Bloom filter allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.bloomFilter, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.bloomFilter)); - std::vector colorDescriptors = { vks::initializers::descriptorImageInfo(offscreen.sampler, offscreen.color[0].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL), vks::initializers::descriptorImageInfo(offscreen.sampler, offscreen.color[1].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL), }; - writeDescriptorSets = { vks::initializers::writeDescriptorSet(descriptorSets.bloomFilter, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &colorDescriptors[0]), vks::initializers::writeDescriptorSet(descriptorSets.bloomFilter, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &colorDescriptors[1]), }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); // Composition descriptor set - allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.composition, 1); + allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.composition, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.composition)); - colorDescriptors = { vks::initializers::descriptorImageInfo(offscreen.sampler, offscreen.color[0].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL), vks::initializers::descriptorImageInfo(offscreen.sampler, filterPass.color[0].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL), }; - writeDescriptorSets = { vks::initializers::writeDescriptorSet(descriptorSets.composition, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &colorDescriptors[0]), vks::initializers::writeDescriptorSet(descriptorSets.composition, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &colorDescriptors[1]), }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } void preparePipelines() { + // Layouts + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.models, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.models)); + + pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.bloomFilter, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.bloomFilter)); + + pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.composition, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.composition)); + + // Pipelines 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); @@ -798,39 +768,29 @@ public: // Prepare and initialize uniform buffer containing shader uniforms void prepareUniformBuffers() { - // Matrices vertex shader uniform buffer - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBuffers.matrices, - sizeof(uboVS))); - - // Params - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBuffers.params, - sizeof(uboParams))); - + 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(uniformBuffers.matrices.map()); - VK_CHECK_RESULT(uniformBuffers.params.map()); - - updateUniformBuffers(); - updateParams(); + VK_CHECK_RESULT(uniformBuffer.map()); } void updateUniformBuffers() { - uboVS.projection = camera.matrices.perspective; - uboVS.modelview = camera.matrices.view; - uboVS.inverseModelview = glm::inverse(camera.matrices.view); - memcpy(uniformBuffers.matrices.mapped, &uboVS, sizeof(uboVS)); + uniformData.projection = camera.matrices.perspective; + uniformData.modelview = camera.matrices.view; + uniformData.inverseModelview = glm::inverse(camera.matrices.view); + memcpy(uniformBuffer.mapped, &uniformData, sizeof(uniformData)); } - void updateParams() + void prepare() { - memcpy(uniformBuffers.params.mapped, &uboParams, sizeof(uboParams)); + VulkanExampleBase::prepare(); + loadAssets(); + prepareUniformBuffers(); + prepareoffscreenfer(); + setupDescriptors(); + preparePipelines(); + buildCommandBuffers(); + prepared = true; } void draw() @@ -842,44 +802,21 @@ public: VulkanExampleBase::submitFrame(); } - void prepare() - { - VulkanExampleBase::prepare(); - loadAssets(); - prepareUniformBuffers(); - prepareoffscreenfer(); - setupDescriptorSetLayout(); - preparePipelines(); - setupDescriptorPool(); - setupDescriptorSets(); - buildCommandBuffers(); - prepared = true; - } - virtual void render() { if (!prepared) return; - draw(); - if (camera.updated) - updateUniformBuffers(); - } - - virtual void viewChanged() - { updateUniformBuffers(); + draw(); } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { - if (overlay->comboBox("Object type", &models.objectIndex, objectNames)) { - updateUniformBuffers(); + if (overlay->comboBox("Object type", &models.index, modelNames)) { buildCommandBuffers(); } - if (overlay->inputFloat("Exposure", &uboParams.exposure, 0.025f, 3)) { - updateParams(); - } + overlay->inputFloat("Exposure", &uniformData.exposure, 0.025f, 3); if (overlay->checkBox("Bloom", &bloom)) { buildCommandBuffers(); } diff --git a/examples/multithreading/multithreading.cpp b/examples/multithreading/multithreading.cpp index 4af6d555..cd80edfe 100644 --- a/examples/multithreading/multithreading.cpp +++ b/examples/multithreading/multithreading.cpp @@ -30,27 +30,25 @@ public: } matrices; struct { - VkPipeline phong; - VkPipeline starsphere; + VkPipeline phong{ VK_NULL_HANDLE }; + VkPipeline starsphere{ VK_NULL_HANDLE }; } pipelines; - - VkPipelineLayout pipelineLayout; - - VkCommandBuffer primaryCommandBuffer; + VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE }; + VkCommandBuffer primaryCommandBuffer{ VK_NULL_HANDLE }; // Secondary scene command buffers used to store backdrop and user interface struct SecondaryCommandBuffers { - VkCommandBuffer background; - VkCommandBuffer ui; + VkCommandBuffer background{ VK_NULL_HANDLE }; + VkCommandBuffer ui{ VK_NULL_HANDLE }; } secondaryCommandBuffers; // Number of animated objects to be renderer // by using threads and secondary command buffers - uint32_t numObjectsPerThread; + uint32_t numObjectsPerThread{ 0 }; // Multi threaded stuff // Max. number of concurrent threads - uint32_t numThreads; + uint32_t numThreads{ 0 }; // Use push constants to update shader // parameters on a per-thread base @@ -72,7 +70,7 @@ public: }; struct ThreadData { - VkCommandPool commandPool; + VkCommandPool commandPool{ VK_NULL_HANDLE }; // One command buffer per render object std::vector commandBuffer; // One push constant block per render object @@ -86,7 +84,7 @@ public: // Fence to wait for all command buffers to finish before // presenting to the swap chain - VkFence renderFence = {}; + VkFence renderFence{ VK_NULL_HANDLE }; // View frustum for culling invisible objects vks::Frustum frustum; @@ -116,19 +114,16 @@ public: ~VulkanExample() { - // Clean up used Vulkan resources - // Note : Inherited destructor cleans up resources stored in base class - vkDestroyPipeline(device, pipelines.phong, nullptr); - vkDestroyPipeline(device, pipelines.starsphere, nullptr); - - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - - for (auto& thread : threadData) { - vkFreeCommandBuffers(device, thread.commandPool, static_cast(thread.commandBuffer.size()), thread.commandBuffer.data()); - vkDestroyCommandPool(device, thread.commandPool, nullptr); + if (device) { + vkDestroyPipeline(device, pipelines.phong, nullptr); + vkDestroyPipeline(device, pipelines.starsphere, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + for (auto& thread : threadData) { + vkFreeCommandBuffers(device, thread.commandPool, static_cast(thread.commandBuffer.size()), thread.commandBuffer.data()); + vkDestroyCommandPool(device, thread.commandPool, nullptr); + } + vkDestroyFence(device, renderFence, nullptr); } - - vkDestroyFence(device, renderFence, nullptr); } float rnd(float range) @@ -412,27 +407,18 @@ public: models.starSphere.loadFromFile(getAssetPath() + "models/sphere.gltf", vulkanDevice, queue, glTFLoadingFlags); } - void setupPipelineLayout() + void preparePipelines() { - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo(nullptr, 0); - + // Layout + VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(nullptr, 0); // Push constants for model matrices - VkPushConstantRange pushConstantRange = - vks::initializers::pushConstantRange( - VK_SHADER_STAGE_VERTEX_BIT, - sizeof(ThreadPushConstantBlock), - 0); - + VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(ThreadPushConstantBlock), 0); // Push constant ranges are part of the pipeline layout pPipelineLayoutCreateInfo.pushConstantRangeCount = 1; pPipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange; - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - } - void preparePipelines() - { + // Pipelines 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); @@ -476,6 +462,19 @@ public: frustum.update(matrices.projection * matrices.view); } + void prepare() + { + VulkanExampleBase::prepare(); + // Create a fence for synchronization + VkFenceCreateInfo fenceCreateInfo = vks::initializers::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT); + vkCreateFence(device, &fenceCreateInfo, nullptr, &renderFence); + loadAssets(); + preparePipelines(); + prepareMultiThreadedRenderer(); + updateMatrices(); + prepared = true; + } + void draw() { // Wait for fence to signal that all command buffers are ready @@ -498,34 +497,12 @@ public: VulkanExampleBase::submitFrame(); } - void prepare() - { - VulkanExampleBase::prepare(); - // Create a fence for synchronization - VkFenceCreateInfo fenceCreateInfo = vks::initializers::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT); - vkCreateFence(device, &fenceCreateInfo, nullptr, &renderFence); - loadAssets(); - setupPipelineLayout(); - preparePipelines(); - prepareMultiThreadedRenderer(); - updateMatrices(); - prepared = true; - } - virtual void render() { if (!prepared) return; - draw(); - if (camera.updated) - { - updateMatrices(); - } - } - - virtual void viewChanged() - { updateMatrices(); + draw(); } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) diff --git a/examples/ssao/ssao.cpp b/examples/ssao/ssao.cpp index 6587ce5f..41f74ec1 100644 --- a/examples/ssao/ssao.cpp +++ b/examples/ssao/ssao.cpp @@ -12,6 +12,7 @@ #define SSAO_KERNEL_SIZE 64 #define SSAO_RADIUS 0.3f +// We use a smaller noise kernel size on Android due to lower computational power #if defined(__ANDROID__) #define SSAO_NOISE_DIM 8 #else @@ -21,10 +22,7 @@ class VulkanExample : public VulkanExampleBase { public: - struct { - vks::Texture2D ssaoNoise; - } textures; - + vks::Texture2D ssaoNoise; vkglTF::Model scene; struct UBOSceneParams { @@ -43,33 +41,32 @@ public: } uboSSAOParams; struct { - VkPipeline offscreen; - VkPipeline composition; - VkPipeline ssao; - VkPipeline ssaoBlur; + VkPipeline offscreen{ VK_NULL_HANDLE }; + VkPipeline composition{ VK_NULL_HANDLE }; + VkPipeline ssao{ VK_NULL_HANDLE }; + VkPipeline ssaoBlur{ VK_NULL_HANDLE }; } pipelines; struct { - VkPipelineLayout gBuffer; - VkPipelineLayout ssao; - VkPipelineLayout ssaoBlur; - VkPipelineLayout composition; + VkPipelineLayout gBuffer{ VK_NULL_HANDLE }; + VkPipelineLayout ssao{ VK_NULL_HANDLE }; + VkPipelineLayout ssaoBlur{ VK_NULL_HANDLE }; + VkPipelineLayout composition{ VK_NULL_HANDLE }; } pipelineLayouts; struct { - const uint32_t count = 5; - VkDescriptorSet model; - VkDescriptorSet floor; - VkDescriptorSet ssao; - VkDescriptorSet ssaoBlur; - VkDescriptorSet composition; + VkDescriptorSet gBuffer{ VK_NULL_HANDLE }; + VkDescriptorSet ssao{ VK_NULL_HANDLE }; + VkDescriptorSet ssaoBlur{ VK_NULL_HANDLE }; + VkDescriptorSet composition{ VK_NULL_HANDLE }; + const uint32_t count = 4; } descriptorSets; struct { - VkDescriptorSetLayout gBuffer; - VkDescriptorSetLayout ssao; - VkDescriptorSetLayout ssaoBlur; - VkDescriptorSetLayout composition; + VkDescriptorSetLayout gBuffer{ VK_NULL_HANDLE }; + VkDescriptorSetLayout ssao{ VK_NULL_HANDLE }; + VkDescriptorSetLayout ssaoBlur{ VK_NULL_HANDLE }; + VkDescriptorSetLayout composition{ VK_NULL_HANDLE }; } descriptorSetLayouts; struct { @@ -114,7 +111,7 @@ public: struct SSAO : public FrameBuffer { FrameBufferAttachment color; } ssao, ssaoBlur; - } frameBuffers; + } frameBuffers{}; // One sampler for the frame buffer color attachments VkSampler colorSampler; @@ -133,42 +130,44 @@ public: ~VulkanExample() { - vkDestroySampler(device, colorSampler, nullptr); + if (device) { + vkDestroySampler(device, colorSampler, nullptr); - // Attachments - frameBuffers.offscreen.position.destroy(device); - frameBuffers.offscreen.normal.destroy(device); - frameBuffers.offscreen.albedo.destroy(device); - frameBuffers.offscreen.depth.destroy(device); - frameBuffers.ssao.color.destroy(device); - frameBuffers.ssaoBlur.color.destroy(device); + // Attachments + frameBuffers.offscreen.position.destroy(device); + frameBuffers.offscreen.normal.destroy(device); + frameBuffers.offscreen.albedo.destroy(device); + frameBuffers.offscreen.depth.destroy(device); + frameBuffers.ssao.color.destroy(device); + frameBuffers.ssaoBlur.color.destroy(device); - // Framebuffers - frameBuffers.offscreen.destroy(device); - frameBuffers.ssao.destroy(device); - frameBuffers.ssaoBlur.destroy(device); + // Framebuffers + frameBuffers.offscreen.destroy(device); + frameBuffers.ssao.destroy(device); + frameBuffers.ssaoBlur.destroy(device); - vkDestroyPipeline(device, pipelines.offscreen, nullptr); - vkDestroyPipeline(device, pipelines.composition, nullptr); - vkDestroyPipeline(device, pipelines.ssao, nullptr); - vkDestroyPipeline(device, pipelines.ssaoBlur, nullptr); + vkDestroyPipeline(device, pipelines.offscreen, nullptr); + vkDestroyPipeline(device, pipelines.composition, nullptr); + vkDestroyPipeline(device, pipelines.ssao, nullptr); + vkDestroyPipeline(device, pipelines.ssaoBlur, nullptr); - vkDestroyPipelineLayout(device, pipelineLayouts.gBuffer, nullptr); - vkDestroyPipelineLayout(device, pipelineLayouts.ssao, nullptr); - vkDestroyPipelineLayout(device, pipelineLayouts.ssaoBlur, nullptr); - vkDestroyPipelineLayout(device, pipelineLayouts.composition, nullptr); + vkDestroyPipelineLayout(device, pipelineLayouts.gBuffer, nullptr); + vkDestroyPipelineLayout(device, pipelineLayouts.ssao, nullptr); + vkDestroyPipelineLayout(device, pipelineLayouts.ssaoBlur, nullptr); + vkDestroyPipelineLayout(device, pipelineLayouts.composition, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.gBuffer, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.ssao, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.ssaoBlur, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.composition, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.gBuffer, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.ssao, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.ssaoBlur, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.composition, nullptr); - // Uniform buffers - uniformBuffers.sceneParams.destroy(); - uniformBuffers.ssaoKernel.destroy(); - uniformBuffers.ssaoParams.destroy(); + // Uniform buffers + uniformBuffers.sceneParams.destroy(); + uniformBuffers.ssaoKernel.destroy(); + uniformBuffers.ssaoParams.destroy(); - textures.ssaoNoise.destroy(); + ssaoNoise.destroy(); + } } void getEnabledFeatures() @@ -529,7 +528,7 @@ public: vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.offscreen); - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.gBuffer, 0, 1, &descriptorSets.floor, 0, NULL); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.gBuffer, 0, 1, &descriptorSets.gBuffer, 0, nullptr); scene.draw(drawCmdBuffers[i], vkglTF::RenderFlags::BindImages, pipelineLayouts.gBuffer); vkCmdEndRenderPass(drawCmdBuffers[i]); @@ -555,7 +554,7 @@ public: scissor = vks::initializers::rect2D(frameBuffers.ssao.width, frameBuffers.ssao.height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.ssao, 0, 1, &descriptorSets.ssao, 0, NULL); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.ssao, 0, 1, &descriptorSets.ssao, 0, nullptr); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.ssao); vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); @@ -577,7 +576,7 @@ public: scissor = vks::initializers::rect2D(frameBuffers.ssaoBlur.width, frameBuffers.ssaoBlur.height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.ssaoBlur, 0, 1, &descriptorSets.ssaoBlur, 0, NULL); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.ssaoBlur, 0, 1, &descriptorSets.ssaoBlur, 0, nullptr); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.ssaoBlur); vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); @@ -627,25 +626,24 @@ public: } } - void setupDescriptorPool() + void setupDescriptors() { + // Pool std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 10), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 12) }; VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, descriptorSets.count); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - void setupLayoutsAndDescriptors() - { std::vector setLayoutBindings; VkDescriptorSetLayoutCreateInfo setLayoutCreateInfo; - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(); VkDescriptorSetAllocateInfo descriptorAllocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, nullptr, 1); std::vector writeDescriptorSets; std::vector imageDescriptors; + // Layouts and Sets + // G-Buffer creation (offscreen scene rendering) setLayoutBindings = { vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0), // VS + FS Parameter UBO @@ -653,17 +651,12 @@ public: setLayoutCreateInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size())); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &setLayoutCreateInfo, nullptr, &descriptorSetLayouts.gBuffer)); - const std::vector setLayouts = { descriptorSetLayouts.gBuffer, vkglTF::descriptorSetLayoutImage }; - pipelineLayoutCreateInfo.pSetLayouts = setLayouts.data(); - pipelineLayoutCreateInfo.setLayoutCount = 2; - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.gBuffer)); descriptorAllocInfo.pSetLayouts = &descriptorSetLayouts.gBuffer; - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorAllocInfo, &descriptorSets.floor)); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorAllocInfo, &descriptorSets.gBuffer)); writeDescriptorSets = { - vks::initializers::writeDescriptorSet(descriptorSets.floor, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.sceneParams.descriptor), + vks::initializers::writeDescriptorSet(descriptorSets.gBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.sceneParams.descriptor), }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); - pipelineLayoutCreateInfo.setLayoutCount = 1; + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); // SSAO Generation setLayoutBindings = { @@ -675,8 +668,7 @@ public: }; setLayoutCreateInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size())); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &setLayoutCreateInfo, nullptr, &descriptorSetLayouts.ssao)); - pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayouts.ssao; - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.ssao)); + descriptorAllocInfo.pSetLayouts = &descriptorSetLayouts.ssao; VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorAllocInfo, &descriptorSets.ssao)); imageDescriptors = { @@ -686,11 +678,11 @@ public: writeDescriptorSets = { vks::initializers::writeDescriptorSet(descriptorSets.ssao, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &imageDescriptors[0]), // FS Position+Depth vks::initializers::writeDescriptorSet(descriptorSets.ssao, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &imageDescriptors[1]), // FS Normals - vks::initializers::writeDescriptorSet(descriptorSets.ssao, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, &textures.ssaoNoise.descriptor), // FS SSAO Noise + vks::initializers::writeDescriptorSet(descriptorSets.ssao, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, &ssaoNoise.descriptor), // FS SSAO Noise vks::initializers::writeDescriptorSet(descriptorSets.ssao, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3, &uniformBuffers.ssaoKernel.descriptor), // FS SSAO Kernel UBO vks::initializers::writeDescriptorSet(descriptorSets.ssao, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 4, &uniformBuffers.ssaoParams.descriptor), // FS SSAO Params UBO }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); // SSAO Blur setLayoutBindings = { @@ -698,8 +690,6 @@ public: }; setLayoutCreateInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size())); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &setLayoutCreateInfo, nullptr, &descriptorSetLayouts.ssaoBlur)); - pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayouts.ssaoBlur; - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.ssaoBlur)); descriptorAllocInfo.pSetLayouts = &descriptorSetLayouts.ssaoBlur; VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorAllocInfo, &descriptorSets.ssaoBlur)); imageDescriptors = { @@ -708,7 +698,7 @@ public: writeDescriptorSets = { vks::initializers::writeDescriptorSet(descriptorSets.ssaoBlur, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &imageDescriptors[0]), }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); // Composition setLayoutBindings = { @@ -721,8 +711,6 @@ public: }; setLayoutCreateInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size())); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &setLayoutCreateInfo, nullptr, &descriptorSetLayouts.composition)); - pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayouts.composition; - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.composition)); descriptorAllocInfo.pSetLayouts = &descriptorSetLayouts.composition; VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorAllocInfo, &descriptorSets.composition)); imageDescriptors = { @@ -740,11 +728,32 @@ public: vks::initializers::writeDescriptorSet(descriptorSets.composition, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4, &imageDescriptors[4]), // FS Sampler SSAO blurred vks::initializers::writeDescriptorSet(descriptorSets.composition, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 5, &uniformBuffers.ssaoParams.descriptor), // FS SSAO Params UBO }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } void preparePipelines() { + // Layouts + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(); + + const std::vector setLayouts = { descriptorSetLayouts.gBuffer, vkglTF::descriptorSetLayoutImage }; + pipelineLayoutCreateInfo.pSetLayouts = setLayouts.data(); + pipelineLayoutCreateInfo.setLayoutCount = 2; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.gBuffer)); + + pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayouts.ssao; + pipelineLayoutCreateInfo.setLayoutCount = 1; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.ssao)); + + pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayouts.ssaoBlur; + pipelineLayoutCreateInfo.setLayoutCount = 1; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.ssaoBlur)); + + pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayouts.composition; + pipelineLayoutCreateInfo.setLayoutCount = 1; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.composition)); + + // Pipelines 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); @@ -778,53 +787,47 @@ public: VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.composition)); // SSAO generation pipeline - { - pipelineCreateInfo.renderPass = frameBuffers.ssao.renderPass; - pipelineCreateInfo.layout = pipelineLayouts.ssao; - // SSAO Kernel size and radius are constant for this pipeline, so we set them using specialization constants - struct SpecializationData { - uint32_t kernelSize = SSAO_KERNEL_SIZE; - float radius = SSAO_RADIUS; - } specializationData; - std::array specializationMapEntries = { - vks::initializers::specializationMapEntry(0, offsetof(SpecializationData, kernelSize), sizeof(SpecializationData::kernelSize)), - vks::initializers::specializationMapEntry(1, offsetof(SpecializationData, radius), sizeof(SpecializationData::radius)) - }; - VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(2, specializationMapEntries.data(), sizeof(specializationData), &specializationData); - shaderStages[1] = loadShader(getShadersPath() + "ssao/ssao.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - shaderStages[1].pSpecializationInfo = &specializationInfo; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.ssao)); - } + pipelineCreateInfo.renderPass = frameBuffers.ssao.renderPass; + pipelineCreateInfo.layout = pipelineLayouts.ssao; + // SSAO Kernel size and radius are constant for this pipeline, so we set them using specialization constants + struct SpecializationData { + uint32_t kernelSize = SSAO_KERNEL_SIZE; + float radius = SSAO_RADIUS; + } specializationData; + std::array specializationMapEntries = { + vks::initializers::specializationMapEntry(0, offsetof(SpecializationData, kernelSize), sizeof(SpecializationData::kernelSize)), + vks::initializers::specializationMapEntry(1, offsetof(SpecializationData, radius), sizeof(SpecializationData::radius)) + }; + VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(2, specializationMapEntries.data(), sizeof(specializationData), &specializationData); + shaderStages[1] = loadShader(getShadersPath() + "ssao/ssao.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + shaderStages[1].pSpecializationInfo = &specializationInfo; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.ssao)); // SSAO blur pipeline - { - pipelineCreateInfo.renderPass = frameBuffers.ssaoBlur.renderPass; - pipelineCreateInfo.layout = pipelineLayouts.ssaoBlur; - shaderStages[1] = loadShader(getShadersPath() + "ssao/blur.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.ssaoBlur)); - } + pipelineCreateInfo.renderPass = frameBuffers.ssaoBlur.renderPass; + pipelineCreateInfo.layout = pipelineLayouts.ssaoBlur; + shaderStages[1] = loadShader(getShadersPath() + "ssao/blur.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.ssaoBlur)); // Fill G-Buffer pipeline - { - // Vertex input state from glTF model loader - pipelineCreateInfo.pVertexInputState = vkglTF::Vertex::getPipelineVertexInputState({ vkglTF::VertexComponent::Position, vkglTF::VertexComponent::UV, vkglTF::VertexComponent::Color, vkglTF::VertexComponent::Normal }); - pipelineCreateInfo.renderPass = frameBuffers.offscreen.renderPass; - pipelineCreateInfo.layout = pipelineLayouts.gBuffer; - // Blend attachment states required for all color attachments - // This is important, as color write mask will otherwise be 0x0 and you - // won't see anything rendered to the attachment - std::array blendAttachmentStates = { - vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE), - vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE), - vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE) - }; - colorBlendState.attachmentCount = static_cast(blendAttachmentStates.size()); - colorBlendState.pAttachments = blendAttachmentStates.data(); - rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT; - shaderStages[0] = loadShader(getShadersPath() + "ssao/gbuffer.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getShadersPath() + "ssao/gbuffer.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.offscreen)); - } + // Vertex input state from glTF model loader + pipelineCreateInfo.pVertexInputState = vkglTF::Vertex::getPipelineVertexInputState({ vkglTF::VertexComponent::Position, vkglTF::VertexComponent::UV, vkglTF::VertexComponent::Color, vkglTF::VertexComponent::Normal }); + pipelineCreateInfo.renderPass = frameBuffers.offscreen.renderPass; + pipelineCreateInfo.layout = pipelineLayouts.gBuffer; + // Blend attachment states required for all color attachments + // This is important, as color write mask will otherwise be 0x0 and you + // won't see anything rendered to the attachment + std::array blendAttachmentStates = { + vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE), + vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE), + vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE) + }; + colorBlendState.attachmentCount = static_cast(blendAttachmentStates.size()); + colorBlendState.pAttachments = blendAttachmentStates.data(); + rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT; + shaderStages[0] = loadShader(getShadersPath() + "ssao/gbuffer.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getShadersPath() + "ssao/gbuffer.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.offscreen)); } float lerp(float a, float b, float f) @@ -878,13 +881,12 @@ public: ssaoKernel.data()); // Random noise - std::vector ssaoNoise(SSAO_NOISE_DIM * SSAO_NOISE_DIM); - for (uint32_t i = 0; i < static_cast(ssaoNoise.size()); i++) - { - ssaoNoise[i] = glm::vec4(rndDist(rndEngine) * 2.0f - 1.0f, rndDist(rndEngine) * 2.0f - 1.0f, 0.0f, 0.0f); + std::vector noiseValues(SSAO_NOISE_DIM * SSAO_NOISE_DIM); + for (uint32_t i = 0; i < static_cast(noiseValues.size()); i++) { + noiseValues[i] = glm::vec4(rndDist(rndEngine) * 2.0f - 1.0f, rndDist(rndEngine) * 2.0f - 1.0f, 0.0f, 0.0f); } // Upload as texture - textures.ssaoNoise.fromBuffer(ssaoNoise.data(), ssaoNoise.size() * sizeof(glm::vec4), VK_FORMAT_R32G32B32A32_SFLOAT, SSAO_NOISE_DIM, SSAO_NOISE_DIM, vulkanDevice, queue, VK_FILTER_NEAREST); + ssaoNoise.fromBuffer(noiseValues.data(), noiseValues.size() * sizeof(glm::vec4), VK_FORMAT_R32G32B32A32_SFLOAT, SSAO_NOISE_DIM, SSAO_NOISE_DIM, vulkanDevice, queue, VK_FILTER_NEAREST); } void updateUniformBufferMatrices() @@ -907,6 +909,18 @@ public: uniformBuffers.ssaoParams.unmap(); } + void prepare() + { + VulkanExampleBase::prepare(); + loadAssets(); + prepareOffscreenFramebuffers(); + prepareUniformBuffers(); + setupDescriptors(); + preparePipelines(); + buildCommandBuffers(); + prepared = true; + } + void draw() { VulkanExampleBase::prepareFrame(); @@ -916,49 +930,22 @@ public: VulkanExampleBase::submitFrame(); } - void prepare() - { - VulkanExampleBase::prepare(); - loadAssets(); - prepareOffscreenFramebuffers(); - prepareUniformBuffers(); - setupDescriptorPool(); - setupLayoutsAndDescriptors(); - preparePipelines(); - buildCommandBuffers(); - prepared = true; - } - virtual void render() { if (!prepared) { return; } - draw(); - if (camera.updated) { - updateUniformBufferMatrices(); - updateUniformBufferSSAOParams(); - } - } - - virtual void viewChanged() - { updateUniformBufferMatrices(); updateUniformBufferSSAOParams(); + draw(); } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { - if (overlay->checkBox("Enable SSAO", &uboSSAOParams.ssao)) { - updateUniformBufferSSAOParams(); - } - if (overlay->checkBox("SSAO blur", &uboSSAOParams.ssaoBlur)) { - updateUniformBufferSSAOParams(); - } - if (overlay->checkBox("SSAO pass only", &uboSSAOParams.ssaoOnly)) { - updateUniformBufferSSAOParams(); - } + overlay->checkBox("Enable SSAO", &uboSSAOParams.ssao); + overlay->checkBox("SSAO blur", &uboSSAOParams.ssaoBlur); + overlay->checkBox("SSAO pass only", &uboSSAOParams.ssaoOnly); } } }; diff --git a/shaders/glsl/hdr/composition.vert b/shaders/glsl/hdr/composition.vert index a5d60d0e..3a42f3c5 100644 --- a/shaders/glsl/hdr/composition.vert +++ b/shaders/glsl/hdr/composition.vert @@ -2,11 +2,6 @@ layout (location = 0) out vec2 outUV; -out gl_PerVertex -{ - vec4 gl_Position; -}; - void main() { outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); diff --git a/shaders/glsl/hdr/gbuffer.frag b/shaders/glsl/hdr/gbuffer.frag index b920dad3..e713fe36 100644 --- a/shaders/glsl/hdr/gbuffer.frag +++ b/shaders/glsl/hdr/gbuffer.frag @@ -6,6 +6,7 @@ layout (binding = 0) uniform UBO { mat4 projection; mat4 modelview; mat4 inverseModelview; + float exposure; } ubo; layout (location = 0) in vec3 inUVW; @@ -22,10 +23,6 @@ layout (constant_id = 0) const int type = 0; #define PI 3.1415926 #define TwoPI (2.0 * PI) -layout (binding = 2) uniform Exposure { - float exposure; -} exposure; - void main() { vec4 color; @@ -86,7 +83,7 @@ void main() // Color with manual exposure into attachment 0 - outColor0.rgb = vec3(1.0) - exp(-color.rgb * exposure.exposure); + outColor0.rgb = vec3(1.0) - exp(-color.rgb * ubo.exposure); // Bright parts for bloom into attachment 1 float l = dot(outColor0.rgb, vec3(0.2126, 0.7152, 0.0722)); diff --git a/shaders/glsl/hdr/gbuffer.frag.spv b/shaders/glsl/hdr/gbuffer.frag.spv index 57f315b32d34afe90f1405b81ae28e87653163f4..d06577dc5f31a2c72a507f2b225859ddd6fef0a8 100644 GIT binary patch delta 1232 zcmYk4%WD%+6vodqNn14$C9PSAwIxdx?5cvKRTLCmh|5}+1`0+-(gfVi!o5(k@!ycy zxpJd|&syKw*49UTRofc1uLS&l>0Fr!U+#Cld%ip8o-<1ar}{IAwtR<~XWOjPn&X*~ z)Mqnmj9;pEwOhOODM$##E0_JTYPlGm_s)3(37eKy5>ono(pniU7sp2Z(uGLl5WiYE z=9m0(e@jbRqjn%s-+59FcWPccw`zNme)kDW8lE1(6Nnq(Tr%TjH;d?%=#UPZsf%8) zPdV+9?+et}tN4M|HX$u^E1qoW`qM)`@zYkcng2{2FZpi&r8qUX_>DMc5|cM8OoYS1 zpcCdK4Ce-hT>M_~_32t+zsk#qe-LH`^4N2E^WtVlh7RlC+hR0;V!HIYZ(5!Im-wj| z@K0LSY+WJ-4%nf!5mq}#ygr805y{83G9VXk7hedMx13G~^y;CI7wBOjy5FNnzoto1 z{$t^ufS!)7G$Brpb_?uZjdGue-xb(DDvka=7w!o3{j4;4_`)nOl6eMo36doKH@y-TOo`)RfOyD3E7;zo8f`WsU^=7kpWD8Rw3%9SS1$M% zDU1+1twn>=)_KA8?Ta}3F8(S`&Q0B!aef!bL0^&or&gYI^_{&R!m_ZcV&OWcr&Z#j zf_RBbiqRHpH*(ovK@4S0Hjc#3F_g$2Ur&6G97^P}b%7k$!QbM1h4E4SQA{2WXOe>! zc>?>Z08@NaD~d6>QIUh@UbHHXCqAk*#dzGP$U$?S4RJht^%O!}v8`rJz2=bc4`HCh AG5`Po delta 1113 zcmZva%WG3X6vofZ&5bGKTA`IJgpk^msGutaX{(|rx^SgXy3|0yNTsdNT^6n_l)LdC zaOvvq+__M}XMI;~weeA{&(=hIfZ*?&WFTNCe3|oo=W)-OnfaY7JK`|Yzs@YMJii|^ z@kmrRv*yg1MmiOo2u?_Y)OoSk*w+3Y;>wRj)g`!z!e1VH{~ zdLbJJ-H|D%?2%rMP6xG8yLQ3JS-Z`yI_hB$x#F5j+E#du{Vvcd!|$=nr+oRfKL@kv z@Sx`};KRjTL!QsWFD@hl+bmbJ7_tDAq(C`+;3Br!-XS$|4XX}9(90*^vQxn2f5tx2 zfsMqkz{@~O^~6_!^40ivXLq+c*9SHrG}A5lk)ThP#Y|0MqdyVf82lPV+0!L-MEjt*t3;t-~aCyD4ZNGwRhefC}g}sR8jx K@RtkS4gLYllc{(B diff --git a/shaders/glsl/hdr/gbuffer.vert b/shaders/glsl/hdr/gbuffer.vert index ef9f0ad7..7a6ecc52 100644 --- a/shaders/glsl/hdr/gbuffer.vert +++ b/shaders/glsl/hdr/gbuffer.vert @@ -9,6 +9,7 @@ layout (binding = 0) uniform UBO { mat4 projection; mat4 modelview; mat4 inverseModelview; + float exposure; } ubo; layout (location = 0) out vec3 outUVW; @@ -17,11 +18,6 @@ layout (location = 2) out vec3 outNormal; layout (location = 3) out vec3 outViewVec; layout (location = 4) out vec3 outLightVec; -out gl_PerVertex -{ - vec4 gl_Position; -}; - void main() { outUVW = inPos; diff --git a/shaders/glsl/hdr/gbuffer.vert.spv b/shaders/glsl/hdr/gbuffer.vert.spv index 6563548ce0d1b30126b81d389de28d432f7f9dd3..30b2e9b80e5dc8666c99b65f833dfdf44a683735 100644 GIT binary patch literal 3584 zcmZ9N4ObLp6vroC7R%JsOe-^x-Zd&yvrHkiphCe2taB`8Xzavy(J=Cg*%qwr36AN&Tq47cFB@Fv{LzaGv%2+*JO@$aFp zy8g|z&g|T^;@((UW4hVq^nN#I=gw-%k?ZEcJ~!wm_5t+S3sY2I%Vq6WTg_YPLMLld zVc^!k(p*gI>sk5(a*Y}2Yi(I$J#Dqq%a!YGKf6zFuQuCjt+IyRer{!)?C`^q_d%mX?c27QVh2zLUap=|XPj z8-mR-HKAm@e6u6qlDcnJ)qOL2l)U%Nyce55ckWU@Ji*`4hjaA*7z>*`k=qr1#;E$K z>o*2REU|7s=UVks*Y6%2eqs;(in@Biw0i)Lm;0ujeYpomVJY;XLd|2w4mcmlJYv=- z<{6kV#mpC&vY6kDx%G|QzOyq8-8YUITZ?b0UikLq-=exP_v5AC5SqI3Q%E(=LHHnE z&OzP#LG&G^EPl4s{dVL2F=YFRd-dq?0QS4k2Vreal)8H&MLhS!c;?^FX@2WJ#NQ`5 z#ng{*##Q&7?C}`7bsU1N!@i#8^v*cuIm~Gf)?wYRaSpy>+Sk-HJtB`44WX8}lTbB=<)3A4SsE*fB46Kuq0v zy93sx{Tioz$i_FGzk5>X`Hxj{|3T0VezZjIJ@Ucj3b$1tF6KBLR^-NZy(|FJhE}b!)Fj#T$Z|hhQRbOPWT)} z7MG>)nP%SZ-7st|gRr(SqZg2!(H1>e?~Aau;@0Tfz66U)fxV0@W}d)aDKYCZukl`m z_1E5e-@@z)mBJRcm^u#EO~*@^?A|roZ;y z`z>shZ}={fAm@7n7owS!A(lFLNbUo!d1q{k8YLI=3&-&96=D!I#L@ zJy6%Kx(Dt<^!OEW_a1x=CLaBKgIw+BI=Yw?{oFtntM)TrV%2_bg6V$)_P*NB0=l`i ziMWf%;!dYk3A5N{xjt6{%?Vao6qm=J6KGL-_1I*xGY(V zxx;4#Ss(H6X&{TsQnybNOdsQf&nmLGEQL?}K7S8pEymV1-mHz>g16{lfU^T@EAAYY zOH6qkc>@mLACbjE{|R{?{9768XJl=}^}ow07WVg$wcjlNKm7$+OxsOP^?&K)4E!Hg Csp?|@ literal 3332 zcmZ9Ni*i&&5QdLgvO!T0kc+pN5bt1A1Vj-DpeAY{LCjiSNl1=iG0Dc=O#nrqiYJIq z;GMYh!D1Uf z|HWz>-`eQTH9qU@o2$7t+v>2ozmv6lYu&V!?K${Y4uj<0hdp<0hTGRGtlxUOb-i5d zHe1{e$hJAFRvch&<7x|BFJ1;OuUwfe+l{i_ zEiJFgEw8xO>NKlEjkOobAU{=4Ho6yE?bU^q#Mz_f+P_rgXU!|kGxa^3csX-x`<>_;xnBV*+TQ*3%DQ{T_;~tFxhfg1*`h zd#uR)0ppw->zz8Nxld!eK8*U#@8az|Xx|6#W>x;e%XbcY7uXv82FT}DuSqestz?a>xBc;DwxedWEQv+_JDuLSo3Sk7~Tdogj|%X7{55^B8u z?)w&gOY+g%aj?C0Mx(c{g5~3${?jxr&N>RN{*h+f8;Q&BbS!bbI}KIubR5oj{oVIl z*h+7B0_@rP#942G<(1%0g5~nF-b$Qjh2PtWb6#iZh;woZHK#d@(Z^o+9iB%0cI}0| z($@b^UfVf!E}hTl-5GHITu#8rNAJ#pedD;(Ik21(+*c<~rCI z`H1-rEUzm4F)MJ!m?vUZ!SbpSG4c0#4bHomTi