Skip to content

Commit 382c9fc

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

1 file changed

Lines changed: 72 additions & 74 deletions

File tree

examples/bufferdeviceaddress/bufferdeviceaddress.cpp

Lines changed: 72 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
*
44
* This sample shows how to read data from a buffer device address (aka "reference") instead of using uniforms
55
* The application passes buffer device addresses to the shader via push constants, and the shader then simply reads the data behind that address
6+
* This makes stuff like descriptor handling a lot easier, as we now only pass around references akin to pointers and no longer need descriptors for buffers
67
* See cube.vert for the shader side of things
78
*
8-
* Copyright (C) 2024 by Sascha Willems - www.saschawillems.de
9+
* Copyright (C) 2024-2025 by Sascha Willems - www.saschawillems.de
910
*
1011
*/
1112

@@ -19,9 +20,9 @@ class VulkanExample : public VulkanExampleBase
1920

2021
struct Cube {
2122
glm::mat4 modelMatrix;
22-
vks::Buffer buffer;
2323
glm::vec3 rotation;
24-
VkDeviceAddress bufferDeviceAddress{};
24+
std::array<vks::Buffer, maxConcurrentFrames> buffers{};
25+
std::array<VkDeviceAddress, maxConcurrentFrames> bufferDeviceAddresses{};
2526
};
2627
std::array<Cube, 2> cubes{};
2728

@@ -31,8 +32,8 @@ class VulkanExample : public VulkanExampleBase
3132
// Global matrices
3233
struct Scene {
3334
glm::mat4 mvp;
34-
vks::Buffer buffer;
35-
VkDeviceAddress bufferDeviceAddress{};
35+
std::array<vks::Buffer, maxConcurrentFrames> buffers;
36+
std::array<VkDeviceAddress, maxConcurrentFrames> bufferDeviceAddresses{};
3637
} scene;
3738

3839
VkPipeline pipeline{ VK_NULL_HANDLE };
@@ -53,6 +54,8 @@ class VulkanExample : public VulkanExampleBase
5354

5455
VulkanExample() : VulkanExampleBase()
5556
{
57+
useNewSync = true;
58+
5659
title = "Buffer device address";
5760
camera.type = Camera::CameraType::lookat;
5861
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
@@ -77,10 +80,14 @@ class VulkanExample : public VulkanExampleBase
7780
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
7881
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
7982
texture.destroy();
80-
for (auto cube : cubes) {
81-
cube.buffer.destroy();
83+
for (auto& cube : cubes) {
84+
for (auto& buffer : cube.buffers) {
85+
buffer.destroy();
86+
}
87+
}
88+
for (auto& buffer : scene.buffers) {
89+
buffer.destroy();
8290
}
83-
scene.buffer.destroy();
8491
}
8592
}
8693

@@ -170,34 +177,35 @@ class VulkanExample : public VulkanExampleBase
170177
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
171178
}
172179

173-
void prepareBuffers()
180+
void prepareUniformBuffers()
174181
{
175-
// Note that we don't use this buffer for uniforms but rather pass it's address as a reference to the shader, so isntead of the uniform buffer usage we use a different flag
176-
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &scene.buffer, sizeof(glm::mat4)));
177-
VK_CHECK_RESULT(scene.buffer.map());
178-
179-
// Get the device of this buffer that is later on passed to the shader (aka "reference")
180-
VkBufferDeviceAddressInfo bufferDeviceAdressInfo{};
181-
bufferDeviceAdressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
182-
bufferDeviceAdressInfo.buffer = scene.buffer.buffer;
183-
scene.bufferDeviceAddress = vkGetBufferDeviceAddressKHR(device, &bufferDeviceAdressInfo);
184-
185-
for (auto& cube : cubes) {
182+
for (uint32_t i = 0; i < maxConcurrentFrames; i++) {
186183
// Note that we don't use this buffer for uniforms but rather pass it's address as a reference to the shader, so isntead of the uniform buffer usage we use a different flag
187-
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &cube.buffer, sizeof(glm::mat4)));
188-
VK_CHECK_RESULT(cube.buffer.map());
184+
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &scene.buffers[i], sizeof(glm::mat4)));
185+
VK_CHECK_RESULT(scene.buffers[i].map());
189186

190187
// Get the device of this buffer that is later on passed to the shader (aka "reference")
191-
bufferDeviceAdressInfo.buffer = cube.buffer.buffer;
192-
cube.bufferDeviceAddress = vkGetBufferDeviceAddressKHR(device, &bufferDeviceAdressInfo);
188+
VkBufferDeviceAddressInfo bufferDeviceAdressInfo{};
189+
bufferDeviceAdressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
190+
bufferDeviceAdressInfo.buffer = scene.buffers[i].buffer;
191+
scene.bufferDeviceAddresses[i] = vkGetBufferDeviceAddressKHR(device, &bufferDeviceAdressInfo);
192+
193+
for (auto& cube : cubes) {
194+
// Note that we don't use this buffer for uniforms but rather pass it's address as a reference to the shader, so isntead of the uniform buffer usage we use a different flag
195+
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &cube.buffers[i], sizeof(glm::mat4)));
196+
VK_CHECK_RESULT(cube.buffers[i].map());
197+
198+
// Get the device of this buffer that is later on passed to the shader (aka "reference")
199+
bufferDeviceAdressInfo.buffer = cube.buffers[i].buffer;
200+
cube.bufferDeviceAddresses[i] = vkGetBufferDeviceAddressKHR(device, &bufferDeviceAdressInfo);
201+
}
193202
}
194-
updateBuffers();
195203
}
196204

197-
void updateBuffers()
205+
void updateUniformBuffers()
198206
{
199207
scene.mvp = camera.matrices.perspective * camera.matrices.view;
200-
memcpy(scene.buffer.mapped, &scene, sizeof(glm::mat4));
208+
memcpy(scene.buffers[currentBuffer].mapped, &scene, sizeof(glm::mat4));
201209

202210
cubes[0].modelMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(-2.0f, 0.0f, 0.0f));
203211
cubes[1].modelMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(1.5f, 0.5f, 0.0f));
@@ -207,7 +215,7 @@ class VulkanExample : public VulkanExampleBase
207215
cube.modelMatrix = glm::rotate(cube.modelMatrix, glm::radians(cube.rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
208216
cube.modelMatrix = glm::rotate(cube.modelMatrix, glm::radians(cube.rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
209217
cube.modelMatrix = glm::scale(cube.modelMatrix, glm::vec3(0.25f));
210-
memcpy(cube.buffer.mapped, &cube.modelMatrix, sizeof(glm::mat4));
218+
memcpy(cube.buffers[currentBuffer].mapped, &cube.modelMatrix, sizeof(glm::mat4));
211219
}
212220
}
213221

@@ -219,18 +227,20 @@ class VulkanExample : public VulkanExampleBase
219227
vkGetBufferDeviceAddressKHR = reinterpret_cast<PFN_vkGetBufferDeviceAddressKHR>(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR"));
220228

221229
loadAssets();
222-
prepareBuffers();
230+
prepareUniformBuffers();
223231
setupDescriptors();
224232
preparePipelines();
225-
buildCommandBuffers();
226233
prepared = true;
227234
}
228235

229-
void buildCommandBuffers()
236+
void buildCommandBuffer()
230237
{
238+
VkCommandBuffer cmdBuffer = drawCmdBuffers[currentBuffer];
239+
vkResetCommandBuffer(cmdBuffer, 0);
240+
231241
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
232242

233-
VkClearValue clearValues[2];
243+
VkClearValue clearValues[2]{};
234244
clearValues[0].color = defaultClearColor;
235245
clearValues[1].depthStencil = { 1.0f, 0 };
236246

@@ -242,64 +252,52 @@ class VulkanExample : public VulkanExampleBase
242252
renderPassBeginInfo.renderArea.extent.height = height;
243253
renderPassBeginInfo.clearValueCount = 2;
244254
renderPassBeginInfo.pClearValues = clearValues;
255+
renderPassBeginInfo.framebuffer = frameBuffers[currentImageIndex];
245256

246-
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) {
247-
renderPassBeginInfo.framebuffer = frameBuffers[i];
248-
249-
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
257+
VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo));
250258

251-
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
259+
vkCmdBeginRenderPass(cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
252260

253-
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
261+
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
254262

255-
VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
256-
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
263+
VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
264+
vkCmdSetViewport(cmdBuffer, 0, 1, &viewport);
257265

258-
VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
259-
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
266+
VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
267+
vkCmdSetScissor(cmdBuffer, 0, 1, &scissor);
260268

261-
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
269+
vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
262270

263-
model.bindBuffers(drawCmdBuffers[i]);
271+
model.bindBuffers(cmdBuffer);
264272

265-
// Instead of using descriptors to pass global and per-model matrices to the shader, we can now simply pass buffer references via push constants
266-
// The shader then simply reads data from the address of that reference
267-
PushConstantBlock references{};
268-
// Pass pointer to the global matrix via a buffer device address
269-
references.sceneReference = scene.bufferDeviceAddress;
273+
// Instead of using descriptors to pass global and per-model matrices to the shader, we can now simply pass buffer references via push constants
274+
// The shader then simply reads data from the address of that reference
275+
PushConstantBlock references{};
276+
// Pass pointer to the global matrix via a buffer device address
277+
references.sceneReference = scene.bufferDeviceAddresses[currentBuffer];
270278

271-
for (auto& cube : cubes) {
272-
// Pass pointer to this cube's data buffer via a buffer device address
273-
// So instead of having to bind different descriptors, we only pass a different device address
274-
// This doesn't have to be an address from a different buffer, but could very well be just another address in the same buffer
275-
references.modelReference = cube.bufferDeviceAddress;
276-
vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstantBlock), &references);
277-
278-
model.draw(drawCmdBuffers[i]);
279-
}
279+
for (auto& cube : cubes) {
280+
// Pass pointer to this cube's data buffer via a buffer device address
281+
// So instead of having to bind different descriptors, we only pass a different device address
282+
// This doesn't have to be an address from a different buffer, but could very well be just another address in the same buffer
283+
references.modelReference = cube.bufferDeviceAddresses[currentBuffer];
284+
vkCmdPushConstants(cmdBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstantBlock), &references);
280285

281-
drawUI(drawCmdBuffers[i]);
286+
model.draw(cmdBuffer);
287+
}
282288

283-
vkCmdEndRenderPass(drawCmdBuffers[i]);
289+
drawUI(cmdBuffer);
284290

285-
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
286-
}
287-
}
291+
vkCmdEndRenderPass(cmdBuffer);
288292

289-
void draw()
290-
{
291-
VulkanExampleBase::prepareFrame();
292-
submitInfo.commandBufferCount = 1;
293-
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
294-
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
295-
VulkanExampleBase::submitFrame();
293+
VK_CHECK_RESULT(vkEndCommandBuffer(cmdBuffer));
296294
}
297295

298296
virtual void render()
299297
{
300298
if (!prepared)
301299
return;
302-
draw();
300+
VulkanExampleBase::prepareFrame();
303301
if (animate && !paused) {
304302
cubes[0].rotation.x += 2.5f * frameTimer;
305303
if (cubes[0].rotation.x > 360.0f)
@@ -308,9 +306,9 @@ class VulkanExample : public VulkanExampleBase
308306
if (cubes[1].rotation.x > 360.0f)
309307
cubes[1].rotation.x -= 360.0f;
310308
}
311-
if ((camera.updated) || (animate && !paused)) {
312-
updateBuffers();
313-
}
309+
updateUniformBuffers();
310+
buildCommandBuffer();
311+
VulkanExampleBase::submitFrame();
314312
}
315313

316314
virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay)

0 commit comments

Comments
 (0)