Use push constants for fixed object data, some minor code cleanup

This commit is contained in:
Sascha Willems 2020-08-21 17:27:54 +02:00
parent fbc3526c58
commit e04c084312
9 changed files with 80 additions and 128 deletions

View file

@ -11,25 +11,24 @@ struct Node
uint next; uint next;
}; };
layout (set = 0, binding = 1) uniform ObjectUBO layout (set = 0, binding = 1) buffer GeometrySBO
{
mat4 model;
vec4 color;
} objectUBO;
layout (set = 0, binding = 2) buffer GeometrySBO
{ {
uint count; uint count;
uint maxNodeCount; 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[]; Node nodes[];
}; };
layout(push_constant) uniform PushConsts {
mat4 model;
vec4 color;
} pushConsts;
void main() void main()
{ {
// Increase the node count // Increase the node count
@ -42,7 +41,7 @@ void main()
uint prevHeadIdx = imageAtomicExchange(headIndexImage, ivec2(gl_FragCoord.xy), nodeIdx); uint prevHeadIdx = imageAtomicExchange(headIndexImage, ivec2(gl_FragCoord.xy), nodeIdx);
// Store node data // Store node data
nodes[nodeIdx].color = objectUBO.color; nodes[nodeIdx].color = pushConsts.color;
nodes[nodeIdx].depth = gl_FragCoord.z; nodes[nodeIdx].depth = gl_FragCoord.z;
nodes[nodeIdx].next = prevHeadIdx; nodes[nodeIdx].next = prevHeadIdx;
} }

View file

@ -8,14 +8,13 @@ layout (set = 0, binding = 0) uniform RenderPassUBO
mat4 view; mat4 view;
} renderPassUBO; } renderPassUBO;
layout (set = 0, binding = 1) uniform ObjectUBO layout(push_constant) uniform PushConsts {
{
mat4 model; mat4 model;
vec4 color; vec4 color;
} objectUBO; } pushConsts;
void main() 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); gl_Position = PVM * vec4(inPos, 1.0);
} }

View file

@ -14,25 +14,23 @@ struct Node
uint next; uint next;
}; };
struct ObjectUBO
{
float4x4 model;
float4 color;
};
cbuffer ubo : register(b1) { ObjectUBO objectUBO; }
struct GeometrySBO struct GeometrySBO
{ {
uint count; uint count;
uint maxNodeCount; uint maxNodeCount;
}; };
// Binding 0 : Position storage buffer // Binding 0 : Position storage buffer
RWStructuredBuffer<GeometrySBO> geometrySBO : register(u2); RWStructuredBuffer<GeometrySBO> geometrySBO : register(u1);
RWTexture2D<uint> headIndexImage : register(u3); RWTexture2D<uint> headIndexImage : register(u2);
RWStructuredBuffer<Node> nodes : register(u4); RWStructuredBuffer<Node> nodes : register(u3);
struct PushConsts {
float4x4 model;
float4 color;
};
[[vk::push_constant]] PushConsts pushConsts;
[earlydepthstencil] [earlydepthstencil]
void main(VSOutput input) void main(VSOutput input)
@ -49,7 +47,7 @@ void main(VSOutput input)
InterlockedExchange(headIndexImage[uint2(input.Pos.xy)], nodeIdx, prevHeadIdx); InterlockedExchange(headIndexImage[uint2(input.Pos.xy)], nodeIdx, prevHeadIdx);
// Store node data // Store node data
nodes[nodeIdx].color = objectUBO.color; nodes[nodeIdx].color = pushConsts.color;
nodes[nodeIdx].depth = input.Pos.z; nodes[nodeIdx].depth = input.Pos.z;
nodes[nodeIdx].next = prevHeadIdx; nodes[nodeIdx].next = prevHeadIdx;
} }

View file

@ -13,13 +13,11 @@ struct RenderPassUBO
cbuffer renderPassUBO : register(b0) { RenderPassUBO renderPassUBO; } cbuffer renderPassUBO : register(b0) { RenderPassUBO renderPassUBO; }
struct ObjectUBO struct PushConsts {
{
float4x4 model; float4x4 model;
float4 color; float4 color;
}; };
[[vk::push_constant]] PushConsts pushConsts;
cbuffer objectUBO : register(b1) { ObjectUBO objectUBO; }
struct VSOutput struct VSOutput
{ {
@ -29,6 +27,6 @@ struct VSOutput
VSOutput main(VSInput input) VSOutput main(VSInput input)
{ {
VSOutput output = (VSOutput)0; 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; return output;
} }

View file

@ -13,8 +13,6 @@
#include "VulkanglTFModel.h" #include "VulkanglTFModel.h"
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
#define SPHERE_COUNT 5 * 5 * 5
#define CUBE_COUNT 2
#define NODE_COUNT 20 #define NODE_COUNT 20
class VulkanExample : public VulkanExampleBase class VulkanExample : public VulkanExampleBase
@ -27,7 +25,6 @@ public:
struct { struct {
vks::Buffer renderPass; vks::Buffer renderPass;
vks::Buffer objects;
} uniformBuffers; } uniformBuffers;
struct Node { struct Node {
@ -54,10 +51,10 @@ public:
glm::mat4 view; glm::mat4 view;
} renderPassUBO; } renderPassUBO;
struct { struct ObjectData {
glm::mat4 model; glm::mat4 model;
glm::vec4 color; glm::vec4 color;
} objectUBO; };
struct { struct {
VkDescriptorSetLayout geometry; VkDescriptorSetLayout geometry;
@ -103,7 +100,6 @@ public:
destroyGeometryPass(); destroyGeometryPass();
uniformBuffers.renderPass.destroy(); uniformBuffers.renderPass.destroy();
uniformBuffers.objects.destroy();
} }
void getEnabledFeatures() override void getEnabledFeatures() override
@ -171,49 +167,6 @@ private:
sizeof(renderPassUBO))); sizeof(renderPassUBO)));
VK_CHECK_RESULT(uniformBuffers.renderPass.map()); 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<uint8_t*>(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() void prepareGeometryPass()
@ -222,7 +175,7 @@ private:
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
// Geometry render pass doesn't need any output attachment. // Geometry render pass doesn't need any output attachment.
auto renderPassInfo = vks::initializers::renderPassCreateInfo(); VkRenderPassCreateInfo renderPassInfo = vks::initializers::renderPassCreateInfo();
renderPassInfo.attachmentCount = 0; renderPassInfo.attachmentCount = 0;
renderPassInfo.subpassCount = 1; renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpassDescription; renderPassInfo.pSubpasses = &subpassDescription;
@ -314,8 +267,8 @@ private:
VK_CHECK_RESULT(geometryPass.linkedList.map()); VK_CHECK_RESULT(geometryPass.linkedList.map());
// Change HeadInex image's layout from UNDEFINED to GENERAL // Change HeadIndex image's layout from UNDEFINED to GENERAL
auto cmdBufAllocInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); VkCommandBufferAllocateInfo cmdBufAllocInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1);
VkCommandBuffer cmdBuf; VkCommandBuffer cmdBuf;
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocInfo, &cmdBuf)); VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocInfo, &cmdBuf));
@ -323,7 +276,7 @@ private:
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuf, &cmdBufInfo)); VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuf, &cmdBufInfo));
auto barrier = vks::initializers::imageMemoryBarrier(); VkImageMemoryBarrier barrier = vks::initializers::imageMemoryBarrier();
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
@ -336,7 +289,7 @@ private:
VK_CHECK_RESULT(vkEndCommandBuffer(cmdBuf)); VK_CHECK_RESULT(vkEndCommandBuffer(cmdBuf));
auto submitInfo = vks::initializers::submitInfo(); VkSubmitInfo submitInfo = vks::initializers::submitInfo();
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuf; submitInfo.pCommandBuffers = &cmdBuf;
@ -353,37 +306,33 @@ private:
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
0), 0),
// ObjectUBO
vks::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
1),
// AtomicSBO // AtomicSBO
vks::initializers::descriptorSetLayoutBinding( vks::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
2), 1),
// headIndexImage // headIndexImage
vks::initializers::descriptorSetLayoutBinding( vks::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
3), 2),
// LinkedListSBO // LinkedListSBO
vks::initializers::descriptorSetLayoutBinding( vks::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
4), 3),
}; };
auto descriptorLayoutCreateInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VkDescriptorSetLayoutCreateInfo descriptorLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings);
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayouts.geometry));
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCreateInfo, nullptr, &descriptorSetLayouts.geometry));
// Create a geometry pipeline layout. // Create a geometry pipeline layout.
auto pipelineLayoutCreateInfo = VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.geometry, 1);
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);
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.geometry)); pipelineLayoutCI.pushConstantRangeCount = 1;
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayouts.geometry));
// Create a color descriptor set layout. // Create a color descriptor set layout.
setLayoutBindings = { setLayoutBindings = {
@ -399,15 +348,12 @@ private:
1), 1),
}; };
descriptorLayoutCreateInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); descriptorLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings);
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayouts.color));
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCreateInfo, nullptr, &descriptorSetLayouts.color));
// Create a color pipeline layout. // Create a color pipeline layout.
pipelineLayoutCreateInfo = pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.color, 1);
vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.color, 1); VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayouts.color));
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayouts.color));
} }
void preparePipelines() void preparePipelines()
@ -503,29 +449,23 @@ private:
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0, 0,
&uniformBuffers.renderPass.descriptor), &uniformBuffers.renderPass.descriptor),
// Binding 1: ObjectUBO
vks::initializers::writeDescriptorSet(
descriptorSets.geometry,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
1,
&uniformBuffers.objects.descriptor),
// Binding 2: GeometrySBO // Binding 2: GeometrySBO
vks::initializers::writeDescriptorSet( vks::initializers::writeDescriptorSet(
descriptorSets.geometry, descriptorSets.geometry,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
2, 1,
&geometryPass.geometry.descriptor), &geometryPass.geometry.descriptor),
// Binding 3: headIndexImage // Binding 3: headIndexImage
vks::initializers::writeDescriptorSet( vks::initializers::writeDescriptorSet(
descriptorSets.geometry, descriptorSets.geometry,
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
3, 2,
&geometryPass.headIndex.descriptor), &geometryPass.headIndex.descriptor),
// Binding 4: LinkedListSBO // Binding 4: LinkedListSBO
vks::initializers::writeDescriptorSet( vks::initializers::writeDescriptorSet(
descriptorSets.geometry, descriptorSets.geometry,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
4, 3,
&geometryPass.linkedList.descriptor) &geometryPass.linkedList.descriptor)
}; };
@ -609,19 +549,37 @@ private:
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.geometry); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.geometry);
uint32_t dynamicOffset = 0; uint32_t dynamicOffset = 0;
models.sphere.bindBuffers(drawCmdBuffers[i]); 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); 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.sphere.draw(drawCmdBuffers[i]);
dynamicOffset += objectUniformBufferSize;
} }
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]); models.cube.draw(drawCmdBuffers[i]);
dynamicOffset += objectUniformBufferSize;
} }
vkCmdEndRenderPass(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]);
// Make a pipeline barrier to guarantee the geometry pass is done // Make a pipeline barrier to guarantee the geometry pass is done