Skip to content

Commit 4454f6d

Browse files
Persistent mapping for uniform buffers (#310)
* Updated UBO chapter and removed in-place map and unmap of the ubo Replaced it with map-once aka "persistent mapping" * Fixed index for uniform buffer selection * Update code samples to persistent ubo mapping * Resize vector for mapped uniform buffer pointers * Use calculated buffer size for mapping * Update code samples to persistent ubo mapping * Spelling
1 parent 6ebbe97 commit 4454f6d

10 files changed

+54
-44
lines changed

code/22_descriptor_layout.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ class HelloTriangleApplication {
159159

160160
std::vector<VkBuffer> uniformBuffers;
161161
std::vector<VkDeviceMemory> uniformBuffersMemory;
162+
std::vector<void*> uniformBuffersMapped;
162163

163164
std::vector<VkCommandBuffer> commandBuffers;
164165

@@ -746,9 +747,12 @@ class HelloTriangleApplication {
746747

747748
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
748749
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
750+
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
749751

750752
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
751753
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
754+
755+
vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
752756
}
753757
}
754758

@@ -923,10 +927,7 @@ class HelloTriangleApplication {
923927
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 10.0f);
924928
ubo.proj[1][1] *= -1;
925929

926-
void* data;
927-
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
928-
memcpy(data, &ubo, sizeof(ubo));
929-
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
930+
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
930931
}
931932

932933
void drawFrame() {

code/23_descriptor_sets.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ class HelloTriangleApplication {
159159

160160
std::vector<VkBuffer> uniformBuffers;
161161
std::vector<VkDeviceMemory> uniformBuffersMemory;
162+
std::vector<void*> uniformBuffersMapped;
162163

163164
VkDescriptorPool descriptorPool;
164165
std::vector<VkDescriptorSet> descriptorSets;
@@ -753,9 +754,12 @@ class HelloTriangleApplication {
753754

754755
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
755756
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
757+
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
756758

757759
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
758760
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
761+
762+
vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
759763
}
760764
}
761765

@@ -981,10 +985,7 @@ class HelloTriangleApplication {
981985
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 10.0f);
982986
ubo.proj[1][1] *= -1;
983987

984-
void* data;
985-
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
986-
memcpy(data, &ubo, sizeof(ubo));
987-
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
988+
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
988989
}
989990

990991
void drawFrame() {

code/24_texture_image.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ class HelloTriangleApplication {
165165

166166
std::vector<VkBuffer> uniformBuffers;
167167
std::vector<VkDeviceMemory> uniformBuffersMemory;
168+
std::vector<void*> uniformBuffersMapped;
168169

169170
VkDescriptorPool descriptorPool;
170171
std::vector<VkDescriptorSet> descriptorSets;
@@ -898,9 +899,12 @@ class HelloTriangleApplication {
898899

899900
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
900901
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
902+
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
901903

902904
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
903905
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
906+
907+
vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
904908
}
905909
}
906910

@@ -1136,10 +1140,7 @@ class HelloTriangleApplication {
11361140
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 10.0f);
11371141
ubo.proj[1][1] *= -1;
11381142

1139-
void* data;
1140-
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
1141-
memcpy(data, &ubo, sizeof(ubo));
1142-
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
1143+
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
11431144
}
11441145

11451146
void drawFrame() {

code/25_sampler.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ class HelloTriangleApplication {
167167

168168
std::vector<VkBuffer> uniformBuffers;
169169
std::vector<VkDeviceMemory> uniformBuffersMemory;
170+
std::vector<void*> uniformBuffersMapped;
170171

171172
VkDescriptorPool descriptorPool;
172173
std::vector<VkDescriptorSet> descriptorSets;
@@ -937,9 +938,12 @@ class HelloTriangleApplication {
937938

938939
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
939940
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
941+
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
940942

941943
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
942944
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
945+
946+
vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
943947
}
944948
}
945949

@@ -1174,10 +1178,7 @@ class HelloTriangleApplication {
11741178
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 10.0f);
11751179
ubo.proj[1][1] *= -1;
11761180

1177-
void* data;
1178-
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
1179-
memcpy(data, &ubo, sizeof(ubo));
1180-
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
1181+
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
11811182
}
11821183

11831184
void drawFrame() {

code/26_texture_mapping.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ class HelloTriangleApplication {
173173

174174
std::vector<VkBuffer> uniformBuffers;
175175
std::vector<VkDeviceMemory> uniformBuffersMemory;
176+
std::vector<void*> uniformBuffersMapped;
176177

177178
VkDescriptorPool descriptorPool;
178179
std::vector<VkDescriptorSet> descriptorSets;
@@ -951,9 +952,12 @@ class HelloTriangleApplication {
951952

952953
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
953954
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
955+
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
954956

955957
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
956958
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
959+
960+
vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
957961
}
958962
}
959963

@@ -1204,10 +1208,7 @@ class HelloTriangleApplication {
12041208
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 10.0f);
12051209
ubo.proj[1][1] *= -1;
12061210

1207-
void* data;
1208-
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
1209-
memcpy(data, &ubo, sizeof(ubo));
1210-
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
1211+
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
12111212
}
12121213

12131214
void drawFrame() {

code/27_depth_buffering.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ class HelloTriangleApplication {
184184

185185
std::vector<VkBuffer> uniformBuffers;
186186
std::vector<VkDeviceMemory> uniformBuffersMemory;
187+
std::vector<void*> uniformBuffersMapped;
187188

188189
VkDescriptorPool descriptorPool;
189190
std::vector<VkDescriptorSet> descriptorSets;
@@ -1028,9 +1029,12 @@ class HelloTriangleApplication {
10281029

10291030
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
10301031
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
1032+
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
10311033

10321034
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
10331035
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
1036+
1037+
vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
10341038
}
10351039
}
10361040

@@ -1284,10 +1288,7 @@ class HelloTriangleApplication {
12841288
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 10.0f);
12851289
ubo.proj[1][1] *= -1;
12861290

1287-
void* data;
1288-
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
1289-
memcpy(data, &ubo, sizeof(ubo));
1290-
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
1291+
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
12911292
}
12921293

12931294
void drawFrame() {

code/28_model_loading.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ class HelloTriangleApplication {
190190

191191
std::vector<VkBuffer> uniformBuffers;
192192
std::vector<VkDeviceMemory> uniformBuffersMemory;
193+
std::vector<void*> uniformBuffersMapped;
193194

194195
VkDescriptorPool descriptorPool;
195196
std::vector<VkDescriptorSet> descriptorSets;
@@ -1074,9 +1075,12 @@ class HelloTriangleApplication {
10741075

10751076
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
10761077
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
1078+
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
10771079

10781080
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
10791081
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
1082+
1083+
vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
10801084
}
10811085
}
10821086

@@ -1330,10 +1334,7 @@ class HelloTriangleApplication {
13301334
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 10.0f);
13311335
ubo.proj[1][1] *= -1;
13321336

1333-
void* data;
1334-
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
1335-
memcpy(data, &ubo, sizeof(ubo));
1336-
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
1337+
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
13371338
}
13381339

13391340
void drawFrame() {

code/29_mipmapping.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ class HelloTriangleApplication {
191191

192192
std::vector<VkBuffer> uniformBuffers;
193193
std::vector<VkDeviceMemory> uniformBuffersMemory;
194+
std::vector<void*> uniformBuffersMapped;
194195

195196
VkDescriptorPool descriptorPool;
196197
std::vector<VkDescriptorSet> descriptorSets;
@@ -1168,9 +1169,12 @@ class HelloTriangleApplication {
11681169

11691170
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
11701171
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
1172+
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
11711173

11721174
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
11731175
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
1176+
1177+
vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
11741178
}
11751179
}
11761180

@@ -1424,10 +1428,7 @@ class HelloTriangleApplication {
14241428
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 10.0f);
14251429
ubo.proj[1][1] *= -1;
14261430

1427-
void* data;
1428-
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
1429-
memcpy(data, &ubo, sizeof(ubo));
1430-
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
1431+
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
14311432
}
14321433

14331434
void drawFrame() {

code/30_multisampling.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ class HelloTriangleApplication {
196196

197197
std::vector<VkBuffer> uniformBuffers;
198198
std::vector<VkDeviceMemory> uniformBuffersMemory;
199+
std::vector<void*> uniformBuffersMapped;
199200

200201
VkDescriptorPool descriptorPool;
201202
std::vector<VkDescriptorSet> descriptorSets;
@@ -1218,9 +1219,12 @@ class HelloTriangleApplication {
12181219

12191220
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
12201221
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
1222+
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
12211223

12221224
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
12231225
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
1226+
1227+
vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
12241228
}
12251229
}
12261230

@@ -1474,10 +1478,7 @@ class HelloTriangleApplication {
14741478
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 10.0f);
14751479
ubo.proj[1][1] *= -1;
14761480

1477-
void* data;
1478-
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
1479-
memcpy(data, &ubo, sizeof(ubo));
1480-
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
1481+
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
14811482
}
14821483

14831484
void drawFrame() {

en/05_Uniform_buffers/00_Descriptor_layout_and_buffer.md

+9-8
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ VkDeviceMemory indexBufferMemory;
243243

244244
std::vector<VkBuffer> uniformBuffers;
245245
std::vector<VkDeviceMemory> uniformBuffersMemory;
246+
std::vector<void*> uniformBuffersMapped;
246247
```
247248

248249
Similarly, create a new function `createUniformBuffers` that is called after
@@ -264,16 +265,19 @@ void createUniformBuffers() {
264265

265266
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
266267
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
268+
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
267269

268270
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
269271
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
272+
273+
vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
270274
}
271275
}
272276
```
273277

274-
We're going to write a separate function that updates the uniform buffer with a
275-
new transformation every frame, so there will be no `vkMapMemory` here. The
276-
uniform data will be used for all draw calls, so the buffer containing it should only be destroyed when we stop rendering.
278+
We map the buffer right after creation using `vkMapMemory` to get a pointer to which we can write the data later on. The buffer stays mapped to this pointer for the application's whole lifetime. This technique is called **"persistent mapping"** and works on all Vulkan implementations. Not having to map the buffer every time we need to update it increases performances, as mapping is not free.
279+
280+
The uniform data will be used for all draw calls, so the buffer containing it should only be destroyed when we stop rendering.
277281

278282
```c++
279283
void cleanup() {
@@ -393,13 +397,10 @@ do this, then the image will be rendered upside down.
393397

394398
All of the transformations are defined now, so we can copy the data in the
395399
uniform buffer object to the current uniform buffer. This happens in exactly the same
396-
way as we did for vertex buffers, except without a staging buffer:
400+
way as we did for vertex buffers, except without a staging buffer. As noted earlier, we only map the uniform buffer once, so we can directly write to it without having to map again:
397401

398402
```c++
399-
void* data;
400-
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
401-
memcpy(data, &ubo, sizeof(ubo));
402-
vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
403+
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
403404
```
404405
405406
Using a UBO this way is not the most efficient way to pass frequently changing

0 commit comments

Comments
 (0)