Skip to content

Commit eaff8c0

Browse files
committed
Update additional samples to use new sync
1 parent ac160ad commit eaff8c0

1 file changed

Lines changed: 112 additions & 134 deletions

File tree

examples/dynamicuniformbuffer/dynamicuniformbuffer.cpp

Lines changed: 112 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* Vulkan Example - Dynamic uniform buffers
33
*
4-
* Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de
4+
* Copyright (C) 2016-2025 by Sascha Willems - www.saschawillems.de
55
*
66
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
77
*
@@ -18,7 +18,7 @@
1818

1919
#include "vulkanexamplebase.h"
2020

21-
#define OBJECT_INSTANCES 125
21+
constexpr auto OBJECT_INSTANCES = 125;
2222

2323
// Vertex layout for this example
2424
struct Vertex {
@@ -57,10 +57,11 @@ class VulkanExample : public VulkanExampleBase
5757
vks::Buffer indexBuffer;
5858
uint32_t indexCount{ 0 };
5959

60-
struct {
60+
struct UniformBuffers {
6161
vks::Buffer view;
6262
vks::Buffer dynamic;
63-
} uniformBuffers;
63+
};
64+
std::array<UniformBuffers, maxConcurrentFrames> uniformBuffers;
6465

6566
struct {
6667
glm::mat4 projection;
@@ -82,12 +83,11 @@ class VulkanExample : public VulkanExampleBase
8283
VkDescriptorSet descriptorSet{ VK_NULL_HANDLE };
8384
VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE };
8485

85-
float animationTimer{ 0.0f };
86-
8786
size_t dynamicAlignment{ 0 };
8887

8988
VulkanExample() : VulkanExampleBase()
9089
{
90+
useNewSync = true;
9191
title = "Dynamic uniform buffers";
9292
camera.type = Camera::CameraType::lookat;
9393
camera.setPosition(glm::vec3(0.0f, 0.0f, -30.0f));
@@ -106,64 +106,10 @@ class VulkanExample : public VulkanExampleBase
106106
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
107107
vertexBuffer.destroy();
108108
indexBuffer.destroy();
109-
uniformBuffers.view.destroy();
110-
uniformBuffers.dynamic.destroy();
111-
}
112-
}
113-
114-
void buildCommandBuffers()
115-
{
116-
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
117-
118-
VkClearValue clearValues[2];
119-
clearValues[0].color = defaultClearColor;
120-
clearValues[1].depthStencil = { 1.0f, 0 };
121-
122-
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
123-
renderPassBeginInfo.renderPass = renderPass;
124-
renderPassBeginInfo.renderArea.offset.x = 0;
125-
renderPassBeginInfo.renderArea.offset.y = 0;
126-
renderPassBeginInfo.renderArea.extent.width = width;
127-
renderPassBeginInfo.renderArea.extent.height = height;
128-
renderPassBeginInfo.clearValueCount = 2;
129-
renderPassBeginInfo.pClearValues = clearValues;
130-
131-
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
132-
{
133-
renderPassBeginInfo.framebuffer = frameBuffers[i];
134-
135-
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
136-
137-
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
138-
139-
VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
140-
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
141-
142-
VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
143-
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
144-
145-
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
146-
147-
VkDeviceSize offsets[1] = { 0 };
148-
vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &vertexBuffer.buffer, offsets);
149-
vkCmdBindIndexBuffer(drawCmdBuffers[i], indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
150-
151-
// Render multiple objects using different model matrices by dynamically offsetting into one uniform buffer
152-
for (uint32_t j = 0; j < OBJECT_INSTANCES; j++)
153-
{
154-
// One dynamic offset per dynamic descriptor to offset into the ubo containing all model matrices
155-
uint32_t dynamicOffset = j * static_cast<uint32_t>(dynamicAlignment);
156-
// Bind the descriptor set for rendering a mesh using the dynamic offset
157-
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 1, &dynamicOffset);
158-
159-
vkCmdDrawIndexed(drawCmdBuffers[i], indexCount, 1, 0, 0, 0);
109+
for (auto& buffer : uniformBuffers) {
110+
buffer.view.destroy();
111+
buffer.dynamic.destroy();
160112
}
161-
162-
drawUI(drawCmdBuffers[i]);
163-
164-
vkCmdEndRenderPass(drawCmdBuffers[i]);
165-
166-
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
167113
}
168114
}
169115

@@ -208,12 +154,12 @@ class VulkanExample : public VulkanExampleBase
208154
{
209155
// Pool
210156
std::vector<VkDescriptorPoolSize> poolSizes = {
211-
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
212-
// Dynamic uniform buffer
213-
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1)
157+
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, maxConcurrentFrames),
158+
// Dynamic uniform buffers require a different descriptor type
159+
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, maxConcurrentFrames)
214160
};
215161

216-
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2);
162+
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, maxConcurrentFrames);
217163
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
218164

219165
// Layout
@@ -226,17 +172,20 @@ class VulkanExample : public VulkanExampleBase
226172
VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings);
227173
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout));
228174

229-
// Set
175+
// Sets per frame, just like the buffers themselves
176+
// Images do not need to be duplicated per frame, we reuse the same one for each frame
230177
VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
231-
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
232-
233-
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
234-
// Binding 0 : Projection/View matrix as uniform buffer
235-
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.view.descriptor),
236-
// Binding 1 : Instance matrix as dynamic uniform buffer
237-
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, &uniformBuffers.dynamic.descriptor),
238-
};
239-
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
178+
for (auto i = 0; i < uniformBuffers.size(); i++) {
179+
VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
180+
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
181+
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
182+
// Binding 0 : Projection/View matrix as uniform buffer
183+
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers[currentBuffer].view.descriptor),
184+
// Binding 1 : Instance matrix as dynamic uniform buffer
185+
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, &uniformBuffers[currentBuffer].dynamic.descriptor),
186+
};
187+
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
188+
}
240189
}
241190

242191
void preparePipelines()
@@ -255,7 +204,7 @@ class VulkanExample : public VulkanExampleBase
255204
VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0);
256205
std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
257206
VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables);
258-
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
207+
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages{};
259208

260209
// Vertex bindings and attributes
261210
VkVertexInputBindingDescription vertexInputBinding = {
@@ -309,28 +258,28 @@ class VulkanExample : public VulkanExampleBase
309258
std::cout << "minUniformBufferOffsetAlignment = " << minUboAlignment << std::endl;
310259
std::cout << "dynamicAlignment = " << dynamicAlignment << std::endl;
311260

312-
// Vertex shader uniform buffer block
313-
314-
// Static shared uniform buffer object with projection and view matrix
315-
VK_CHECK_RESULT(vulkanDevice->createBuffer(
316-
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
317-
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
318-
&uniformBuffers.view,
319-
sizeof(uboVS)));
320-
321-
// Uniform buffer object with per-object matrices
322-
VK_CHECK_RESULT(vulkanDevice->createBuffer(
323-
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
324-
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
325-
&uniformBuffers.dynamic,
326-
bufferSize));
327-
328-
// Override descriptor range to [base, base + dynamicAlignment]
329-
uniformBuffers.dynamic.descriptor.range = dynamicAlignment;
330-
331-
// Map persistent
332-
VK_CHECK_RESULT(uniformBuffers.view.map());
333-
VK_CHECK_RESULT(uniformBuffers.dynamic.map());
261+
for (auto& buffer : uniformBuffers) {
262+
// Static shared uniform buffer object with projection and view matrix
263+
VK_CHECK_RESULT(vulkanDevice->createBuffer(
264+
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
265+
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
266+
&buffer.view,
267+
sizeof(uboVS)));
268+
269+
// Uniform buffer object with per-object matrices
270+
VK_CHECK_RESULT(vulkanDevice->createBuffer(
271+
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
272+
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
273+
&buffer.dynamic,
274+
bufferSize));
275+
276+
// Override descriptor range to [base, base + dynamicAlignment]
277+
buffer.dynamic.descriptor.range = dynamicAlignment;
278+
279+
// Map persistent
280+
VK_CHECK_RESULT(buffer.view.map());
281+
VK_CHECK_RESULT(buffer.dynamic.map());
282+
}
334283

335284
// Prepare per-object matrices with offsets and random rotations
336285
std::default_random_engine rndEngine(benchmark.active ? 0 : (unsigned)time(nullptr));
@@ -339,45 +288,31 @@ class VulkanExample : public VulkanExampleBase
339288
rotations[i] = glm::vec3(rndDist(rndEngine), rndDist(rndEngine), rndDist(rndEngine)) * 2.0f * (float)M_PI;
340289
rotationSpeeds[i] = glm::vec3(rndDist(rndEngine), rndDist(rndEngine), rndDist(rndEngine));
341290
}
342-
343-
updateUniformBuffers();
344-
updateDynamicUniformBuffer();
345291
}
346292

347293
void updateUniformBuffers()
348294
{
349295
// Fixed ubo with projection and view matrices
350296
uboVS.projection = camera.matrices.perspective;
351297
uboVS.view = camera.matrices.view;
352-
353-
memcpy(uniformBuffers.view.mapped, &uboVS, sizeof(uboVS));
298+
memcpy(uniformBuffers[currentBuffer].view.mapped, &uboVS, sizeof(uboVS));
354299
}
355300

356301
void updateDynamicUniformBuffer()
357302
{
358-
// Update at max. 60 fps
359-
animationTimer += frameTimer;
360-
if (animationTimer <= 1.0f / 60.0f) {
361-
return;
362-
}
363-
364303
// Dynamic ubo with per-object model matrices indexed by offsets in the command buffer
365304
uint32_t dim = static_cast<uint32_t>(pow(OBJECT_INSTANCES, (1.0f / 3.0f)));
366305
glm::vec3 offset(5.0f);
367-
368-
for (uint32_t x = 0; x < dim; x++)
369-
{
370-
for (uint32_t y = 0; y < dim; y++)
371-
{
372-
for (uint32_t z = 0; z < dim; z++)
373-
{
374-
uint32_t index = x * dim * dim + y * dim + z;
306+
for (uint32_t x = 0; x < dim; x++) {
307+
for (uint32_t y = 0; y < dim; y++) {
308+
for (uint32_t z = 0; z < dim; z++) {
309+
const uint32_t index = x * dim * dim + y * dim + z;
375310

376311
// Aligned offset
377312
glm::mat4* modelMat = (glm::mat4*)(((uint64_t)uboDataDynamic.model + (index * dynamicAlignment)));
378313

379314
// Update rotations
380-
rotations[index] += animationTimer * rotationSpeeds[index];
315+
rotations[index] += frameTimer * rotationSpeeds[index];
381316

382317
// Update matrices
383318
glm::vec3 pos = glm::vec3(-((dim * offset.x) / 2.0f) + offset.x / 2.0f + x * offset.x, -((dim * offset.y) / 2.0f) + offset.y / 2.0f + y * offset.y, -((dim * offset.z) / 2.0f) + offset.z / 2.0f + z * offset.z);
@@ -388,14 +323,11 @@ class VulkanExample : public VulkanExampleBase
388323
}
389324
}
390325
}
391-
392-
animationTimer = 0.0f;
393-
394-
memcpy(uniformBuffers.dynamic.mapped, uboDataDynamic.model, uniformBuffers.dynamic.size);
326+
memcpy(uniformBuffers[currentBuffer].dynamic.mapped, uboDataDynamic.model, uniformBuffers[currentBuffer].dynamic.size);
395327
// Flush to make changes visible to the host
396328
VkMappedMemoryRange memoryRange = vks::initializers::mappedMemoryRange();
397-
memoryRange.memory = uniformBuffers.dynamic.memory;
398-
memoryRange.size = uniformBuffers.dynamic.size;
329+
memoryRange.memory = uniformBuffers[currentBuffer].dynamic.memory;
330+
memoryRange.size = uniformBuffers[currentBuffer].dynamic.size;
399331
vkFlushMappedMemoryRanges(device, 1, &memoryRange);
400332
}
401333

@@ -406,26 +338,72 @@ class VulkanExample : public VulkanExampleBase
406338
prepareUniformBuffers();
407339
setupDescriptors();
408340
preparePipelines();
409-
buildCommandBuffers();
410341
prepared = true;
411342
}
412343

413-
void draw()
344+
void buildCommandBuffer()
414345
{
415-
VulkanExampleBase::prepareFrame();
416-
submitInfo.commandBufferCount = 1;
417-
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
418-
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
419-
VulkanExampleBase::submitFrame();
346+
VkCommandBuffer cmdBuffer = drawCmdBuffers[currentBuffer];
347+
vkResetCommandBuffer(cmdBuffer, 0);
348+
349+
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
350+
351+
VkClearValue clearValues[2]{};
352+
clearValues[0].color = defaultClearColor;
353+
clearValues[1].depthStencil = { 1.0f, 0 };
354+
355+
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
356+
renderPassBeginInfo.renderPass = renderPass;
357+
renderPassBeginInfo.renderArea.offset.x = 0;
358+
renderPassBeginInfo.renderArea.offset.y = 0;
359+
renderPassBeginInfo.renderArea.extent.width = width;
360+
renderPassBeginInfo.renderArea.extent.height = height;
361+
renderPassBeginInfo.clearValueCount = 2;
362+
renderPassBeginInfo.pClearValues = clearValues;
363+
renderPassBeginInfo.framebuffer = frameBuffers[currentImageIndex];
364+
365+
VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo));
366+
367+
vkCmdBeginRenderPass(cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
368+
369+
VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
370+
vkCmdSetViewport(cmdBuffer, 0, 1, &viewport);
371+
372+
VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
373+
vkCmdSetScissor(cmdBuffer, 0, 1, &scissor);
374+
375+
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
376+
377+
VkDeviceSize offsets[1] = { 0 };
378+
vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer.buffer, offsets);
379+
vkCmdBindIndexBuffer(cmdBuffer, indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
380+
381+
// Render multiple objects using different model matrices by dynamically offsetting into one uniform buffer
382+
for (uint32_t j = 0; j < OBJECT_INSTANCES; j++) {
383+
// One dynamic offset per dynamic descriptor to offset into the ubo containing all model matrices
384+
uint32_t dynamicOffset = j * static_cast<uint32_t>(dynamicAlignment);
385+
// Bind the descriptor set for rendering a mesh using the dynamic offset
386+
vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 1, &dynamicOffset);
387+
388+
vkCmdDrawIndexed(cmdBuffer, indexCount, 1, 0, 0, 0);
389+
}
390+
391+
drawUI(cmdBuffer);
392+
393+
vkCmdEndRenderPass(cmdBuffer);
394+
395+
VK_CHECK_RESULT(vkEndCommandBuffer(cmdBuffer));
420396
}
421397

422398
virtual void render()
423399
{
424400
if (!prepared)
425401
return;
402+
VulkanExampleBase::prepareFrame();
426403
updateUniformBuffers();
427404
updateDynamicUniformBuffer();
428-
draw();
405+
buildCommandBuffer();
406+
VulkanExampleBase::submitFrame();
429407
}
430408
};
431409

0 commit comments

Comments
 (0)