From 53bb3d63f07f88745d8d96596399b7ead856a247 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Mon, 15 Jan 2024 18:45:57 +0100 Subject: [PATCH] Code cleanup --- .../texturemipmapgen/texturemipmapgen.cpp | 167 ++++++++---------- 1 file changed, 71 insertions(+), 96 deletions(-) diff --git a/examples/texturemipmapgen/texturemipmapgen.cpp b/examples/texturemipmapgen/texturemipmapgen.cpp index 2691c4a6..0db6578c 100644 --- a/examples/texturemipmapgen/texturemipmapgen.cpp +++ b/examples/texturemipmapgen/texturemipmapgen.cpp @@ -1,5 +1,7 @@ /* * Vulkan Example - Runtime mip map generation +* +* This samples shows how to generate a full mip-chain from a top-level image and how different sampling modes compare * * Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de * @@ -15,34 +17,34 @@ class VulkanExample : public VulkanExampleBase { public: struct Texture { - VkImage image; - VkDeviceMemory deviceMemory; - VkImageView view; - uint32_t width, height; - uint32_t mipLevels; + VkImage image{ VK_NULL_HANDLE }; + VkDeviceMemory deviceMemory{ VK_NULL_HANDLE }; + VkImageView view{ VK_NULL_HANDLE }; + uint32_t width{ 0 }; + uint32_t height{ 0 }; + uint32_t mipLevels{ 0 }; } texture; // To demonstrate mip mapping and filtering this example uses separate samplers std::vector samplerNames{ "No mip maps" , "Mip maps (bilinear)" , "Mip maps (anisotropic)" }; - std::vector samplers; + std::vector samplers{}; vkglTF::Model model; - vks::Buffer uniformBufferVS; - - struct uboVS { + struct UniformData { glm::mat4 projection; glm::mat4 view; glm::mat4 model; glm::vec4 viewPos; float lodBias = 0.0f; int32_t samplerIndex = 2; - } uboVS; + } uniformData; + vks::Buffer uniformBuffer; - VkPipeline pipeline; - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; - VkDescriptorSetLayout descriptorSetLayout; + VkPipeline pipeline{ VK_NULL_HANDLE }; + VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE }; + VkDescriptorSet descriptorSet{ VK_NULL_HANDLE }; + VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE }; VulkanExample() : VulkanExampleBase() { @@ -58,14 +60,15 @@ public: ~VulkanExample() { - destroyTextureImage(texture); - vkDestroyPipeline(device, pipeline, nullptr); - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - uniformBufferVS.destroy(); - for (auto sampler : samplers) - { - vkDestroySampler(device, sampler, nullptr); + if (device) { + destroyTextureImage(texture); + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + uniformBuffer.destroy(); + for (auto sampler : samplers) { + vkDestroySampler(device, sampler, nullptr); + } } } @@ -76,7 +79,8 @@ public: } } - void loadTexture(std::string filename, VkFormat format, bool forceLinearTiling) + // Loads a full sized image from disk, generates a Vulkan image (texture) from it and creates a full mip chain using blits + void loadTextureAndGenerateMips(std::string filename, VkFormat format) { ktxResult result; ktxTexture* ktxTexture; @@ -300,8 +304,9 @@ public: vulkanDevice->flushCommandBuffer(blitCmd, queue, true); // --------------------------------------------------------------- - // Create samplers + // Create some samplers with different settings that can be selected via the UI samplers.resize(3); + VkSamplerCreateInfo sampler = vks::initializers::samplerCreateInfo(); sampler.magFilter = VK_FILTER_LINEAR; sampler.minFilter = VK_FILTER_LINEAR; @@ -372,7 +377,6 @@ public: for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) { - // Set target frame buffer renderPassBeginInfo.framebuffer = frameBuffers[i]; VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); @@ -398,80 +402,50 @@ public: } } - void draw() - { - VulkanExampleBase::prepareFrame(); - - // Command buffer to be submitted to the queue - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; - - // Submit to queue - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - - VulkanExampleBase::submitFrame(); - } - void loadAssets() { model.loadFromFile(getAssetPath() + "models/tunnel_cylinder.gltf", vulkanDevice, queue, vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::FlipY); - loadTexture(getAssetPath() + "textures/metalplate_nomips_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, false); + loadTextureAndGenerateMips(getAssetPath() + "textures/metalplate_nomips_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM); } - void setupDescriptorPool() + void setupDescriptors() { - std::vector poolSizes = - { - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), // Vertex shader UBO - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1), // Sampled image - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_SAMPLER, 3), // 3 samplers (array) + // Pool + std::vector poolSizes = { + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1), + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_SAMPLER, 3), }; - - VkDescriptorPoolCreateInfo descriptorPoolInfo = - vks::initializers::descriptorPoolCreateInfo( - static_cast(poolSizes.size()), - poolSizes.data(), - 1); - + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - void setupDescriptorSetLayout() - { + // Layout std::vector setLayoutBindings = { // Binding 0: Vertex shader uniform buffer vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0), // Binding 1: Sampled image vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT, 1), - // Binding 2: Sampler array (3 descriptors) + // Binding 2: Array with 3 samplers vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 2, 3), }; - VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - } - - void setupDescriptorSet() - { - VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout,1); + // Sets + VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); VkDescriptorImageInfo textureDescriptor = vks::initializers::descriptorImageInfo(VK_NULL_HANDLE, texture.view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); std::vector writeDescriptorSets = { - // Binding 0: Vertex shader uniform buffer - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBufferVS.descriptor), + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), // Binding 1: Sampled image vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, &textureDescriptor) }; - // Binding 2: Sampler array + // Binding 2: Contains an array of samplers that can be switched from the UI to demonstrate different filteirng modes std::vector samplerDescriptors; - for (auto i = 0; i < samplers.size(); i++) - { + for (auto i = 0; i < samplers.size(); i++) { samplerDescriptors.push_back(vks::initializers::descriptorImageInfo(samplers[i], VK_NULL_HANDLE, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); } VkWriteDescriptorSet samplerDescriptorWrite{}; @@ -483,11 +457,16 @@ public: samplerDescriptorWrite.dstBinding = 2; samplerDescriptorWrite.dstArrayElement = 0; writeDescriptorSets.push_back(samplerDescriptorWrite); - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } void preparePipelines() { + // Layout + VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, 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); @@ -519,26 +498,27 @@ public: // Prepare and initialize uniform buffer containing shader uniforms 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, - &uniformBufferVS, - sizeof(uboVS), - &uboVS)); - - updateUniformBuffers(); + 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), &uniformData)); + VK_CHECK_RESULT(uniformBuffer.map()); } void updateUniformBuffers() { - uboVS.projection = camera.matrices.perspective; - uboVS.view = camera.matrices.view; - uboVS.model = glm::rotate(glm::mat4(1.0f), glm::radians(timer * 360.0f), glm::vec3(1.0f, 0.0f, 0.0f)); - uboVS.viewPos = glm::vec4(camera.position, 0.0f) * glm::vec4(-1.0f); - VK_CHECK_RESULT(uniformBufferVS.map()); - memcpy(uniformBufferVS.mapped, &uboVS, sizeof(uboVS)); - uniformBufferVS.unmap(); + uniformData.projection = camera.matrices.perspective; + uniformData.view = camera.matrices.view; + // @todo: paused + uniformData.model = glm::rotate(glm::mat4(1.0f), glm::radians(timer * 360.0f), glm::vec3(1.0f, 0.0f, 0.0f)); + uniformData.viewPos = glm::vec4(camera.position, 0.0f) * glm::vec4(-1.0f); + memcpy(uniformBuffer.mapped, &uniformData, sizeof(uniformData)); + } + + void draw() + { + VulkanExampleBase::prepareFrame(); + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + VulkanExampleBase::submitFrame(); } void prepare() @@ -546,10 +526,8 @@ public: VulkanExampleBase::prepare(); loadAssets(); prepareUniformBuffers(); - setupDescriptorSetLayout(); + setupDescriptors(); preparePipelines(); - setupDescriptorPool(); - setupDescriptorSet(); buildCommandBuffers(); prepared = true; } @@ -558,20 +536,17 @@ public: { if (!prepared) return; + updateUniformBuffers(); draw(); - if (!paused || camera.updated) - { - updateUniformBuffers(); - } } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { - if (overlay->sliderFloat("LOD bias", &uboVS.lodBias, 0.0f, (float)texture.mipLevels)) { + if (overlay->sliderFloat("LOD bias", &uniformData.lodBias, 0.0f, (float)texture.mipLevels)) { updateUniformBuffers(); } - if (overlay->comboBox("Sampler type", &uboVS.samplerIndex, samplerNames)) { + if (overlay->comboBox("Sampler type", &uniformData.samplerIndex, samplerNames)) { updateUniformBuffers(); } }