diff --git a/data/shaders/glsl/oit/geometry.frag b/data/shaders/glsl/oit/geometry.frag index a8fff040..9a582043 100644 --- a/data/shaders/glsl/oit/geometry.frag +++ b/data/shaders/glsl/oit/geometry.frag @@ -11,25 +11,24 @@ struct Node uint next; }; -layout (set = 0, binding = 1) uniform ObjectUBO -{ - mat4 model; - vec4 color; -} objectUBO; - -layout (set = 0, binding = 2) buffer GeometrySBO +layout (set = 0, binding = 1) buffer GeometrySBO { uint count; uint maxNodeCount; }; -layout (set = 0, binding = 3, r32ui) uniform uimage2D headIndexImage; +layout (set = 0, binding = 2, r32ui) uniform uimage2D headIndexImage; -layout (set = 0, binding = 4) buffer LinkedListSBO +layout (set = 0, binding = 3) buffer LinkedListSBO { Node nodes[]; }; +layout(push_constant) uniform PushConsts { + mat4 model; + vec4 color; +} pushConsts; + void main() { // Increase the node count @@ -42,7 +41,7 @@ void main() uint prevHeadIdx = imageAtomicExchange(headIndexImage, ivec2(gl_FragCoord.xy), nodeIdx); // Store node data - nodes[nodeIdx].color = objectUBO.color; + nodes[nodeIdx].color = pushConsts.color; nodes[nodeIdx].depth = gl_FragCoord.z; nodes[nodeIdx].next = prevHeadIdx; } diff --git a/data/shaders/glsl/oit/geometry.frag.spv b/data/shaders/glsl/oit/geometry.frag.spv index ddc2d691..f7563e99 100644 Binary files a/data/shaders/glsl/oit/geometry.frag.spv and b/data/shaders/glsl/oit/geometry.frag.spv differ diff --git a/data/shaders/glsl/oit/geometry.vert b/data/shaders/glsl/oit/geometry.vert index 4ed12046..e53b0c75 100644 --- a/data/shaders/glsl/oit/geometry.vert +++ b/data/shaders/glsl/oit/geometry.vert @@ -8,14 +8,13 @@ layout (set = 0, binding = 0) uniform RenderPassUBO mat4 view; } renderPassUBO; -layout (set = 0, binding = 1) uniform ObjectUBO -{ - mat4 model; +layout(push_constant) uniform PushConsts { + mat4 model; vec4 color; -} objectUBO; +} pushConsts; void main() { - mat4 PVM = renderPassUBO.projection * renderPassUBO.view * objectUBO.model; + mat4 PVM = renderPassUBO.projection * renderPassUBO.view * pushConsts.model; gl_Position = PVM * vec4(inPos, 1.0); } diff --git a/data/shaders/glsl/oit/geometry.vert.spv b/data/shaders/glsl/oit/geometry.vert.spv index a7d75996..1784d170 100644 Binary files a/data/shaders/glsl/oit/geometry.vert.spv and b/data/shaders/glsl/oit/geometry.vert.spv differ diff --git a/data/shaders/hlsl/oit/geometry.frag b/data/shaders/hlsl/oit/geometry.frag index 296fd37d..a6aee44d 100644 --- a/data/shaders/hlsl/oit/geometry.frag +++ b/data/shaders/hlsl/oit/geometry.frag @@ -14,25 +14,23 @@ struct Node uint next; }; -struct ObjectUBO -{ - float4x4 model; - float4 color; -}; - -cbuffer ubo : register(b1) { ObjectUBO objectUBO; } - struct GeometrySBO { uint count; uint maxNodeCount; }; // Binding 0 : Position storage buffer -RWStructuredBuffer geometrySBO : register(u2); +RWStructuredBuffer geometrySBO : register(u1); -RWTexture2D headIndexImage : register(u3); +RWTexture2D headIndexImage : register(u2); -RWStructuredBuffer nodes : register(u4); +RWStructuredBuffer nodes : register(u3); + +struct PushConsts { + float4x4 model; + float4 color; +}; +[[vk::push_constant]] PushConsts pushConsts; [earlydepthstencil] void main(VSOutput input) @@ -49,7 +47,7 @@ void main(VSOutput input) InterlockedExchange(headIndexImage[uint2(input.Pos.xy)], nodeIdx, prevHeadIdx); // Store node data - nodes[nodeIdx].color = objectUBO.color; + nodes[nodeIdx].color = pushConsts.color; nodes[nodeIdx].depth = input.Pos.z; nodes[nodeIdx].next = prevHeadIdx; } diff --git a/data/shaders/hlsl/oit/geometry.frag.spv b/data/shaders/hlsl/oit/geometry.frag.spv index 3fd22787..01fd554d 100644 Binary files a/data/shaders/hlsl/oit/geometry.frag.spv and b/data/shaders/hlsl/oit/geometry.frag.spv differ diff --git a/data/shaders/hlsl/oit/geometry.vert b/data/shaders/hlsl/oit/geometry.vert index f4b5c940..c1d114f3 100644 --- a/data/shaders/hlsl/oit/geometry.vert +++ b/data/shaders/hlsl/oit/geometry.vert @@ -13,13 +13,11 @@ struct RenderPassUBO cbuffer renderPassUBO : register(b0) { RenderPassUBO renderPassUBO; } -struct ObjectUBO -{ - float4x4 model; - float4 color; +struct PushConsts { + float4x4 model; + float4 color; }; - -cbuffer objectUBO : register(b1) { ObjectUBO objectUBO; } +[[vk::push_constant]] PushConsts pushConsts; struct VSOutput { @@ -29,6 +27,6 @@ struct VSOutput VSOutput main(VSInput input) { VSOutput output = (VSOutput)0; - output.Pos = mul(renderPassUBO.projection, mul(renderPassUBO.view, mul(objectUBO.model, input.Pos))); + output.Pos = mul(renderPassUBO.projection, mul(renderPassUBO.view, mul(pushConsts.model, input.Pos))); return output; } diff --git a/data/shaders/hlsl/oit/geometry.vert.spv b/data/shaders/hlsl/oit/geometry.vert.spv index 9ff7f93a..d7b08261 100644 Binary files a/data/shaders/hlsl/oit/geometry.vert.spv and b/data/shaders/hlsl/oit/geometry.vert.spv differ diff --git a/examples/oit/oit.cpp b/examples/oit/oit.cpp index 8fcb6fc5..98641deb 100644 --- a/examples/oit/oit.cpp +++ b/examples/oit/oit.cpp @@ -13,8 +13,6 @@ #include "VulkanglTFModel.h" #define ENABLE_VALIDATION false -#define SPHERE_COUNT 5 * 5 * 5 -#define CUBE_COUNT 2 #define NODE_COUNT 20 class VulkanExample : public VulkanExampleBase @@ -27,7 +25,6 @@ public: struct { vks::Buffer renderPass; - vks::Buffer objects; } uniformBuffers; struct Node { @@ -54,10 +51,10 @@ public: glm::mat4 view; } renderPassUBO; - struct { + struct ObjectData { glm::mat4 model; glm::vec4 color; - } objectUBO; + }; struct { VkDescriptorSetLayout geometry; @@ -103,7 +100,6 @@ public: destroyGeometryPass(); uniformBuffers.renderPass.destroy(); - uniformBuffers.objects.destroy(); } void getEnabledFeatures() override @@ -171,49 +167,6 @@ private: sizeof(renderPassUBO))); VK_CHECK_RESULT(uniformBuffers.renderPass.map()); - - // This example has many object and the information of objects will be stored in one buffer. - // This buffer will be used for the uniform buffer dynamic. - // So we need to calculate a object uniform buffer size based on minUniformBufferOffsetAlignment. - objectUniformBufferSize = - (sizeof(objectUBO) + deviceProperties.limits.minUniformBufferOffsetAlignment) & ~(deviceProperties.limits.minUniformBufferOffsetAlignment - 1); - - // Create an uniform buffer for objects. - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBuffers.objects, - objectUniformBufferSize * (SPHERE_COUNT + CUBE_COUNT))); - - VK_CHECK_RESULT(uniformBuffers.objects.map()); - - // Set up the scene. - uint8_t* objectUniformBufferData = static_cast(uniformBuffers.objects.mapped); - assert(SPHERE_COUNT == 5 * 5 * 5); - for (int i = 0; i != 5; i++) - { - for (int j = 0; j != 5; j++) - { - for (int k = 0; k != 5; k++) - { - auto T = glm::translate(glm::mat4(1.0f), glm::vec3(i - 2, j - 2, k - 2)); - auto S = glm::scale(glm::mat4(1.0f), glm::vec3(0.3f)); - objectUBO.model = T * S; - objectUBO.color = glm::vec4(1.0f, 0.0f, 0.0f, 0.5f); - memcpy(objectUniformBufferData, &objectUBO, sizeof(objectUBO)); - objectUniformBufferData += objectUniformBufferSize; - } - } - } - for (auto i = 0; i != CUBE_COUNT; ++i) - { - auto T = glm::translate(glm::mat4(1.0f), glm::vec3(3.0f * i - 1.5f, 0.0f, 0.0f)); - auto S = glm::scale(glm::mat4(1.0f), glm::vec3(0.2f)); - objectUBO.model = T * S; - objectUBO.color = glm::vec4(0.0f, 0.0f, 1.0f, 0.5f); - memcpy(objectUniformBufferData, &objectUBO, sizeof(objectUBO)); - objectUniformBufferData += objectUniformBufferSize; - } } void prepareGeometryPass() @@ -222,14 +175,14 @@ private: subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; // Geometry render pass doesn't need any output attachment. - auto renderPassInfo = vks::initializers::renderPassCreateInfo(); + VkRenderPassCreateInfo renderPassInfo = vks::initializers::renderPassCreateInfo(); renderPassInfo.attachmentCount = 0; renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpassDescription; VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassInfo, nullptr, &geometryPass.renderPass)); - // Geometry framebuffer doesn't need any output attachment. + // Geometry frame buffer doesn't need any output attachment. VkFramebufferCreateInfo fbufCreateInfo = vks::initializers::framebufferCreateInfo(); fbufCreateInfo.renderPass = geometryPass.renderPass; fbufCreateInfo.attachmentCount = 0; @@ -314,8 +267,8 @@ private: VK_CHECK_RESULT(geometryPass.linkedList.map()); - // Change HeadInex image's layout from UNDEFINED to GENERAL - auto cmdBufAllocInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); + // Change HeadIndex image's layout from UNDEFINED to GENERAL + VkCommandBufferAllocateInfo cmdBufAllocInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); VkCommandBuffer cmdBuf; VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocInfo, &cmdBuf)); @@ -323,7 +276,7 @@ private: VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuf, &cmdBufInfo)); - auto barrier = vks::initializers::imageMemoryBarrier(); + VkImageMemoryBarrier barrier = vks::initializers::imageMemoryBarrier(); barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; @@ -336,7 +289,7 @@ private: VK_CHECK_RESULT(vkEndCommandBuffer(cmdBuf)); - auto submitInfo = vks::initializers::submitInfo(); + VkSubmitInfo submitInfo = vks::initializers::submitInfo(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cmdBuf; @@ -353,37 +306,33 @@ private: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0), - // ObjectUBO - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - 1), // AtomicSBO vks::initializers::descriptorSetLayoutBinding( VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, - 2), + 1), // headIndexImage vks::initializers::descriptorSetLayoutBinding( VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT, - 3), + 2), // LinkedListSBO vks::initializers::descriptorSetLayoutBinding( VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, - 4), + 3), }; - auto descriptorLayoutCreateInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); - - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCreateInfo, nullptr, &descriptorSetLayouts.geometry)); + VkDescriptorSetLayoutCreateInfo descriptorLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayouts.geometry)); // Create a geometry pipeline layout. - auto pipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.geometry, 1); - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.geometry)); + VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.geometry, 1); + // Static object data passed using push constants + VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(ObjectData), 0); + pipelineLayoutCI.pushConstantRangeCount = 1; + pipelineLayoutCI.pPushConstantRanges = &pushConstantRange; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayouts.geometry)); // Create a color descriptor set layout. setLayoutBindings = { @@ -399,15 +348,12 @@ private: 1), }; - descriptorLayoutCreateInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); - - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCreateInfo, nullptr, &descriptorSetLayouts.color)); + descriptorLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayouts.color)); // Create a color pipeline layout. - pipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.color, 1); - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.color)); + pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.color, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayouts.color)); } void preparePipelines() @@ -503,29 +449,23 @@ private: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.renderPass.descriptor), - // Binding 1: ObjectUBO - vks::initializers::writeDescriptorSet( - descriptorSets.geometry, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - 1, - &uniformBuffers.objects.descriptor), // Binding 2: GeometrySBO vks::initializers::writeDescriptorSet( descriptorSets.geometry, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - 2, + 1, &geometryPass.geometry.descriptor), // Binding 3: headIndexImage vks::initializers::writeDescriptorSet( descriptorSets.geometry, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - 3, + 2, &geometryPass.headIndex.descriptor), // Binding 4: LinkedListSBO vks::initializers::writeDescriptorSet( descriptorSets.geometry, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - 4, + 3, &geometryPass.linkedList.descriptor) }; @@ -609,19 +549,37 @@ private: vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.geometry); uint32_t dynamicOffset = 0; models.sphere.bindBuffers(drawCmdBuffers[i]); - for (auto j = 0; j != SPHERE_COUNT; ++j) + + // Render the scene + ObjectData objectData; + + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.geometry, 0, 1, &descriptorSets.geometry, 0, nullptr); + objectData.color = glm::vec4(1.0f, 0.0f, 0.0f, 0.5f); + for (int32_t x = 0; x < 5; x++) { - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.geometry, 0, 1, &descriptorSets.geometry, 1, &dynamicOffset); - models.sphere.draw(drawCmdBuffers[i]); - dynamicOffset += objectUniformBufferSize; + for (int32_t y = 0; y < 5; y++) + { + for (int32_t z = 0; z < 5; z++) + { + glm::mat4 T = glm::translate(glm::mat4(1.0f), glm::vec3(x - 2, y - 2, z - 2)); + glm::mat4 S = glm::scale(glm::mat4(1.0f), glm::vec3(0.3f)); + objectData.model = T * S; + vkCmdPushConstants(drawCmdBuffers[i], pipelineLayouts.geometry, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjectData), &objectData); + models.sphere.draw(drawCmdBuffers[i]); + } + } } - models.cube.bindBuffers(drawCmdBuffers[i]); - for (auto j = 0; j != CUBE_COUNT; ++j) + + objectData.color = glm::vec4(0.0f, 0.0f, 1.0f, 0.5f); + for (uint32_t x = 0; x < 2; x++) { - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.geometry, 0, 1, &descriptorSets.geometry, 1, &dynamicOffset); + glm::mat4 T = glm::translate(glm::mat4(1.0f), glm::vec3(3.0f * x - 1.5f, 0.0f, 0.0f)); + glm::mat4 S = glm::scale(glm::mat4(1.0f), glm::vec3(0.2f)); + objectData.model = T * S; + vkCmdPushConstants(drawCmdBuffers[i], pipelineLayouts.geometry, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjectData), &objectData); models.cube.draw(drawCmdBuffers[i]); - dynamicOffset += objectUniformBufferSize; } + vkCmdEndRenderPass(drawCmdBuffers[i]); // Make a pipeline barrier to guarantee the geometry pass is done