Skip to content

Commit 2f5fefa

Browse files
authored
Remove shit (#577)
* udpates Signed-off-by: Jessie Frazelle <[email protected]> * updates Signed-off-by: Jessie Frazelle <[email protected]> * updates Signed-off-by: Jessie Frazelle <[email protected]> --------- Signed-off-by: Jessie Frazelle <[email protected]>
1 parent 63660c0 commit 2f5fefa

File tree

2 files changed

+604
-630
lines changed

2 files changed

+604
-630
lines changed

content/posts/vulkan-resource-binding-2023.mdx

Lines changed: 22 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@ For our engine, we decided to start by standardizing 3 _Descriptor Set Layouts_
2525

2626
Below are examples of the 3 set bindings in shader code.
2727

28-
<BasicSnippet
29-
lang="cpp"
30-
title="GLSL"
31-
code={`
28+
```cpp
3229
layout(set = 0, binding = 0) uniform Scene
3330
{
3431
mat4 viewProjection;
@@ -51,18 +48,14 @@ layout(set = 2, binding = 0) uniform Draw
5148
mat4 model;
5249
//...
5350
} draw;
54-
`}
55-
/>
51+
```
5652
5753
## One pipeline layout to rule them all
5854
5955
Before the descriptor sets can be bound to a pipeline, they must first be referenced by a _Pipeline Layout_. Pipeline layouts essentially tell the API which descriptor set layouts the shader can expect.
6056
While the per-set-layout bindings are statically defined, standardizing them across the engine frees us to re-use both the descriptor set layouts and the pipeline layout that reference them for most of our common shader collections. Doing this drastically simplifies the engine design. For OpenGL-like implementations, allocating tons of descriptor sets and copying & rewriting the bindings for every draw call is a common practice. The elegant persistent binding method highlighted in the NVIDIA article was far more preferable to us. This means that having maximally flexible descriptor set layouts is a crucial design goal.
6157
62-
<BasicSnippet
63-
lang="cpp"
64-
title="c++"
65-
code={`
58+
```cpp
6659
VkDescriptorSetLayoutCreateInfo createInfo = {};
6760
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
6861

@@ -107,18 +100,15 @@ for(int i = 0; i < 3; i++)
107100
&defaultDSLayouts[i])
108101
);
109102
}
110-
`}/>
103+
```
111104

112105
Note that the usage of "UBO" in various code examples here is a relic of the old OpenGL nomenclature for "Uniform Buffer Object". Essentially "UBO" and "Uniform Buffer" refer to the same concept.
113106

114107
## Descriptor Indexing to the rescue!
115108

116109
Before Vulkan Descriptor Indexing, one had to pre-specify exactly how many texture bindings there could be in a descriptor set. Additionally, each binding had to be set to a valid VkImage resource regardless of whether or not it was used by each shader. This made writing the code for re-usable flexible pipeline layouts both tedious and ugly. Luckily, the Descriptor Indexing feature is core as of Vulkan 1.2. All we have to do is enable the feature during instance creation, and then use it in our code!
117110

118-
<BasicSnippet
119-
lang="cpp"
120-
title="c++"
121-
code={`
111+
```cpp
122112
//...
123113
bindings[1].push_back({
124114
1,
@@ -131,7 +121,7 @@ VkDescriptorBindingFlags bindFlags[] = {
131121
0,
132122
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT
133123
};
134-
bindingsExtInfo[1].sType =
124+
bindingsExtInfo[1].sType =
135125
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO;
136126
bindingsExtInfo[1].bindingCount = (uint32_t)bindings[1].size();
137127
bindingsExtInfo[1].pBindingFlags = bindFlags;
@@ -144,12 +134,9 @@ checkVk(vkCreateDescriptorSetLayout(
144134
nullptr,
145135
&defaultDSLayouts[i])
146136
);
147-
`}/>
137+
```
148138
149-
<BasicSnippet
150-
lang="cpp"
151-
title="c++"
152-
code={`
139+
```cpp
153140
VkWriteDescriptorSet write = {};
154141
VkDescriptorImageInfo imageInfo = {};
155142

@@ -166,31 +153,25 @@ write.descriptorCount = 1;
166153
write.pImageInfo = &imageInfo;
167154

168155
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
169-
`}/>
156+
```
170157
171158
And in our shader:
172159
173-
<BasicSnippet
174-
lang="cpp"
175-
title="GLSL"
176-
code={`
160+
```cpp
177161
#define TEX_NORMAL 0
178162
layout(set = 1, binding = 1) uniform sampler2D textures[];
179163

180164
//...
181165
vec4 encodedNormal = texture(textures[TEX_NORMAL], va_texcoord);
182-
`}/>
166+
```
183167
184168
## Where things live matters
185169
186170
Once our descriptor set layouts, pipeline layouts, and pipelines were set up, we needed to actually allocate our resources on the GPU. For Vulkan, that boils down to whether or not they should live in device-local memory or not. For textures, the question is a no brainer - device-local memory is more efficient for the GPU to access during sampling. For buffers, the answer becomes less cut and dry. Device-local memory requires a copy from host-visible (CPU) memory to update. This update usually requires recording a command buffer to execute the transfer for you. On the other hand, host-visible memory, as its name implies, can be directly updated from the host (with some coherency and caching caveats that may need to be considered). The general rule is, if the resource is updated infrequently and accessed repeatedly from a shader, device-local is the way to go. Otherwise, host-visible is usually a better option.
187171
188172
For our engine, we decided to go with device-local scene uniform buffers (updated once per frame), device-local material uniform buffers (updated during scene initialization), and host-visible per-draw uniform buffers.
189173
190-
<BasicSnippet
191-
lang="cpp"
192-
title="c++"
193-
code={`
174+
```cpp
194175
sceneUbo = make_unique<Buffer>(
195176
device,
196177
gfxQueue,
@@ -209,32 +190,28 @@ drawUbo = make_unique<Buffer>(
209190
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
210191
VMA_MEMORY_USAGE_AUTO_PREFER_HOST
211192
);
212-
`}/>
193+
```
213194
214195
## Dynamic Draw call UBOs
215196
216197
The last consideration we made was to employ an old solution to an old problem. Updating draw UBOs in Vulkan is quite different compared to higher level APIs such as OpenGL. In Vulkan, you cannot change a resource that is currently being utilized by an in-flight command buffer. This means, that if we draw 100 objects in a single frame, we would need to maintain memory for and perform updates on 100 separate drawUbo buffers. This quickly becomes unruly as scene complexity grows. Thus, we opted to go with dynamic uniform buffers to solve this problem. Dynamic UBOs essentially allow us to map one large host visible buffer and copy each buffer into it and grow it as we draw our frame. This method works well for most dynamic scenes with lots of draws.
217198
218199
Going back to our descriptor set layout init:
219200
220-
<BasicSnippet
221-
lang="cpp"
222-
title="c++"
223-
code={`//Model/draw-call UBO (set 2)
201+
```cpp
202+
//Model/draw-call UBO (set 2)
224203
bindings[2].push_back({
225204
0,
226205
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
227206
1,
228207
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
229208
nullptr
230-
});`}/>
209+
});
210+
```
231211
232212
and our buffer init:
233213
234-
<BasicSnippet
235-
lang="cpp"
236-
title="c++"
237-
code={`
214+
```cpp
238215
drawUbo = make_unique<Buffer>(
239216
device,
240217
gfxQueue,
@@ -245,14 +222,11 @@ drawUbo->setPersistentlyMapped(true);
245222

246223
//1<<20 is a fancy-way to specify 1 MB of memory
247224
drawUbo->createBuffer(1<<20);
248-
`}/>
225+
```
249226
250227
now, we can populate the data each frame:
251228
252-
<BasicSnippet
253-
lang="cpp"
254-
title="c++"
255-
code={`
229+
```cpp
256230
void updateDynamicUBO(
257231
const void \*data,
258232
size_t len,
@@ -267,7 +241,7 @@ void updateDynamicUBO(
267241
//make sure we haven't ran off the end of the dynamic UBO
268242
if(uboOffset+alignedLen < ubo->getSize())
269243
{
270-
uint8_t *uboHostData =
244+
uint8_t *uboHostData =
271245
(uint8_t *)drawUbo->getPersistentlyMappedData();
272246
memcpy(uboHostData+uboOffset, data, len);
273247

@@ -279,7 +253,7 @@ void updateDynamicUBO(
279253
}
280254

281255
}
282-
`}/>
256+
```
283257
284258
## Bringing it all back to earth
285259

0 commit comments

Comments
 (0)