Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3e2b63e

Browse files
committed
Update uniform buffer creation to have one per swap chain image
1 parent 5962e1f commit 3e2b63e

9 files changed

Lines changed: 206 additions & 119 deletions

05_Uniform_buffers/00_Descriptor_layout_and_buffer.md

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -234,18 +234,20 @@ the uniform buffer every frame, so it doesn't really make any sense to have a
234234
staging buffer. It would just add extra overhead in this case and likely degrade
235235
performance instead of improving it.
236236

237-
Add new class members for `uniformBuffer`, and `uniformBufferMemory`:
237+
We should have multiple buffers, because multiple frames may be in flight at the same time and we don't want to update the buffer in preparation of the next frame while a previous one is still reading from it! We could either have a uniform buffer per frame or per swap chain image. However, since we need to refer to the uniform buffer from the command buffer that we have per swap chain image, it makes the most sense to also have a uniform buffer per swap chain image.
238+
239+
To that end, add new class members for `uniformBuffers`, and `uniformBuffersMemory`:
238240

239241
```c++
240242
VkBuffer indexBuffer;
241243
VkDeviceMemory indexBufferMemory;
242244

243-
VkBuffer uniformBuffer;
244-
VkDeviceMemory uniformBufferMemory;
245+
std::vector<VkBuffer> uniformBuffers;
246+
std::vector<VkDeviceMemory> uniformBuffersMemory;
245247
```
246248

247-
Similarly, create a new function `createUniformBuffer` that is called after
248-
`createIndexBuffer` and allocates the buffer:
249+
Similarly, create a new function `createUniformBuffers` that is called after
250+
`createIndexBuffer` and allocates the buffers:
249251

250252
```c++
251253
void initVulkan() {
@@ -260,7 +262,13 @@ void initVulkan() {
260262

261263
void createUniformBuffer() {
262264
VkDeviceSize bufferSize = sizeof(UniformBufferObject);
263-
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory);
265+
266+
uniformBuffers.resize(swapChainImages.size());
267+
uniformBuffersMemory.resize(swapChainImages.size());
268+
269+
for (size_t i = 0; i < swapChainImages.size(); i++) {
270+
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
271+
}
264272
}
265273
```
266274

@@ -274,33 +282,40 @@ void cleanup() {
274282
cleanupSwapChain();
275283

276284
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
277-
vkDestroyBuffer(device, uniformBuffer, nullptr);
278-
vkFreeMemory(device, uniformBufferMemory, nullptr);
285+
286+
for (size_t i = 0; i < swapChainImages.size(); i++) {
287+
vkDestroyBuffer(device, uniformBuffers[i], nullptr);
288+
vkFreeMemory(device, uniformBuffersMemory[i], nullptr);
289+
}
279290

280291
...
281292
}
282293
```
283294

284295
## Updating uniform data
285296

286-
Create a new function `updateUniformBuffer` and add a call to it from the main
287-
loop:
297+
Create a new function `updateUniformBuffer` and add a call to it from the `drawFrame` function right after we know which swap chain image we're going to acquire:
288298

289299
```c++
290-
void mainLoop() {
291-
while (!glfwWindowShouldClose(window)) {
292-
glfwPollEvents();
300+
void drawFrame() {
301+
...
293302

294-
updateUniformBuffer();
295-
drawFrame();
296-
}
303+
uint32_t imageIndex;
304+
VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
305+
306+
...
297307

298-
vkDeviceWaitIdle(device);
308+
updateUniformBuffer(imageIndex);
309+
310+
VkSubmitInfo submitInfo = {};
311+
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
312+
313+
...
299314
}
300315

301316
...
302317

303-
void updateUniformBuffer() {
318+
void updateUniformBuffer(uint32_t currentImage) {
304319

305320
}
306321
```
@@ -328,7 +343,7 @@ timekeeping. We'll use this to make sure that the geometry rotates 90 degrees
328343
per second regardless of frame rate.
329344

330345
```c++
331-
void updateUniformBuffer() {
346+
void updateUniformBuffer(uint32_t currentImage) {
332347
static auto startTime = std::chrono::high_resolution_clock::now();
333348

334349
auto currentTime = std::chrono::high_resolution_clock::now();
@@ -381,22 +396,22 @@ sign on the scaling factor of the Y axis in the projection matrix. If you don't
381396
do this, then the image will be rendered upside down.
382397

383398
All of the transformations are defined now, so we can copy the data in the
384-
uniform buffer object to the uniform buffer. This happens in exactly the same
399+
uniform buffer object to the current uniform buffer. This happens in exactly the same
385400
way as we did for vertex buffers, except without a staging buffer:
386401

387402
```c++
388403
void* data;
389-
vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data);
404+
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
390405
memcpy(data, &ubo, sizeof(ubo));
391-
vkUnmapMemory(device, uniformBufferMemory);
406+
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
392407
```
393408
394409
Using a UBO this way is not the most efficient way to pass frequently changing
395410
values to the shader. A more efficient way to pass a small buffer of data to
396411
shaders are *push constants*. We may look at these in a future chapter.
397412
398413
In the next chapter we'll look at descriptor sets, which will actually bind the
399-
`VkBuffer` to the uniform buffer descriptor so that the shader can access this
414+
`VkBuffer`s to the uniform buffer descriptors so that the shader can access this
400415
transformation data.
401416
402417
[C++ code](/code/21_descriptor_layout.cpp) /

code/21_descriptor_layout.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ class HelloTriangleApplication {
154154
VkBuffer indexBuffer;
155155
VkDeviceMemory indexBufferMemory;
156156

157-
VkBuffer uniformBuffer;
158-
VkDeviceMemory uniformBufferMemory;
157+
std::vector<VkBuffer> uniformBuffers;
158+
std::vector<VkDeviceMemory> uniformBuffersMemory;
159159

160160
std::vector<VkCommandBuffer> commandBuffers;
161161

@@ -187,16 +187,14 @@ class HelloTriangleApplication {
187187
createCommandPool();
188188
createVertexBuffer();
189189
createIndexBuffer();
190-
createUniformBuffer();
190+
createUniformBuffers();
191191
createCommandBuffers();
192192
createSyncObjects();
193193
}
194194

195195
void mainLoop() {
196196
while (!glfwWindowShouldClose(window)) {
197197
glfwPollEvents();
198-
199-
updateUniformBuffer();
200198
drawFrame();
201199
}
202200

@@ -225,8 +223,11 @@ class HelloTriangleApplication {
225223
cleanupSwapChain();
226224

227225
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
228-
vkDestroyBuffer(device, uniformBuffer, nullptr);
229-
vkFreeMemory(device, uniformBufferMemory, nullptr);
226+
227+
for (size_t i = 0; i < swapChainImages.size(); i++) {
228+
vkDestroyBuffer(device, uniformBuffers[i], nullptr);
229+
vkFreeMemory(device, uniformBuffersMemory[i], nullptr);
230+
}
230231

231232
vkDestroyBuffer(device, indexBuffer, nullptr);
232233
vkFreeMemory(device, indexBufferMemory, nullptr);
@@ -723,9 +724,15 @@ class HelloTriangleApplication {
723724
vkFreeMemory(device, stagingBufferMemory, nullptr);
724725
}
725726

726-
void createUniformBuffer() {
727+
void createUniformBuffers() {
727728
VkDeviceSize bufferSize = sizeof(UniformBufferObject);
728-
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory);
729+
730+
uniformBuffers.resize(swapChainImages.size());
731+
uniformBuffersMemory.resize(swapChainImages.size());
732+
733+
for (size_t i = 0; i < swapChainImages.size(); i++) {
734+
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
735+
}
729736
}
730737

731738
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
@@ -874,7 +881,7 @@ class HelloTriangleApplication {
874881
}
875882
}
876883

877-
void updateUniformBuffer() {
884+
void updateUniformBuffer(uint32_t currentImage) {
878885
static auto startTime = std::chrono::high_resolution_clock::now();
879886

880887
auto currentTime = std::chrono::high_resolution_clock::now();
@@ -887,9 +894,9 @@ class HelloTriangleApplication {
887894
ubo.proj[1][1] *= -1;
888895

889896
void* data;
890-
vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data);
897+
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
891898
memcpy(data, &ubo, sizeof(ubo));
892-
vkUnmapMemory(device, uniformBufferMemory);
899+
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
893900
}
894901

895902
void drawFrame() {
@@ -906,6 +913,8 @@ class HelloTriangleApplication {
906913
throw std::runtime_error("failed to acquire swap chain image!");
907914
}
908915

916+
updateUniformBuffer(imageIndex);
917+
909918
VkSubmitInfo submitInfo = {};
910919
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
911920

code/22_descriptor_set.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ class HelloTriangleApplication {
154154
VkBuffer indexBuffer;
155155
VkDeviceMemory indexBufferMemory;
156156

157-
VkBuffer uniformBuffer;
158-
VkDeviceMemory uniformBufferMemory;
157+
std::vector<VkBuffer> uniformBuffers;
158+
std::vector<VkDeviceMemory> uniformBuffersMemory;
159159

160160
VkDescriptorPool descriptorPool;
161161
VkDescriptorSet descriptorSet;
@@ -190,7 +190,7 @@ class HelloTriangleApplication {
190190
createCommandPool();
191191
createVertexBuffer();
192192
createIndexBuffer();
193-
createUniformBuffer();
193+
createUniformBuffers();
194194
createDescriptorPool();
195195
createDescriptorSet();
196196
createCommandBuffers();
@@ -200,8 +200,6 @@ class HelloTriangleApplication {
200200
void mainLoop() {
201201
while (!glfwWindowShouldClose(window)) {
202202
glfwPollEvents();
203-
204-
updateUniformBuffer();
205203
drawFrame();
206204
}
207205

@@ -232,8 +230,11 @@ class HelloTriangleApplication {
232230
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
233231

234232
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
235-
vkDestroyBuffer(device, uniformBuffer, nullptr);
236-
vkFreeMemory(device, uniformBufferMemory, nullptr);
233+
234+
for (size_t i = 0; i < swapChainImages.size(); i++) {
235+
vkDestroyBuffer(device, uniformBuffers[i], nullptr);
236+
vkFreeMemory(device, uniformBuffersMemory[i], nullptr);
237+
}
237238

238239
vkDestroyBuffer(device, indexBuffer, nullptr);
239240
vkFreeMemory(device, indexBufferMemory, nullptr);
@@ -730,9 +731,15 @@ class HelloTriangleApplication {
730731
vkFreeMemory(device, stagingBufferMemory, nullptr);
731732
}
732733

733-
void createUniformBuffer() {
734+
void createUniformBuffers() {
734735
VkDeviceSize bufferSize = sizeof(UniformBufferObject);
735-
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory);
736+
737+
uniformBuffers.resize(swapChainImages.size());
738+
uniformBuffersMemory.resize(swapChainImages.size());
739+
740+
for (size_t i = 0; i < swapChainImages.size(); i++) {
741+
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
742+
}
736743
}
737744

738745
void createDescriptorPool() {
@@ -928,7 +935,7 @@ class HelloTriangleApplication {
928935
}
929936
}
930937

931-
void updateUniformBuffer() {
938+
void updateUniformBuffer(uint32_t currentImage) {
932939
static auto startTime = std::chrono::high_resolution_clock::now();
933940

934941
auto currentTime = std::chrono::high_resolution_clock::now();
@@ -941,9 +948,9 @@ class HelloTriangleApplication {
941948
ubo.proj[1][1] *= -1;
942949

943950
void* data;
944-
vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data);
951+
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
945952
memcpy(data, &ubo, sizeof(ubo));
946-
vkUnmapMemory(device, uniformBufferMemory);
953+
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
947954
}
948955

949956
void drawFrame() {
@@ -960,6 +967,8 @@ class HelloTriangleApplication {
960967
throw std::runtime_error("failed to acquire swap chain image!");
961968
}
962969

970+
updateUniformBuffer(imageIndex);
971+
963972
VkSubmitInfo submitInfo = {};
964973
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
965974

0 commit comments

Comments
 (0)