From a546f466c19cbdd1df76ec8382880622532cb82e Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sun, 21 Jan 2024 12:52:14 +0100 Subject: [PATCH] Code cleanup --- .../computeparticles/computeparticles.cpp | 389 +++++------------- .../computeraytracing/computeraytracing.cpp | 1 - examples/parallaxmapping/parallaxmapping.cpp | 161 ++++---- 3 files changed, 180 insertions(+), 371 deletions(-) diff --git a/examples/computeparticles/computeparticles.cpp b/examples/computeparticles/computeparticles.cpp index 508724ea4..4b6d494c7 100644 --- a/examples/computeparticles/computeparticles.cpp +++ b/examples/computeparticles/computeparticles.cpp @@ -3,7 +3,7 @@ * * Updated compute shader by Lukas Bergdoll (https://github.com/Voultapher) * -* Copyright (C) 2016-2021 by Sascha Willems - www.saschawillems.de +* Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ @@ -29,14 +29,19 @@ class VulkanExample : public VulkanExampleBase vks::Texture2D gradient; } textures; - struct { - VkPipelineVertexInputStateCreateInfo inputState; - std::vector bindingDescriptions; - std::vector attributeDescriptions; - } vertices; + // SSBO particle declaration + struct Particle { + glm::vec2 pos; // Particle position + glm::vec2 vel; // Particle velocity + glm::vec4 gradientPos; // Texture coordinates for the gradient ramp map + }; + + // We use a shader storage buffer object to store the particlces + // This is updated by the compute pipeline and displayed as a vertex buffer by the graphics pipeline + vks::Buffer storageBuffer; // Resources for the graphics part of the example - struct { + struct Graphics { uint32_t queueFamilyIndex; // Used to check if compute and graphics queue families differ and require additional barriers VkDescriptorSetLayout descriptorSetLayout; // Particle system rendering shader binding layout VkDescriptorSet descriptorSet; // Particle system rendering shader bindings @@ -46,10 +51,8 @@ class VulkanExample : public VulkanExampleBase } graphics; // Resources for the compute part of the example - struct { + struct Compute { uint32_t queueFamilyIndex; // Used to check if compute and graphics queue families differ and require additional barriers - vks::Buffer storageBuffer; // (Shader) storage buffer object containing the particles - vks::Buffer uniformBuffer; // Uniform buffer object containing particle system parameters VkQueue queue; // Separate queue for compute commands (queue family may differ from the one used for graphics) VkCommandPool commandPool; // Use a separate command pool (queue family may differ from the one used for graphics) VkCommandBuffer commandBuffer; // Command buffer storing the dispatch commands and barriers @@ -58,21 +61,15 @@ class VulkanExample : public VulkanExampleBase VkDescriptorSet descriptorSet; // Compute shader bindings VkPipelineLayout pipelineLayout; // Layout of the compute pipeline VkPipeline pipeline; // Compute pipeline for updating particle positions - struct computeUBO { // Compute shader uniform block object + vks::Buffer uniformBuffer; // Uniform buffer object containing particle system parameters + struct UniformData { // Compute shader uniform block object float deltaT; // Frame delta time float destX; // x position of the attractor float destY; // y position of the attractor int32_t particleCount = PARTICLE_COUNT; - } ubo; + } uniformData; } compute; - // SSBO particle declaration - struct Particle { - glm::vec2 pos; // Particle position - glm::vec2 vel; // Particle velocity - glm::vec4 gradientPos; // Texture coordinates for the gradient ramp map - }; - VulkanExample() : VulkanExampleBase() { title = "Compute shader particle system"; @@ -80,23 +77,25 @@ class VulkanExample : public VulkanExampleBase ~VulkanExample() { - // Graphics - vkDestroyPipeline(device, graphics.pipeline, nullptr); - vkDestroyPipelineLayout(device, graphics.pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, graphics.descriptorSetLayout, nullptr); - vkDestroySemaphore(device, graphics.semaphore, nullptr); - - // Compute - compute.storageBuffer.destroy(); - compute.uniformBuffer.destroy(); - vkDestroyPipelineLayout(device, compute.pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, compute.descriptorSetLayout, nullptr); - vkDestroyPipeline(device, compute.pipeline, nullptr); - vkDestroySemaphore(device, compute.semaphore, nullptr); - vkDestroyCommandPool(device, compute.commandPool, nullptr); - - textures.particle.destroy(); - textures.gradient.destroy(); + if (device) { + // Graphics + vkDestroyPipeline(device, graphics.pipeline, nullptr); + vkDestroyPipelineLayout(device, graphics.pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, graphics.descriptorSetLayout, nullptr); + vkDestroySemaphore(device, graphics.semaphore, nullptr); + + // Compute + compute.uniformBuffer.destroy(); + vkDestroyPipelineLayout(device, compute.pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, compute.descriptorSetLayout, nullptr); + vkDestroyPipeline(device, compute.pipeline, nullptr); + vkDestroySemaphore(device, compute.semaphore, nullptr); + vkDestroyCommandPool(device, compute.commandPool, nullptr); + + storageBuffer.destroy(); + textures.particle.destroy(); + textures.gradient.destroy(); + } } void loadAssets() @@ -140,9 +139,9 @@ class VulkanExample : public VulkanExampleBase VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, compute.queueFamilyIndex, graphics.queueFamilyIndex, - compute.storageBuffer.buffer, + storageBuffer.buffer, 0, - compute.storageBuffer.size + storageBuffer.size }; vkCmdPipelineBarrier( @@ -168,7 +167,7 @@ class VulkanExample : public VulkanExampleBase vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphics.pipelineLayout, 0, 1, &graphics.descriptorSet, 0, NULL); VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &compute.storageBuffer.buffer, offsets); + vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &storageBuffer.buffer, offsets); vkCmdDraw(drawCmdBuffers[i], PARTICLE_COUNT, 1, 0, 0); drawUI(drawCmdBuffers[i]); @@ -186,9 +185,9 @@ class VulkanExample : public VulkanExampleBase 0, graphics.queueFamilyIndex, compute.queueFamilyIndex, - compute.storageBuffer.buffer, + storageBuffer.buffer, 0, - compute.storageBuffer.size + storageBuffer.size }; vkCmdPipelineBarrier( @@ -225,9 +224,9 @@ class VulkanExample : public VulkanExampleBase VK_ACCESS_SHADER_WRITE_BIT, graphics.queueFamilyIndex, compute.queueFamilyIndex, - compute.storageBuffer.buffer, + storageBuffer.buffer, 0, - compute.storageBuffer.size + storageBuffer.size }; vkCmdPipelineBarrier( @@ -257,9 +256,9 @@ class VulkanExample : public VulkanExampleBase 0, compute.queueFamilyIndex, graphics.queueFamilyIndex, - compute.storageBuffer.buffer, + storageBuffer.buffer, 0, - compute.storageBuffer.size + storageBuffer.size }; vkCmdPipelineBarrier( @@ -307,14 +306,14 @@ class VulkanExample : public VulkanExampleBase // The SSBO will be used as a storage buffer for the compute pipeline and as a vertex buffer in the graphics pipeline VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - &compute.storageBuffer, + &storageBuffer, storageBufferSize); // Copy from staging buffer to storage buffer VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); VkBufferCopy copyRegion = {}; copyRegion.size = storageBufferSize; - vkCmdCopyBuffer(copyCmd, stagingBuffer.buffer, compute.storageBuffer.buffer, 1, ©Region); + vkCmdCopyBuffer(copyCmd, stagingBuffer.buffer, storageBuffer.buffer, 1, ©Region); // Execute a transfer barrier to the compute queue, if necessary if (graphics.queueFamilyIndex != compute.queueFamilyIndex) { @@ -326,9 +325,9 @@ class VulkanExample : public VulkanExampleBase 0, graphics.queueFamilyIndex, compute.queueFamilyIndex, - compute.storageBuffer.buffer, + storageBuffer.buffer, 0, - compute.storageBuffer.size + storageBuffer.size }; vkCmdPipelineBarrier( @@ -343,96 +342,37 @@ class VulkanExample : public VulkanExampleBase vulkanDevice->flushCommandBuffer(copyCmd, queue, true); stagingBuffer.destroy(); - - // Binding description - vertices.bindingDescriptions.resize(1); - vertices.bindingDescriptions[0] = - vks::initializers::vertexInputBindingDescription( - 0, - sizeof(Particle), - VK_VERTEX_INPUT_RATE_VERTEX); - - // Attribute descriptions - // Describes memory layout and shader positions - vertices.attributeDescriptions.resize(2); - // Location 0 : Position - vertices.attributeDescriptions[0] = - vks::initializers::vertexInputAttributeDescription( - 0, - 0, - VK_FORMAT_R32G32_SFLOAT, - offsetof(Particle, pos)); - // Location 1 : Gradient position - vertices.attributeDescriptions[1] = - vks::initializers::vertexInputAttributeDescription( - 0, - 1, - VK_FORMAT_R32G32B32A32_SFLOAT, - offsetof(Particle, gradientPos)); - - // Assign to vertex buffer - vertices.inputState = vks::initializers::pipelineVertexInputStateCreateInfo(); - vertices.inputState.vertexBindingDescriptionCount = static_cast(vertices.bindingDescriptions.size()); - vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data(); - vertices.inputState.vertexAttributeDescriptionCount = static_cast(vertices.attributeDescriptions.size()); - vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data(); } + // The descriptor pool will be shared between graphics and compute void setupDescriptorPool() { - std::vector poolSizes = - { + std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2) }; - - VkDescriptorPoolCreateInfo descriptorPoolInfo = - vks::initializers::descriptorPoolCreateInfo( - static_cast(poolSizes.size()), - poolSizes.data(), - 2); - + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); } - void setupDescriptorSetLayout() + void prepareGraphics() { - std::vector setLayoutBindings; - // Binding 0 : Particle color map - setLayoutBindings.push_back(vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - VK_SHADER_STAGE_FRAGMENT_BIT, - 0)); - // Binding 1 : Particle gradient ramp - setLayoutBindings.push_back(vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - VK_SHADER_STAGE_FRAGMENT_BIT, - 1)); - - VkDescriptorSetLayoutCreateInfo descriptorLayout = - vks::initializers::descriptorSetLayoutCreateInfo( - setLayoutBindings.data(), - static_cast(setLayoutBindings.size())); + prepareStorageBuffers(); + prepareUniformBuffers(); + // Descriptor set layout + std::vector setLayoutBindings = { + // Binding 0 : Particle color map + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0), + // Binding 1 : Particle gradient ramp + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1) + }; + VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &graphics.descriptorSetLayout)); - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo( - &graphics.descriptorSetLayout, - 1); - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &graphics.pipelineLayout)); - } - - void setupDescriptorSet() - { - VkDescriptorSetAllocateInfo allocInfo = - vks::initializers::descriptorSetAllocateInfo( - descriptorPool, - &graphics.descriptorSetLayout, - 1); - + // Descriptor set + VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &graphics.descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &graphics.descriptorSet)); std::vector writeDescriptorSets; @@ -450,71 +390,44 @@ class VulkanExample : public VulkanExampleBase &textures.gradient.descriptor)); vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); - } - void preparePipelines() - { - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = - vks::initializers::pipelineInputAssemblyStateCreateInfo( - VK_PRIMITIVE_TOPOLOGY_POINT_LIST, - 0, - VK_FALSE); - - VkPipelineRasterizationStateCreateInfo rasterizationState = - vks::initializers::pipelineRasterizationStateCreateInfo( - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_NONE, - VK_FRONT_FACE_COUNTER_CLOCKWISE, - 0); - - VkPipelineColorBlendAttachmentState blendAttachmentState = - vks::initializers::pipelineColorBlendAttachmentState( - 0xf, - VK_FALSE); - - VkPipelineColorBlendStateCreateInfo colorBlendState = - vks::initializers::pipelineColorBlendStateCreateInfo( - 1, - &blendAttachmentState); - - VkPipelineDepthStencilStateCreateInfo depthStencilState = - vks::initializers::pipelineDepthStencilStateCreateInfo( - VK_FALSE, - VK_FALSE, - VK_COMPARE_OP_ALWAYS); - - VkPipelineViewportStateCreateInfo viewportState = - vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); - - VkPipelineMultisampleStateCreateInfo multisampleState = - vks::initializers::pipelineMultisampleStateCreateInfo( - VK_SAMPLE_COUNT_1_BIT, - 0); + // Pipeline layout + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&graphics.descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &graphics.pipelineLayout)); - std::vector dynamicStateEnables = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR + // Pipeline + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0, VK_FALSE); + VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0); + VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); + VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); + VkPipelineDepthStencilStateCreateInfo depthStencilState = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_FALSE, VK_FALSE, VK_COMPARE_OP_ALWAYS); + VkPipelineViewportStateCreateInfo viewportState = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); + VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0); + std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); + std::array shaderStages; + + // Vertex Input state + std::vector inputBindings = { + vks::initializers::vertexInputBindingDescription(0, sizeof(Particle), VK_VERTEX_INPUT_RATE_VERTEX) }; - VkPipelineDynamicStateCreateInfo dynamicState = - vks::initializers::pipelineDynamicStateCreateInfo( - dynamicStateEnables.data(), - static_cast(dynamicStateEnables.size()), - 0); - - // Rendering pipeline - // Load shaders - std::array shaderStages; + std::vector inputAttributes = { + // Location 0 : Position + vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Particle, pos)), + // Location 1 : Velocity (used for color gradient lookup) + vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Particle, gradientPos)), + }; + VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); + vertexInputState.vertexBindingDescriptionCount = static_cast(inputBindings.size()); + vertexInputState.pVertexBindingDescriptions = inputBindings.data(); + vertexInputState.vertexAttributeDescriptionCount = static_cast(inputAttributes.size()); + vertexInputState.pVertexAttributeDescriptions = inputAttributes.data(); shaderStages[0] = loadShader(getShadersPath() + "computeparticles/particle.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[1] = loadShader(getShadersPath() + "computeparticles/particle.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - VkGraphicsPipelineCreateInfo pipelineCreateInfo = - vks::initializers::pipelineCreateInfo( - graphics.pipelineLayout, - renderPass, - 0); - - pipelineCreateInfo.pVertexInputState = &vertices.inputState; + VkGraphicsPipelineCreateInfo pipelineCreateInfo = vks::initializers::pipelineCreateInfo(graphics.pipelineLayout, renderPass, 0); + pipelineCreateInfo.pVertexInputState = &vertexInputState; pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCreateInfo.pColorBlendState = &colorBlendState; @@ -537,15 +450,6 @@ class VulkanExample : public VulkanExampleBase blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_DST_ALPHA; VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &graphics.pipeline)); - } - - void prepareGraphics() - { - prepareStorageBuffers(); - prepareUniformBuffers(); - setupDescriptorSetLayout(); - preparePipelines(); - setupDescriptorSet(); // Semaphore for compute & graphics sync VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); @@ -582,37 +486,18 @@ class VulkanExample : public VulkanExampleBase VK_SHADER_STAGE_COMPUTE_BIT, 1), }; - - VkDescriptorSetLayoutCreateInfo descriptorLayout = - vks::initializers::descriptorSetLayoutCreateInfo( - setLayoutBindings.data(), - static_cast(setLayoutBindings.size())); - + VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &compute.descriptorSetLayout)); - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo( - &compute.descriptorSetLayout, - 1); - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &compute.pipelineLayout)); - - VkDescriptorSetAllocateInfo allocInfo = - vks::initializers::descriptorSetAllocateInfo( - descriptorPool, - &compute.descriptorSetLayout, - 1); - + VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &compute.descriptorSetLayout,1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &compute.descriptorSet)); - - std::vector computeWriteDescriptorSets = - { + std::vector computeWriteDescriptorSets = { // Binding 0 : Particle position storage buffer vks::initializers::writeDescriptorSet( compute.descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, - &compute.storageBuffer.descriptor), + &storageBuffer.descriptor), // Binding 1 : Uniform buffer vks::initializers::writeDescriptorSet( compute.descriptorSet, @@ -620,10 +505,11 @@ class VulkanExample : public VulkanExampleBase 1, &compute.uniformBuffer.descriptor) }; - vkUpdateDescriptorSets(device, static_cast(computeWriteDescriptorSets.size()), computeWriteDescriptorSets.data(), 0, NULL); // Create pipeline + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&compute.descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &compute.pipelineLayout)); VkComputePipelineCreateInfo computePipelineCreateInfo = vks::initializers::computePipelineCreateInfo(compute.pipelineLayout, 0); computePipelineCreateInfo.stage = loadShader(getShadersPath() + "computeparticles/particle.comp.spv", VK_SHADER_STAGE_COMPUTE_BIT); VK_CHECK_RESULT(vkCreateComputePipelines(device, pipelineCache, 1, &computePipelineCreateInfo, nullptr, &compute.pipeline)); @@ -644,72 +530,13 @@ class VulkanExample : public VulkanExampleBase // Build a single command buffer containing the compute dispatch commands buildComputeCommandBuffer(); - - // SRS - By reordering compute and graphics within draw(), the following code is no longer needed: - // If graphics and compute queue family indices differ, acquire and immediately release the storage buffer, so that the initial acquire from the graphics command buffers are matched up properly - /* - if (graphics.queueFamilyIndex != compute.queueFamilyIndex) - { - // Create a transient command buffer for setting up the initial buffer transfer state - VkCommandBuffer transferCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, compute.commandPool, true); - - VkBufferMemoryBarrier acquire_buffer_barrier = - { - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, - nullptr, - 0, - VK_ACCESS_SHADER_WRITE_BIT, - graphics.queueFamilyIndex, - compute.queueFamilyIndex, - compute.storageBuffer.buffer, - 0, - compute.storageBuffer.size - }; - vkCmdPipelineBarrier( - transferCmd, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - 0, - 0, nullptr, - 1, &acquire_buffer_barrier, - 0, nullptr); - - VkBufferMemoryBarrier release_buffer_barrier = - { - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, - nullptr, - VK_ACCESS_SHADER_WRITE_BIT, - 0, - compute.queueFamilyIndex, - graphics.queueFamilyIndex, - compute.storageBuffer.buffer, - 0, - compute.storageBuffer.size - }; - vkCmdPipelineBarrier( - transferCmd, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, - 0, - 0, nullptr, - 1, &release_buffer_barrier, - 0, nullptr); - - vulkanDevice->flushCommandBuffer(transferCmd, compute.queue, compute.commandPool); - } - */ } // Prepare and initialize uniform buffer containing shader uniforms void prepareUniformBuffers() { // Compute shader uniform buffer block - vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &compute.uniformBuffer, - sizeof(compute.ubo)); - + vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &compute.uniformBuffer, sizeof(Compute::UniformData)); // Map for host access VK_CHECK_RESULT(compute.uniformBuffer.map()); @@ -718,21 +545,21 @@ class VulkanExample : public VulkanExampleBase void updateUniformBuffers() { - compute.ubo.deltaT = paused ? 0.0f : frameTimer * 2.5f; + compute.uniformData.deltaT = paused ? 0.0f : frameTimer * 2.5f; if (!attachToCursor) { - compute.ubo.destX = sin(glm::radians(timer * 360.0f)) * 0.75f; - compute.ubo.destY = 0.0f; + compute.uniformData.destX = sin(glm::radians(timer * 360.0f)) * 0.75f; + compute.uniformData.destY = 0.0f; } else { float normalizedMx = (mousePos.x - static_cast(width / 2)) / static_cast(width / 2); float normalizedMy = (mousePos.y - static_cast(height / 2)) / static_cast(height / 2); - compute.ubo.destX = normalizedMx; - compute.ubo.destY = normalizedMy; + compute.uniformData.destX = normalizedMx; + compute.uniformData.destY = normalizedMy; } - memcpy(compute.uniformBuffer.mapped, &compute.ubo, sizeof(compute.ubo)); + memcpy(compute.uniformBuffer.mapped, &compute.uniformData, sizeof(Compute::UniformData)); } void draw() diff --git a/examples/computeraytracing/computeraytracing.cpp b/examples/computeraytracing/computeraytracing.cpp index 0fe99e815..04f0caaef 100644 --- a/examples/computeraytracing/computeraytracing.cpp +++ b/examples/computeraytracing/computeraytracing.cpp @@ -434,7 +434,6 @@ class VulkanExample : public VulkanExampleBase // The descriptor pool will be shared between graphics and compute void setupDescriptorPool() { - // @todo: probably wrong std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4), diff --git a/examples/parallaxmapping/parallaxmapping.cpp b/examples/parallaxmapping/parallaxmapping.cpp index a9806ff0a..6875ea853 100644 --- a/examples/parallaxmapping/parallaxmapping.cpp +++ b/examples/parallaxmapping/parallaxmapping.cpp @@ -20,37 +20,33 @@ class VulkanExample : public VulkanExampleBase vkglTF::Model plane; + struct UniformDataVertexShader { + glm::mat4 projection; + glm::mat4 view; + glm::mat4 model; + glm::vec4 lightPos = glm::vec4(0.0f, -2.0f, 0.0f, 1.0f); + glm::vec4 cameraPos; + } uniformDataVertexShader; + + struct UniformDataFragmentShader { + float heightScale = 0.1f; + // Basic parallax mapping needs a bias to look any good (and is hard to tweak) + float parallaxBias = -0.02f; + // Number of layers for steep parallax and parallax occlusion (more layer = better result for less performance) + float numLayers = 48.0f; + // (Parallax) mapping mode to use + int32_t mappingMode = 4; + } uniformDataFragmentShader; + struct { vks::Buffer vertexShader; vks::Buffer fragmentShader; } uniformBuffers; - struct { - - struct { - glm::mat4 projection; - glm::mat4 view; - glm::mat4 model; - glm::vec4 lightPos = glm::vec4(0.0f, -2.0f, 0.0f, 1.0f); - glm::vec4 cameraPos; - } vertexShader; - - struct { - float heightScale = 0.1f; - // Basic parallax mapping needs a bias to look any good (and is hard to tweak) - float parallaxBias = -0.02f; - // Number of layers for steep parallax and parallax occlusion (more layer = better result for less performance) - float numLayers = 48.0f; - // (Parallax) mapping mode to use - int32_t mappingMode = 4; - } fragmentShader; - - } ubos; - - VkPipelineLayout pipelineLayout; - VkPipeline pipeline; - VkDescriptorSetLayout descriptorSetLayout; - VkDescriptorSet descriptorSet; + VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE }; + VkPipeline pipeline{ VK_NULL_HANDLE }; + VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE }; + VkDescriptorSet descriptorSet{ VK_NULL_HANDLE }; const std::vector mappingModes = { "Color only", @@ -72,16 +68,15 @@ class VulkanExample : public VulkanExampleBase ~VulkanExample() { - vkDestroyPipeline(device, pipeline, nullptr); - - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - - uniformBuffers.vertexShader.destroy(); - uniformBuffers.fragmentShader.destroy(); - - textures.colorMap.destroy(); - textures.normalHeightMap.destroy(); + if (device) { + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + uniformBuffers.vertexShader.destroy(); + uniformBuffers.fragmentShader.destroy(); + textures.colorMap.destroy(); + textures.normalHeightMap.destroy(); + } } void loadAssets() @@ -136,52 +131,53 @@ class VulkanExample : public VulkanExampleBase } } - void setupDescriptorPool() + void setupDescriptors() { - // Example uses two ubos and two image sampler - std::vector poolSizes = - { + // Pool + std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2) }; - - VkDescriptorPoolCreateInfo descriptorPoolInfo = - vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); - + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - void setupDescriptorSetLayout() - { + // Layout std::vector setLayoutBindings = { - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), // Binding 0: Vertex shader uniform buffer - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1), // Binding 1: Fragment shader color map image sampler - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 2), // Binding 2: Fragment combined normal and heightmap - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 3), // Binding 3: Fragment shader uniform buffer + // Binding 0: Vertex shader uniform buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), + // Binding 1: Fragment shader color map image sampler + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1), + // Binding 2: Fragment combined normal and heightmap + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 2), + // Binding 3: Fragment shader uniform buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 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() - { + // Set VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); - std::vector writeDescriptorSets = { - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.vertexShader.descriptor), // Binding 0: Vertex shader uniform buffer - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textures.colorMap.descriptor), // Binding 1: Fragment shader image sampler - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, &textures.normalHeightMap.descriptor), // Binding 2: Combined normal and heightmap - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3, &uniformBuffers.fragmentShader.descriptor), // Binding 3: Fragment shader uniform buffer + // Binding 0: Vertex shader uniform buffer + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.vertexShader.descriptor), + // Binding 1: Fragment shader image sampler + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textures.colorMap.descriptor), + // Binding 2: Combined normal and heightmap + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, &textures.normalHeightMap.descriptor), + // Binding 3: Fragment shader uniform buffer + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3, &uniformBuffers.fragmentShader.descriptor), }; vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); } void preparePipelines() { + // Layout + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + 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_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE); VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); @@ -214,43 +210,33 @@ class VulkanExample : public VulkanExampleBase void prepareUniformBuffers() { // 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.vertexShader, - sizeof(ubos.vertexShader))); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffers.vertexShader, sizeof(UniformDataVertexShader))); // Fragment 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.fragmentShader, - sizeof(ubos.fragmentShader))); - + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffers.fragmentShader, sizeof(UniformDataFragmentShader))); // Map persistent VK_CHECK_RESULT(uniformBuffers.vertexShader.map()); VK_CHECK_RESULT(uniformBuffers.fragmentShader.map()); - updateUniformBuffers(); } void updateUniformBuffers() { // Vertex shader - ubos.vertexShader.projection = camera.matrices.perspective; - ubos.vertexShader.view = camera.matrices.view; - ubos.vertexShader.model = glm::scale(glm::mat4(1.0f), glm::vec3(0.2f)); + uniformDataVertexShader.projection = camera.matrices.perspective; + uniformDataVertexShader.view = camera.matrices.view; + uniformDataVertexShader.model = glm::scale(glm::mat4(1.0f), glm::vec3(0.2f)); if (!paused) { - ubos.vertexShader.lightPos.x = sin(glm::radians(timer * 360.0f)) * 1.5f; - ubos.vertexShader.lightPos.z = cos(glm::radians(timer * 360.0f)) * 1.5f; + uniformDataVertexShader.lightPos.x = sin(glm::radians(timer * 360.0f)) * 1.5f; + uniformDataVertexShader.lightPos.z = cos(glm::radians(timer * 360.0f)) * 1.5f; } - ubos.vertexShader.cameraPos = glm::vec4(camera.position, -1.0f) * -1.0f; - memcpy(uniformBuffers.vertexShader.mapped, &ubos.vertexShader, sizeof(ubos.vertexShader)); + uniformDataVertexShader.cameraPos = glm::vec4(camera.position, -1.0f) * -1.0f; + memcpy(uniformBuffers.vertexShader.mapped, &uniformDataVertexShader, sizeof(UniformDataVertexShader)); // Fragment shader - memcpy(uniformBuffers.fragmentShader.mapped, &ubos.fragmentShader, sizeof(ubos.fragmentShader)); + memcpy(uniformBuffers.fragmentShader.mapped, &uniformDataFragmentShader, sizeof(UniformDataFragmentShader)); } void draw() @@ -267,10 +253,8 @@ class VulkanExample : public VulkanExampleBase VulkanExampleBase::prepare(); loadAssets(); prepareUniformBuffers(); - setupDescriptorSetLayout(); + setupDescriptors(); preparePipelines(); - setupDescriptorPool(); - setupDescriptorSet(); buildCommandBuffers(); prepared = true; } @@ -279,17 +263,16 @@ class VulkanExample : public VulkanExampleBase { if (!prepared) return; - draw(); - if (!paused || camera.updated) - { + if (!paused || camera.updated) { updateUniformBuffers(); } + draw(); } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { - if (overlay->comboBox("Mode", &ubos.fragmentShader.mappingMode, mappingModes)) { + if (overlay->comboBox("Mode", &uniformDataFragmentShader.mappingMode, mappingModes)) { updateUniformBuffers(); } }