Skip to content

Commit 7cf450e

Browse files
committed
Align docu in 00_Framebuffers.adoc and 01_Command_buffers.adoc to the sources in 14_command_buffers.cpp
1 parent cf1a148 commit 7cf450e

2 files changed

Lines changed: 93 additions & 95 deletions

File tree

en/03_Drawing_a_triangle/03_Drawing/00_Framebuffers.adoc

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ In the next chapter, we'll create command buffers and record rendering commands.
2121

2222
[,c++]
2323
----
24-
void recordCommandBuffer(uint32_t imageIndex) {
24+
void recordCommandBuffer(uint32_t imageIndex)
25+
{
2526
commandBuffer.begin({});
2627
2728
// Transition the image layout for rendering
@@ -38,20 +39,18 @@ void recordCommandBuffer(uint32_t imageIndex) {
3839
// Set up the color attachment
3940
vk::ClearValue clearColor = vk::ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f);
4041
vk::RenderingAttachmentInfo attachmentInfo = {
41-
.imageView = swapChainImageViews[imageIndex],
42-
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
43-
.loadOp = vk::AttachmentLoadOp::eClear,
44-
.storeOp = vk::AttachmentStoreOp::eStore,
45-
.clearValue = clearColor
46-
};
42+
.imageView = swapChainImageViews[imageIndex],
43+
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
44+
.loadOp = vk::AttachmentLoadOp::eClear,
45+
.storeOp = vk::AttachmentStoreOp::eStore,
46+
.clearValue = clearColor};
4747
4848
// Set up the rendering info
4949
vk::RenderingInfo renderingInfo = {
50-
.renderArea = { .offset = { 0, 0 }, .extent = swapChainExtent },
51-
.layerCount = 1,
52-
.colorAttachmentCount = 1,
53-
.pColorAttachments = &attachmentInfo
54-
};
50+
.renderArea = {.offset = {0, 0}, .extent = swapChainExtent},
51+
.layerCount = 1,
52+
.colorAttachmentCount = 1,
53+
.pColorAttachments = &attachmentInfo};
5554
5655
// Begin rendering
5756
commandBuffer.beginRendering(renderingInfo);

en/03_Drawing_a_triangle/03_Drawing/01_Command_buffers.adoc

Lines changed: 82 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ In addition, this allows command recording to happen in multiple threads if so d
1313

1414
We have to create a command pool before we can create command buffers.
1515
Command pools manage the memory that is used to store the buffers and command buffers are allocated from them.
16-
Add a new class member to store a `VkCommandPool`:
16+
Add a new class member to store a `vk::raii::CommandPool`:
1717

1818
[,c++]
1919
----
@@ -24,7 +24,8 @@ Then create a new function `createCommandPool` and call it from `initVulkan` aft
2424

2525
[,c++]
2626
----
27-
void initVulkan() {
27+
void initVulkan()
28+
{
2829
createInstance();
2930
setupDebugMessenger();
3031
createSurface();
@@ -38,25 +39,26 @@ void initVulkan() {
3839
3940
...
4041
41-
void createCommandPool() {
42-
42+
void createCommandPool()
43+
{
4344
}
4445
----
4546

4647
Command pool creation only takes two parameters:
4748

4849
[,c++]
4950
----
50-
vk::CommandPoolCreateInfo poolInfo{ .flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer, .queueFamilyIndex = graphicsIndex };
51+
vk::CommandPoolCreateInfo poolInfo{.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
52+
.queueFamilyIndex = queueIndex};
5153
----
5254

5355
There are two possible flags for command pools:
5456

55-
* `VK_COMMAND_POOL_CREATE_TRANSIENT_BIT`: Hint that command buffers are rerecorded with new commands very often (may change memory allocation behavior)
56-
* `VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT`: Allow command buffers to be rerecorded individually, without this flag they all have to be reset together
57+
* `vk::CommandPoolCreateFlagBits::eTransient`: Hint that command buffers are rerecorded with new commands very often (may change memory allocation behavior)
58+
* `vk::CommandPoolCreateFlagBits::eResetCommandBuffer`: Allow command buffers to be rerecorded individually, without this flag they all have to be reset together
5759

5860
We will be recording a command buffer every frame, so we want to be able to reset and rerecord over it.
59-
Thus, we need to set the `VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT` flag bit for our command pool.
61+
Thus, we need to set the `vk::CommandPoolCreateFlagBits::eResetCommandBuffer` flag bit for our command pool.
6062

6163
Command buffers are executed by submitting them on one of the device queues, like the graphics and presentation queues we retrieved.
6264
Each command pool can only allocate command buffers that are submitted on a single type of queue.
@@ -67,15 +69,15 @@ We're going to record commands for drawing, which is why we've chosen the graphi
6769
commandPool = vk::raii::CommandPool(device, poolInfo);
6870
----
6971

70-
Finish creating the command pool using the `vkCreateCommandPool` function.
72+
Finish creating the command pool using the `vk::raii::CommandPool` constructor.
7173
It doesn't have any special parameters.
7274
Commands will be used throughout the program to draw things on the screen.
7375

7476
== Command buffer allocation
7577

7678
We can now start allocating command buffers.
7779

78-
Create a `VkCommandBuffer` object as a class member.
80+
Create a `vk::raii::CommandBuffer` object as a class member.
7981
Command buffers will be automatically freed when their command pool is destroyed, so we don't need explicit cleanup.
8082

8183
[,c++]
@@ -87,7 +89,8 @@ We'll now start working on a `createCommandBuffer` function to allocate a single
8789

8890
[,c++]
8991
----
90-
void initVulkan() {
92+
void initVulkan()
93+
{
9194
createInstance();
9295
setupDebugMessenger();
9396
createSurface();
@@ -102,12 +105,12 @@ void initVulkan() {
102105
103106
...
104107
105-
void createCommandBuffer() {
106-
108+
void createCommandBuffer()
109+
{
107110
}
108111
----
109112

110-
Command buffers are allocated with the `vkAllocateCommandBuffers` function, which takes a `VkCommandBufferAllocateInfo` struct as parameter that specifies the command pool and number of buffers to allocate:
113+
Command buffers are allocated with the `vk::raii::CommandBuffers` constructor, which takes a `vk::CommandBufferAllocateInfo` struct as parameter that specifies the command pool and number of buffers to allocate:
111114

112115
[,c++]
113116
----
@@ -118,87 +121,85 @@ commandBuffer = std::move(vk::raii::CommandBuffers(device, allocInfo).front());
118121

119122
The `level` parameter specifies if the allocated command buffers are primary or secondary command buffers.
120123

121-
* `VK_COMMAND_BUFFER_LEVEL_PRIMARY`: Can be submitted to a queue for execution, but cannot be called from other command buffers.
122-
* `VK_COMMAND_BUFFER_LEVEL_SECONDARY`: Cannot be submitted directly, but can be called from primary command buffers.
124+
* `vk::CommandBufferLevel::ePrimary`: Can be submitted to a queue for execution, but cannot be called from other command buffers.
125+
* `vk::CommandBufferLevel::eSecondary`: Cannot be submitted directly, but can be called from primary command buffers.
123126

124127
We won't make use of the secondary command buffer functionality here, but you can imagine that it's helpful to reuse common operations from primary command buffers.
125128

126129
Since we are only allocating one command buffer, the `commandBufferCount` parameter is just one.
130+
The `vk::raii::CommandBuffers` constructor generates a `std::vector<vk::raii::CommandBuffer>`, but we just want a single one here, so we move it out of that vector into a singular variable.
127131

128132
== Command buffer recording
129133

130134
We'll now start working on the `recordCommandBuffer` function that writes the commands we want to execute into a command buffer.
131-
The `VkCommandBuffer` used will be passed in as a parameter, as well as the index of the current swapchain image we want to write to.
135+
The `vk::raii::CommandBuffer` used will be passed in as a parameter, as well as the index of the current swapchain image we want to write to.
132136

133137
[,c++]
134138
----
135-
void recordCommandBuffer(uint32_t imageIndex) {
136-
139+
void recordCommandBuffer(uint32_t imageIndex)
140+
{
137141
}
138142
----
139143

140-
We always begin recording a command buffer by calling `vkBeginCommandBuffer` with a small `VkCommandBufferBeginInfo` structure as argument that specifies some details about the usage of this specific command buffer.
144+
We always begin recording a command buffer by calling `vk::raii::CommandBuffer::begin` with a small `vk::CommandBufferBeginInfo` structure as argument that specifies some details about the usage of this specific command buffer.
141145

142146
[,c++]
143147
----
144-
commandBuffer->begin( {} );
148+
commandBuffer->begin({});
145149
----
146150

147-
The `flags` parameter specifies how we're going to use the command buffer.
151+
The `flags` member of the `vk::CommandBufferBeginInfo` specifies how we're going to use the command buffer.
148152
The following values are available:
149153

150-
* `VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT`: The command buffer will be rerecorded right after executing it once.
151-
* `VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT`: This is a secondary command buffer that will be entirely within a single render pass.
152-
* `VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT`: The command buffer can be resubmitted while it is also already pending execution.
154+
* `vk::CommandBufferUsageFlagBits::eOneTimeSubmit`: The command buffer will be rerecorded right after executing it once.
155+
* `vk::CommandBufferUsageFlagBits::eRenderPassContinue`: This is a secondary command buffer that will be entirely within a single render pass.
156+
* `vk::CommandBufferUsageFlagBits::eSimultaneousUse`: The command buffer can be resubmitted while it is also already pending execution.
153157

154158
None of these flags are applicable for us right now.
155159

156-
The `pInheritanceInfo` parameter is only relevant for secondary command buffers.
160+
The `pInheritanceInfo` member of the `vk::CommandBufferBeginInfo` is only relevant for secondary command buffers.
157161
It specifies which state to inherit from the calling primary command buffers.
158162

159-
If the command buffer was already recorded once, then a call to `vkBeginCommandBuffer` will implicitly reset it.
163+
If the command buffer was already recorded once, then a call to `vk::raii::CommandBuffer::begin` will implicitly reset it.
160164
It's not possible to append commands to a buffer at a later time.
161165

162166
== Image layout transitions
163167

164168
Before we can start rendering to an image, we need to transition its layout to one that is suitable for rendering. In Vulkan, images can be in different layouts that are optimized for different operations. For example, an image can be in a layout that is optimal for presenting to the screen, or in a layout that is optimal for being used as a color attachment.
165169

166-
We'll use a pipeline barrier to transition the image layout from `VK_IMAGE_LAYOUT_UNDEFINED` to `VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL`:
170+
We'll use a pipeline barrier to transition the image layout from `vk::ImageLayout::eUndefined` to `vk::ImageLayout::eColorAttachmentOptimal`:
167171

168172
[,c++]
169173
----
170174
void transition_image_layout(
171-
uint32_t imageIndex,
172-
vk::ImageLayout oldLayout,
173-
vk::ImageLayout newLayout,
174-
vk::AccessFlags2 srcAccessMask,
175-
vk::AccessFlags2 dstAccessMask,
176-
vk::PipelineStageFlags2 srcStageMask,
177-
vk::PipelineStageFlags2 dstStageMask
178-
) {
179-
vk::ImageMemoryBarrier2 barrier = {
180-
.srcStageMask = srcStageMask,
181-
.srcAccessMask = srcAccessMask,
182-
.dstStageMask = dstStageMask,
183-
.dstAccessMask = dstAccessMask,
184-
.oldLayout = oldLayout,
185-
.newLayout = newLayout,
186-
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
187-
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
188-
.image = swapChainImages[imageIndex],
189-
.subresourceRange = {
190-
.aspectMask = vk::ImageAspectFlagBits::eColor,
191-
.baseMipLevel = 0,
192-
.levelCount = 1,
193-
.baseArrayLayer = 0,
194-
.layerCount = 1
195-
}
196-
};
197-
vk::DependencyInfo dependencyInfo = {
198-
.dependencyFlags = {},
199-
.imageMemoryBarrierCount = 1,
200-
.pImageMemoryBarriers = &barrier
201-
};
175+
uint32_t imageIndex,
176+
vk::ImageLayout old_layout,
177+
vk::ImageLayout new_layout,
178+
vk::AccessFlags2 src_access_mask,
179+
vk::AccessFlags2 dst_access_mask,
180+
vk::PipelineStageFlags2 src_stage_mask,
181+
vk::PipelineStageFlags2 dst_stage_mask)
182+
{
183+
vk::ImageMemoryBarrier2 barrier = {
184+
.srcStageMask = src_stage_mask,
185+
.srcAccessMask = src_access_mask,
186+
.dstStageMask = dst_stage_mask,
187+
.dstAccessMask = dst_access_mask,
188+
.oldLayout = old_layout,
189+
.newLayout = new_layout,
190+
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
191+
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
192+
.image = swapChainImages[imageIndex],
193+
.subresourceRange = {
194+
.aspectMask = vk::ImageAspectFlagBits::eColor,
195+
.baseMipLevel = 0,
196+
.levelCount = 1,
197+
.baseArrayLayer = 0,
198+
.layerCount = 1}};
199+
vk::DependencyInfo dependency_info = {
200+
.dependencyFlags = {},
201+
.imageMemoryBarrierCount = 1,
202+
.pImageMemoryBarriers = &barrier};
202203
commandBuffer.pipelineBarrier2(dependencyInfo);
203204
}
204205
----
@@ -211,44 +212,42 @@ With dynamic rendering, we don't need to create a render pass or framebuffers. I
211212

212213
[,c++]
213214
----
214-
// Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL
215+
// Before starting rendering, transition the swapchain image to vk::ImageLayout::eColorAttachmentOptimal
215216
transition_image_layout(
216217
imageIndex,
217218
vk::ImageLayout::eUndefined,
218219
vk::ImageLayout::eColorAttachmentOptimal,
219-
{}, // srcAccessMask (no need to wait for previous operations)
220-
vk::AccessFlagBits2::eColorAttachmentWrite, // dstAccessMask
221-
vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage
222-
vk::PipelineStageFlagBits2::eColorAttachmentOutput // dstStage
220+
{}, // srcAccessMask (no need to wait for previous operations)
221+
vk::AccessFlagBits2::eColorAttachmentWrite, // dstAccessMask
222+
vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage
223+
vk::PipelineStageFlagBits2::eColorAttachmentOutput // dstStage
223224
);
224225
----
225226

226-
First, we transition the image layout to `VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL`. Then, we set up the color attachment:
227+
First, we transition the image layout to `vk::ImageLayout::eColorAttachmentOptimal`. Then, we set up the color attachment:
227228

228229
[,c++]
229230
----
230-
vk::ClearValue clearColor = vk::ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f);
231+
vk::ClearValue clearColor = vk::ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f);
231232
vk::RenderingAttachmentInfo attachmentInfo = {
232-
.imageView = swapChainImageViews[imageIndex],
233+
.imageView = swapChainImageViews[imageIndex],
233234
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
234-
.loadOp = vk::AttachmentLoadOp::eClear,
235-
.storeOp = vk::AttachmentStoreOp::eStore,
236-
.clearValue = clearColor
237-
};
235+
.loadOp = vk::AttachmentLoadOp::eClear,
236+
.storeOp = vk::AttachmentStoreOp::eStore,
237+
.clearValue = clearColor};
238238
----
239239

240-
The `imageView` parameter specifies which image view to render to. The `imageLayout` parameter specifies the layout the image will be in during rendering. The `loadOp` parameter specifies what to do with the image before rendering, and the `storeOp` parameter specifies what to do with the image after rendering. We're using `VK_ATTACHMENT_LOAD_OP_CLEAR` to clear the image to black before rendering, and `VK_ATTACHMENT_STORE_OP_STORE` to store the rendered image for later use.
240+
The `imageView` parameter specifies which image view to render to. The `imageLayout` parameter specifies the layout the image will be in during rendering. The `loadOp` parameter specifies what to do with the image before rendering, and the `storeOp` parameter specifies what to do with the image after rendering. We're using `VK_ATTACHMENT_LOAD_OP_CLEAR` to clear the image to black before rendering, and `vk::AttachmentStoreOp::eStore` to store the rendered image for later use.
241241

242242
Next, we set up the rendering info:
243243

244244
[,c++]
245245
----
246246
vk::RenderingInfo renderingInfo = {
247-
.renderArea = { .offset = { 0, 0 }, .extent = swapChainExtent },
248-
.layerCount = 1,
247+
.renderArea = {.offset = {0, 0}, .extent = swapChainExtent},
248+
.layerCount = 1,
249249
.colorAttachmentCount = 1,
250-
.pColorAttachments = &attachmentInfo
251-
};
250+
.pColorAttachments = &attachmentInfo};
252251
----
253252

254253
The `renderArea` parameter defines the size of the render area, similar to the render area in a render pass. The `layerCount` parameter specifies the number of layers to render to, which is 1 for a non-layered image. The `colorAttachmentCount` and `pColorAttachments` parameters specify the color attachments to render to.
@@ -260,7 +259,7 @@ Now we can begin rendering:
260259
commandBuffer.beginRendering(renderingInfo);
261260
----
262261

263-
All the functions that record commands can be recognized by their `vkCmd` prefix. They all return `void`, so there will be no error handling until we've finished recording.
262+
All the functions that record commands return `void`, so there will be no error handling until we've finished recording.
264263

265264
The parameter for the `beginRendering` command is the rendering info we just set up, which specifies the attachments to render to and the render area.
266265

@@ -270,13 +269,13 @@ We can now bind the graphics pipeline:
270269

271270
[,c++]
272271
----
273-
commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, graphicsPipeline);
272+
commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline);
274273
----
275274

276275
The first parameter specifies if the pipeline object is a graphics or compute pipeline.
277276
We've now told Vulkan which operations to execute in the graphics pipeline and which attachment to use in the fragment shader.
278277

279-
As noted in the link:../02_Graphics_pipeline_basics/02_Fixed_functions.md#dynamic-state[fixed functions chapter], we did specify viewport and scissor state for this pipeline to be dynamic.
278+
As noted in the link:../02_Graphics_pipeline_basics/02_Fixed_functions.md#dynamic-state[fixed functions chapter], we did specify viewport and scissor state for this pipeline to be dynamic.
280279
So we need to set them in the command buffer before issuing our draw command:
281280

282281
[,c++]
@@ -292,8 +291,8 @@ Now we are ready to issue the draw command for the triangle:
292291
commandBuffer.draw(3, 1, 0, 0);
293292
----
294293

295-
The actual `vkCmdDraw` function is a bit anticlimactic, but it's so simple because of all the information we specified in advance.
296-
It has the following parameters, aside from the command buffer:
294+
The actual `vk::raii::CommandBuffer::draw` function is a bit anticlimactic, but it's so simple because of all the information we specified in advance.
295+
It has the following parameters:
297296

298297
* `vertexCount`: Even though we don't have a vertex buffer, we technically still have 3 vertices to draw.
299298
* `instanceCount`: Used for instanced rendering, use `1` if you're not doing that.
@@ -309,11 +308,11 @@ The rendering can now be ended:
309308
commandBuffer.endRendering();
310309
----
311310

312-
After rendering, we need to transition the image layout back to `VK_IMAGE_LAYOUT_PRESENT_SRC_KHR` so it can be presented to the screen:
311+
After rendering, we need to transition the image layout back to `vk::ImageLayout::ePresentSrcKHR` so it can be presented to the screen:
313312

314313
[,c++]
315314
----
316-
// After rendering, transition the swapchain image to PRESENT_SRC
315+
// After rendering, transition the swapchain image to vk::ImageLayout::ePresentSrcKHR
317316
transition_image_layout(
318317
imageIndex,
319318
vk::ImageLayout::eColorAttachmentOptimal,

0 commit comments

Comments
 (0)