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

Skip to content

Commit 72acbd2

Browse files
committed
Update descriptor set creation to have one per swap chain image
1 parent 3e2b63e commit 72acbd2

9 files changed

Lines changed: 302 additions & 260 deletions

05_Uniform_buffers/01_Descriptor_pool_and_sets.md

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
## Introduction
22

33
The descriptor layout from the previous chapter describes the type of
4-
descriptors that can be bound. In this chapter we're going to create a
5-
descriptor set, which will actually specify a `VkBuffer` resource to bind to the
4+
descriptors that can be bound. In this chapter we're going to create
5+
a descriptor set for each `VkBuffer` resource to bind it to the
66
uniform buffer descriptor.
77

88
## Descriptor pool
@@ -50,7 +50,7 @@ We also need to specify the maximum number of descriptor sets that will be
5050
allocated:
5151

5252
```c++
53-
poolInfo.maxSets = 1;
53+
poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size());;
5454
```
5555

5656
The structure has an optional flag similar to command pools that determines if
@@ -85,7 +85,7 @@ void cleanup() {
8585

8686
## Descriptor set
8787

88-
We can now allocate the descriptor set itself. Add a `createDescriptorSet`
88+
We can now allocate the descriptor sets themselves. Add a `createDescriptorSets`
8989
function for that purpose:
9090

9191
```c++
@@ -98,7 +98,7 @@ void initVulkan() {
9898

9999
...
100100

101-
void createDescriptorSet() {
101+
void createDescriptorSets() {
102102

103103
}
104104
```
@@ -108,44 +108,57 @@ struct. You need to specify the descriptor pool to allocate from, the number of
108108
descriptor sets to allocate, and the descriptor layout to base them on:
109109

110110
```c++
111-
VkDescriptorSetLayout layouts[] = {descriptorSetLayout};
111+
std::vector<VkDescriptorSetLayout> layouts(swapChainImages.size(), descriptorSetLayout);
112112
VkDescriptorSetAllocateInfo allocInfo = {};
113113
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
114114
allocInfo.descriptorPool = descriptorPool;
115-
allocInfo.descriptorSetCount = 1;
116-
allocInfo.pSetLayouts = layouts;
115+
allocInfo.descriptorSetCount = static_cast<uint32_t>(swapChainImages.size());
116+
allocInfo.pSetLayouts = layouts.data();
117117
```
118118
119-
Add a class member to hold the descriptor set handle and allocate it with
119+
In our case we will create one descriptor set for each swap chain image, all with the same layout. Unfortunately we do need all the copies of the layout because the next function expects an array matching the number of sets.
120+
121+
Add a class member to hold the descriptor set handles and allocate them with
120122
`vkAllocateDescriptorSets`:
121123
122124
```c++
123125
VkDescriptorPool descriptorPool;
124-
VkDescriptorSet descriptorSet;
126+
std::vector<VkDescriptorSet> descriptorSets;
125127
126128
...
127129
128-
if (vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet) != VK_SUCCESS) {
129-
throw std::runtime_error("failed to allocate descriptor set!");
130+
descriptorSets.resize(swapChainImages.size());
131+
if (vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets[0]) != VK_SUCCESS) {
132+
throw std::runtime_error("failed to allocate descriptor sets!");
130133
}
131134
```
132135

133136
You don't need to explicitly clean up descriptor sets, because they will be
134137
automatically freed when the descriptor pool is destroyed. The call to
135-
`vkAllocateDescriptorSets` will allocate one descriptor set with one uniform
138+
`vkAllocateDescriptorSets` will allocate descriptor sets, each with one uniform
136139
buffer descriptor.
137140

138-
The descriptor set has been allocated now, but the descriptors within still need
139-
to be configured. Descriptors that refer to buffers, like our uniform buffer
141+
The descriptor sets have been allocated now, but the descriptors within still need
142+
to be configured. We'll now add a loop to populate every descriptor:
143+
144+
```c++
145+
for (size_t i = 0; i < swapChainImages.size(); i++) {
146+
147+
}
148+
```
149+
150+
Descriptors that refer to buffers, like our uniform buffer
140151
descriptor, are configured with a `VkDescriptorBufferInfo` struct. This
141152
structure specifies the buffer and the region within it that contains the data
142-
for the descriptor:
153+
for the descriptor.
143154

144155
```c++
145-
VkDescriptorBufferInfo bufferInfo = {};
146-
bufferInfo.buffer = uniformBuffer;
147-
bufferInfo.offset = 0;
148-
bufferInfo.range = sizeof(UniformBufferObject);
156+
for (size_t i = 0; i < swapChainImages.size(); i++) {
157+
VkDescriptorBufferInfo bufferInfo = {};
158+
bufferInfo.buffer = uniformBuffers[i];
159+
bufferInfo.offset = 0;
160+
bufferInfo.range = sizeof(UniformBufferObject);
161+
}
149162
```
150163

151164
If you're overwriting the whole buffer, like we are in this case, then it is is also possible to use the `VK_WHOLE_SIZE` value for the range. The configuration of descriptors is updated using the `vkUpdateDescriptorSets`
@@ -154,7 +167,7 @@ function, which takes an array of `VkWriteDescriptorSet` structs as parameter.
154167
```c++
155168
VkWriteDescriptorSet descriptorWrite = {};
156169
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
157-
descriptorWrite.dstSet = descriptorSet;
170+
descriptorWrite.dstSet = descriptorSets[i];
158171
descriptorWrite.dstBinding = 0;
159172
descriptorWrite.dstArrayElement = 0;
160173
```
@@ -196,14 +209,13 @@ arrays as parameters: an array of `VkWriteDescriptorSet` and an array of
196209
`VkCopyDescriptorSet`. The latter can be used to copy descriptors to each other,
197210
as its name implies.
198211
199-
## Using a descriptor set
212+
## Using descriptor sets
200213
201214
We now need to update the `createCommandBuffers` function to actually bind the
202-
descriptor set to the descriptors in the shader with `cmdBindDescriptorSets`,
203-
this needs to be done before the `vkCmdDrawIndexed` call:
215+
right descriptor set for each swap chain image to the descriptors in the shader with `cmdBindDescriptorSets`. This needs to be done before the `vkCmdDrawIndexed` call:
204216
205217
```c++
206-
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
218+
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);
207219
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
208220
```
209221

@@ -241,7 +253,7 @@ resizing, so we don't need to recreate the descriptor set in
241253
## Multiple descriptor sets
242254

243255
As some of the structures and function calls hinted at, it is actually possible
244-
to bind multiple descriptor sets. You need to specify a descriptor layout for
256+
to bind multiple descriptor sets simultaneously. You need to specify a descriptor layout for
245257
each descriptor set when creating the pipeline layout. Shaders can then
246258
reference specific descriptor sets like this:
247259

@@ -253,6 +265,6 @@ You can use this feature to put descriptors that vary per-object and descriptors
253265
that are shared into separate descriptor sets. In that case you avoid rebinding
254266
most of the descriptors across draw calls which is potentially more efficient.
255267
256-
[C++ code](/code/22_descriptor_set.cpp) /
268+
[C++ code](/code/22_descriptor_sets.cpp) /
257269
[Vertex shader](/code/21_shader_ubo.vert) /
258270
[Fragment shader](/code/21_shader_ubo.frag)

06_Texture_mapping/02_Combined_image_sampler.md

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ the vertex shader, for example to dynamically deform a grid of vertices by a
3939
[heightmap](https://en.wikipedia.org/wiki/Heightmap).
4040
4141
If you would run the application with validation layers now, then you'll see
42-
that it complains that the descriptor pool cannot allocate a descriptor set with
42+
that it complains that the descriptor pool cannot allocate descriptor sets with
4343
this layout, because it doesn't have any combined image sampler descriptors. Go
4444
to the `createDescriptorPool` function and modify it to include a
4545
`VkDescriptorPoolSize` for this descriptor:
@@ -55,17 +55,26 @@ VkDescriptorPoolCreateInfo poolInfo = {};
5555
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
5656
poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
5757
poolInfo.pPoolSizes = poolSizes.data();
58-
poolInfo.maxSets = 1;
58+
poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size());
5959
```
6060

6161
The final step is to bind the actual image and sampler resources to the
62-
descriptor in the descriptor set. Go to the `createDescriptorSet` function.
62+
descriptors in the descriptor set. Go to the `createDescriptorSets` function.
6363

6464
```c++
65-
VkDescriptorImageInfo imageInfo = {};
66-
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
67-
imageInfo.imageView = textureImageView;
68-
imageInfo.sampler = textureSampler;
65+
for (size_t i = 0; i < swapChainImages.size(); i++) {
66+
VkDescriptorBufferInfo bufferInfo = {};
67+
bufferInfo.buffer = uniformBuffers[i];
68+
bufferInfo.offset = 0;
69+
bufferInfo.range = sizeof(UniformBufferObject);
70+
71+
VkDescriptorImageInfo imageInfo = {};
72+
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
73+
imageInfo.imageView = textureImageView;
74+
imageInfo.sampler = textureSampler;
75+
76+
...
77+
}
6978
```
7079

7180
The resources for a combined image sampler structure must be specified in a
@@ -77,15 +86,15 @@ where the objects from the previous chapter come together.
7786
std::array<VkWriteDescriptorSet, 2> descriptorWrites = {};
7887

7988
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
80-
descriptorWrites[0].dstSet = descriptorSet;
89+
descriptorWrites[0].dstSet = descriptorSets[i];
8190
descriptorWrites[0].dstBinding = 0;
8291
descriptorWrites[0].dstArrayElement = 0;
8392
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
8493
descriptorWrites[0].descriptorCount = 1;
8594
descriptorWrites[0].pBufferInfo = &bufferInfo;
8695

8796
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
88-
descriptorWrites[1].dstSet = descriptorSet;
97+
descriptorWrites[1].dstSet = descriptorSets[i];
8998
descriptorWrites[1].dstBinding = 1;
9099
descriptorWrites[1].dstArrayElement = 0;
91100
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
@@ -95,9 +104,9 @@ descriptorWrites[1].pImageInfo = &imageInfo;
95104
vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
96105
```
97106
98-
The descriptor must be updated with this image info, just like the buffer. This
99-
time we're using the `pImageInfo` array instead of `pBufferInfo`. The descriptor
100-
is now ready to be used by the shaders!
107+
The descriptors must be updated with this image info, just like the buffer. This
108+
time we're using the `pImageInfo` array instead of `pBufferInfo`. The descriptors
109+
are now ready to be used by the shaders!
101110
102111
## Texture coordinates
103112
Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ class HelloTriangleApplication {
158158
std::vector<VkDeviceMemory> uniformBuffersMemory;
159159

160160
VkDescriptorPool descriptorPool;
161-
VkDescriptorSet descriptorSet;
161+
std::vector<VkDescriptorSet> descriptorSets;
162162

163163
std::vector<VkCommandBuffer> commandBuffers;
164164

@@ -192,7 +192,7 @@ class HelloTriangleApplication {
192192
createIndexBuffer();
193193
createUniformBuffers();
194194
createDescriptorPool();
195-
createDescriptorSet();
195+
createDescriptorSets();
196196
createCommandBuffers();
197197
createSyncObjects();
198198
}
@@ -751,40 +751,43 @@ class HelloTriangleApplication {
751751
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
752752
poolInfo.poolSizeCount = 1;
753753
poolInfo.pPoolSizes = &poolSize;
754-
poolInfo.maxSets = 1;
754+
poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size());
755755

756756
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
757757
throw std::runtime_error("failed to create descriptor pool!");
758758
}
759759
}
760760

761-
void createDescriptorSet() {
762-
VkDescriptorSetLayout layouts[] = {descriptorSetLayout};
761+
void createDescriptorSets() {
762+
std::vector<VkDescriptorSetLayout> layouts(swapChainImages.size(), descriptorSetLayout);
763763
VkDescriptorSetAllocateInfo allocInfo = {};
764764
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
765765
allocInfo.descriptorPool = descriptorPool;
766-
allocInfo.descriptorSetCount = 1;
767-
allocInfo.pSetLayouts = layouts;
766+
allocInfo.descriptorSetCount = static_cast<uint32_t>(swapChainImages.size());
767+
allocInfo.pSetLayouts = layouts.data();
768768

769-
if (vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet) != VK_SUCCESS) {
770-
throw std::runtime_error("failed to allocate descriptor set!");
769+
descriptorSets.resize(swapChainImages.size());
770+
if (vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets[0]) != VK_SUCCESS) {
771+
throw std::runtime_error("failed to allocate descriptor sets!");
771772
}
772773

773-
VkDescriptorBufferInfo bufferInfo = {};
774-
bufferInfo.buffer = uniformBuffer;
775-
bufferInfo.offset = 0;
776-
bufferInfo.range = sizeof(UniformBufferObject);
777-
778-
VkWriteDescriptorSet descriptorWrite = {};
779-
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
780-
descriptorWrite.dstSet = descriptorSet;
781-
descriptorWrite.dstBinding = 0;
782-
descriptorWrite.dstArrayElement = 0;
783-
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
784-
descriptorWrite.descriptorCount = 1;
785-
descriptorWrite.pBufferInfo = &bufferInfo;
786-
787-
vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
774+
for (size_t i = 0; i < swapChainImages.size(); i++) {
775+
VkDescriptorBufferInfo bufferInfo = {};
776+
bufferInfo.buffer = uniformBuffers[i];
777+
bufferInfo.offset = 0;
778+
bufferInfo.range = sizeof(UniformBufferObject);
779+
780+
VkWriteDescriptorSet descriptorWrite = {};
781+
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
782+
descriptorWrite.dstSet = descriptorSets[i];
783+
descriptorWrite.dstBinding = 0;
784+
descriptorWrite.dstArrayElement = 0;
785+
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
786+
descriptorWrite.descriptorCount = 1;
787+
descriptorWrite.pBufferInfo = &bufferInfo;
788+
789+
vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
790+
}
788791
}
789792

790793
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
@@ -902,7 +905,7 @@ class HelloTriangleApplication {
902905

903906
vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT16);
904907

905-
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
908+
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);
906909

907910
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
908911

0 commit comments

Comments
 (0)