@@ -174,8 +174,8 @@ All of the descriptor bindings are combined into a single
174174` pipelineLayout ` :
175175
176176``` c++
177- VDeleter< VkDescriptorSetLayout> descriptorSetLayout{device, vkDestroyDescriptorSetLayout} ;
178- VDeleter< VkPipelineLayout > pipelineLayout{device, vkDestroyPipelineLayout} ;
177+ VkDescriptorSetLayout descriptorSetLayout;
178+ VkPipelineLayout pipelineLayout;
179179```
180180
181181We can then create it using ` vkCreateDescriptorSetLayout ` . This function accepts
@@ -187,7 +187,7 @@ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
187187layoutInfo.bindingCount = 1 ;
188188layoutInfo.pBindings = &uboLayoutBinding;
189189
190- if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, descriptorSetLayout.replace() ) != VK_SUCCESS) {
190+ if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr , & descriptorSetLayout) != VK_SUCCESS) {
191191 throw std::runtime_error("failed to create descriptor set layout!");
192192}
193193```
@@ -198,40 +198,50 @@ specified in the pipeline layout object. Modify the `VkPipelineLayoutCreateInfo`
198198to reference the layout object:
199199
200200``` c++
201- VkDescriptorSetLayout setLayouts[] = {descriptorSetLayout};
202201VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
203202pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
204203pipelineLayoutInfo.setLayoutCount = 1 ;
205- pipelineLayoutInfo.pSetLayouts = setLayouts ;
204+ pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout ;
206205```
207206
208207You may be wondering why it's possible to specify multiple descriptor set
209208layouts here, because a single one already includes all of the bindings. We'll
210209get back to that in the next chapter, where we'll look into descriptor pools and
211210descriptor sets.
212211
212+ The descriptor layout should stick around while we may create new graphics
213+ pipelines i.e. until the program ends:
214+
215+ ``` c++
216+ void cleanup () {
217+ cleanupSwapChain ();
218+
219+ vkDestroyDescriptorSetLayout (device, descriptorSetLayout, nullptr);
220+
221+ ...
222+ }
223+ ```
224+
213225## Uniform buffer
214226
215227In the next chapter we'll specify the buffer that contains the UBO data for the
216228shader, but we need to create this buffer first. We're going to copy new data to
217- the uniform buffer every frame, so this time the staging buffer actually needs
218- to stick around.
229+ the uniform buffer every frame, so it doesn't really make any sense to have a
230+ staging buffer. It would just add extra overhead in this case and likely degrade
231+ performance instead of improving it.
219232
220- Add new class members for `uniformStagingBuffer`, `uniformStagingBufferMemory`,
221- `uniformBuffer`, and `uniformBufferMemory`:
233+ Add new class members for ` uniformBuffer ` , and ` uniformBufferMemory ` :
222234
223235``` c++
224- VDeleter< VkBuffer> indexBuffer{device, vkDestroyBuffer} ;
225- VDeleter< VkDeviceMemory> indexBufferMemory{device, vkFreeMemory} ;
236+ VkBuffer indexBuffer;
237+ VkDeviceMemory indexBufferMemory;
226238
227- VDeleter<VkBuffer> uniformStagingBuffer{device, vkDestroyBuffer};
228- VDeleter<VkDeviceMemory> uniformStagingBufferMemory{device, vkFreeMemory};
229- VDeleter<VkBuffer> uniformBuffer{device, vkDestroyBuffer};
230- VDeleter<VkDeviceMemory> uniformBufferMemory{device, vkFreeMemory};
239+ VkBuffer uniformBuffer;
240+ VkDeviceMemory uniformBufferMemory;
231241```
232242
233243Similarly, create a new function ` createUniformBuffer ` that is called after
234- ` createIndexBuffer ` and allocates the buffers :
244+ ` createIndexBuffer ` and allocates the buffer :
235245
236246``` c++
237247void initVulkan () {
@@ -246,15 +256,31 @@ void initVulkan() {
246256
247257void createUniformBuffer () {
248258 VkDeviceSize bufferSize = sizeof(UniformBufferObject);
249-
250- createBuffer (bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformStagingBuffer, uniformStagingBufferMemory);
251- createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, uniformBuffer, uniformBufferMemory);
259+ createBuffer (bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory);
252260}
253261```
254262
255263We're going to write a separate function that updates the uniform buffer with a
256- new transformation every frame, so there will be no ` vkMapMemory ` and
257- ` copyBuffer ` operations here.
264+ new transformation every frame, so there will be no ` vkMapMemory ` here. The
265+ uniform data will be used for all draw calls, so the buffer containing it should
266+ only be destroyed at the end:
267+
268+ ``` c++
269+ void cleanup () {
270+ cleanupSwapChain ();
271+
272+ vkDestroyDescriptorSetLayout (device, descriptorSetLayout, nullptr);
273+ vkDestroyBuffer(device, uniformBuffer, nullptr);
274+ vkFreeMemory(device, uniformBufferMemory, nullptr);
275+
276+ ...
277+ }
278+ ```
279+
280+ ## Updating uniform data
281+
282+ Create a new function ` updateUniformBuffer ` and add a call to it from the main
283+ loop:
258284
259285``` c++
260286void mainLoop () {
@@ -266,8 +292,6 @@ void mainLoop() {
266292 }
267293
268294 vkDeviceWaitIdle (device);
269-
270- glfwDestroyWindow (window);
271295}
272296
273297...
@@ -277,10 +301,7 @@ void updateUniformBuffer() {
277301}
278302```
279303
280- ## Updating uniform data
281-
282- Create a new function ` updateUniformBuffer ` and add a call to it from the main
283- loop. This function will generate a new transformation every frame to make the
304+ This function will generate a new transformation every frame to make the
284305geometry spin around. We need to include two new headers to implement this
285306functionality:
286307
@@ -359,26 +380,23 @@ do this, then the image will be rendered upside down.
359380
360381All of the transformations are defined now, so we can copy the data in the
361382uniform buffer object to the uniform buffer. This happens in exactly the same
362- way as we did for vertex buffers with a staging buffer:
383+ way as we did for vertex buffers, except without a staging buffer:
363384
364385``` c++
365386void * data;
366- vkMapMemory (device, uniformStagingBufferMemory , 0, sizeof(ubo), 0, &data);
387+ vkMapMemory (device, uniformBufferMemory , 0, sizeof(ubo), 0, &data);
367388 memcpy(data, &ubo, sizeof(ubo));
368- vkUnmapMemory(device, uniformStagingBufferMemory);
369-
370- copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(ubo));
389+ vkUnmapMemory(device, uniformBufferMemory);
371390```
372391
373- Using a staging buffer and final buffer this way is not the most efficient way
374- to pass frequently changing values to the shader. A more efficient way to pass a
375- small buffer of data to shaders are *push constants*. We may look at these in a
376- future chapter.
392+ Using a UBO this way is not the most efficient way to pass frequently changing
393+ values to the shader. A more efficient way to pass a small buffer of data to
394+ shaders are *push constants*. We may look at these in a future chapter.
377395
378396In the next chapter we'll look at descriptor sets, which will actually bind the
379397`VkBuffer` to the uniform buffer descriptor so that the shader can access this
380398transformation data.
381399
382400[C++ code](/code/descriptor_layout.cpp) /
383401[Vertex shader](/code/shader_ubo.vert) /
384- [Fragment shader](/code/shader_ubo.frag)
402+ [Fragment shader](/code/shader_ubo.frag)
0 commit comments