Skip to content

Commit 5849101

Browse files
committed
Add more comments, fixup indents in guide
1 parent eb96b6c commit 5849101

File tree

5 files changed

+97
-88
lines changed

5 files changed

+97
-88
lines changed

guide/src/rendering/dynamic_rendering.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ attachment_info.setImageView(render_target->image_view)
7373
.setImageLayout(vk::ImageLayout::eAttachmentOptimal)
7474
.setLoadOp(vk::AttachmentLoadOp::eClear)
7575
.setStoreOp(vk::AttachmentStoreOp::eStore)
76+
// temporarily red.
7677
.setClearValue(vk::ClearColorValue{1.0f, 0.0f, 0.0f, 1.0f});
7778
```
7879

guide/src/rendering/render_sync.md

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,62 +14,62 @@ using Buffered = std::array<Type, buffering_v>;
1414
Add a private `struct RenderSync` to `App`:
1515
1616
```cpp
17-
struct RenderSync {
18-
// signaled when Swapchain image has been acquired.
19-
vk::UniqueSemaphore draw{};
20-
// signaled when image is ready to be presented.
21-
vk::UniqueSemaphore present{};
22-
// signaled with present Semaphore, waited on before next render.
23-
vk::UniqueFence drawn{};
24-
// used to record rendering commands.
25-
vk::CommandBuffer command_buffer{};
26-
};
17+
struct RenderSync {
18+
// signaled when Swapchain image has been acquired.
19+
vk::UniqueSemaphore draw{};
20+
// signaled when image is ready to be presented.
21+
vk::UniqueSemaphore present{};
22+
// signaled with present Semaphore, waited on before next render.
23+
vk::UniqueFence drawn{};
24+
// used to record rendering commands.
25+
vk::CommandBuffer command_buffer{};
26+
};
2727
```
2828

2929
Add the new members associated with the Swapchain loop:
3030

3131
```cpp
32-
// command pool for all render Command Buffers.
33-
vk::UniqueCommandPool m_render_cmd_pool{};
34-
// Sync and Command Buffer for virtual frames.
35-
Buffered<RenderSync> m_render_sync{};
36-
// Current virtual frame index.
37-
std::size_t m_frame_index{};
32+
// command pool for all render Command Buffers.
33+
vk::UniqueCommandPool m_render_cmd_pool{};
34+
// Sync and Command Buffer for virtual frames.
35+
Buffered<RenderSync> m_render_sync{};
36+
// Current virtual frame index.
37+
std::size_t m_frame_index{};
3838
```
3939

4040
Add, implement, and call the create function:
4141

4242
```cpp
4343
void App::create_render_sync() {
44-
// Command Buffers are 'allocated' from a Command Pool (which is 'created'
45-
// like all other Vulkan objects so far). We can allocate all the buffers
46-
// from a single pool here.
47-
auto command_pool_ci = vk::CommandPoolCreateInfo{};
48-
// this flag enables resetting the command buffer for re-recording (unlike a
49-
// single-time submit scenario).
50-
command_pool_ci.setFlags(vk::CommandPoolCreateFlagBits::eResetCommandBuffer)
51-
.setQueueFamilyIndex(m_gpu.queue_family);
52-
m_render_cmd_pool = m_device->createCommandPoolUnique(command_pool_ci);
44+
// Command Buffers are 'allocated' from a Command Pool (which is 'created'
45+
// like all other Vulkan objects so far). We can allocate all the buffers
46+
// from a single pool here.
47+
auto command_pool_ci = vk::CommandPoolCreateInfo{};
48+
// this flag enables resetting the command buffer for re-recording (unlike a
49+
// single-time submit scenario).
50+
command_pool_ci.setFlags(vk::CommandPoolCreateFlagBits::eResetCommandBuffer)
51+
.setQueueFamilyIndex(m_gpu.queue_family);
52+
m_render_cmd_pool = m_device->createCommandPoolUnique(command_pool_ci);
5353

54-
auto command_buffer_ai = vk::CommandBufferAllocateInfo{};
55-
command_buffer_ai.setCommandPool(*m_render_cmd_pool)
56-
.setCommandBufferCount(static_cast<std::uint32_t>(resource_buffering_v))
57-
.setLevel(vk::CommandBufferLevel::ePrimary);
58-
auto const command_buffers =
59-
m_device->allocateCommandBuffers(command_buffer_ai);
60-
assert(command_buffers.size() == m_render_sync.size());
54+
auto command_buffer_ai = vk::CommandBufferAllocateInfo{};
55+
command_buffer_ai.setCommandPool(*m_render_cmd_pool)
56+
.setCommandBufferCount(static_cast<std::uint32_t>(resource_buffering_v))
57+
.setLevel(vk::CommandBufferLevel::ePrimary);
58+
auto const command_buffers =
59+
m_device->allocateCommandBuffers(command_buffer_ai);
60+
assert(command_buffers.size() == m_render_sync.size());
6161

62-
// we create Render Fences as pre-signaled so that on the first render for
63-
// each virtual frame we don't wait on their fences (since there's nothing
64-
// to wait for yet).
65-
static constexpr auto fence_create_info_v =
66-
vk::FenceCreateInfo{vk::FenceCreateFlagBits::eSignaled};
67-
for (auto [sync, command_buffer] :
68-
std::views::zip(m_render_sync, command_buffers)) {
69-
sync.command_buffer = command_buffer;
70-
sync.draw = m_device->createSemaphoreUnique({});
71-
sync.present = m_device->createSemaphoreUnique({});
72-
sync.drawn = m_device->createFenceUnique(fence_create_info_v);
73-
}
62+
// we create Render Fences as pre-signaled so that on the first render for
63+
// each virtual frame we don't wait on their fences (since there's nothing
64+
// to wait for yet).
65+
static constexpr auto fence_create_info_v =
66+
vk::FenceCreateInfo{vk::FenceCreateFlagBits::eSignaled};
67+
for (auto [sync, command_buffer] :
68+
std::views::zip(m_render_sync, command_buffers)) {
69+
sync.command_buffer = command_buffer;
70+
sync.draw = m_device->createSemaphoreUnique({});
71+
sync.present = m_device->createSemaphoreUnique({});
72+
sync.drawn = m_device->createFenceUnique(fence_create_info_v);
73+
}
7474
}
7575
```

guide/src/rendering/swapchain_update.md

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@ Expressing as a helper function in `swapchain.cpp`:
1111

1212
```cpp
1313
auto needs_recreation(vk::Result const result) -> bool {
14-
switch (result) {
15-
case vk::Result::eSuccess:
16-
case vk::Result::eSuboptimalKHR: return false;
17-
case vk::Result::eErrorOutOfDateKHR: return true;
18-
default: break;
19-
}
20-
throw std::runtime_error{"Swapchain Error"};
14+
switch (result) {
15+
case vk::Result::eSuccess:
16+
case vk::Result::eSuboptimalKHR: return false;
17+
case vk::Result::eErrorOutOfDateKHR: return true;
18+
default: break;
19+
}
20+
throw std::runtime_error{"Swapchain Error"};
2121
}
2222
```
2323
2424
We also want to return the Image, Image View, and size upon successful acquisition of the underlying Swapchain Image. Wrapping those in a `struct`:
2525
2626
```cpp
2727
struct RenderTarget {
28-
vk::Image image{};
29-
vk::ImageView image_view{};
30-
vk::Extent2D extent{};
28+
vk::Image image{};
29+
vk::ImageView image_view{};
30+
vk::Extent2D extent{};
3131
};
3232
```
3333

@@ -37,58 +37,62 @@ Implementing the acquire operation:
3737

3838
```cpp
3939
auto Swapchain::acquire_next_image(vk::Semaphore const to_signal)
40-
-> std::optional<RenderTarget> {
41-
assert(!m_image_index);
42-
static constexpr auto timeout_v = std::numeric_limits<std::uint64_t>::max();
43-
auto image_index = std::uint32_t{};
44-
auto const result = m_device.acquireNextImageKHR(
45-
*m_swapchain, timeout_v, to_signal, {}, &image_index);
46-
if (needs_recreation(result)) { return {}; }
40+
-> std::optional<RenderTarget> {
41+
assert(!m_image_index);
42+
static constexpr auto timeout_v = std::numeric_limits<std::uint64_t>::max();
43+
// avoid VulkanHPP ErrorOutOfDateKHR exceptions by using alternate API that
44+
// returns a Result.
45+
auto image_index = std::uint32_t{};
46+
auto const result = m_device.acquireNextImageKHR(
47+
*m_swapchain, timeout_v, to_signal, {}, &image_index);
48+
if (needs_recreation(result)) { return {}; }
4749

48-
m_image_index = static_cast<std::size_t>(image_index);
49-
return RenderTarget{
50-
.image = m_images.at(*m_image_index),
51-
.image_view = *m_image_views.at(*m_image_index),
52-
.extent = m_ci.imageExtent,
53-
};
50+
m_image_index = static_cast<std::size_t>(image_index);
51+
return RenderTarget{
52+
.image = m_images.at(*m_image_index),
53+
.image_view = *m_image_views.at(*m_image_index),
54+
.extent = m_ci.imageExtent,
55+
};
5456
}
5557
```
5658
5759
Similarly, present:
5860
5961
```cpp
6062
auto Swapchain::present(vk::Queue const queue, vk::Semaphore const to_wait)
61-
-> bool {
62-
auto const image_index = static_cast<std::uint32_t>(m_image_index.value());
63-
auto present_info = vk::PresentInfoKHR{};
64-
present_info.setSwapchains(*m_swapchain)
65-
.setImageIndices(image_index)
66-
.setWaitSemaphores(to_wait);
67-
auto const result = queue.presentKHR(&present_info);
68-
m_image_index.reset();
69-
return !needs_recreation(result);
63+
-> bool {
64+
auto const image_index = static_cast<std::uint32_t>(m_image_index.value());
65+
auto present_info = vk::PresentInfoKHR{};
66+
present_info.setSwapchains(*m_swapchain)
67+
.setImageIndices(image_index)
68+
.setWaitSemaphores(to_wait);
69+
// avoid VulkanHPP ErrorOutOfDateKHR exceptions by using alternate API.
70+
auto const result = queue.presentKHR(&present_info);
71+
m_image_index.reset();
72+
return !needs_recreation(result);
7073
}
7174
```
7275

7376
It is the responsibility of the user (`class App`) to recreate the Swapchain on receiving `std::nullopt` / `false` return values for either operation. Users will also need to transition the layouts of the returned images between acquire and present operations. Add a helper to assist in that process, and extract the Image Subresource Range out as a common constant:
7477

7578
```cpp
7679
constexpr auto subresource_range_v = [] {
77-
auto ret = vk::ImageSubresourceRange{};
78-
ret.setAspectMask(vk::ImageAspectFlagBits::eColor)
79-
.setLayerCount(1)
80-
.setLevelCount(1);
81-
return ret;
80+
auto ret = vk::ImageSubresourceRange{};
81+
// this is a color image with 1 layer and 1 mip-level (the default).
82+
ret.setAspectMask(vk::ImageAspectFlagBits::eColor)
83+
.setLayerCount(1)
84+
.setLevelCount(1);
85+
return ret;
8286
}();
8387

8488
// ...
8589
auto Swapchain::base_barrier() const -> vk::ImageMemoryBarrier2 {
86-
// fill up the parts common to all barriers.
87-
auto ret = vk::ImageMemoryBarrier2{};
88-
ret.setImage(m_images.at(m_image_index.value()))
89-
.setSubresourceRange(subresource_range_v)
90-
.setSrcQueueFamilyIndex(m_gpu.queue_family)
91-
.setDstQueueFamilyIndex(m_gpu.queue_family);
92-
return ret;
90+
// fill up the parts common to all barriers.
91+
auto ret = vk::ImageMemoryBarrier2{};
92+
ret.setImage(m_images.at(m_image_index.value()))
93+
.setSubresourceRange(subresource_range_v)
94+
.setSrcQueueFamilyIndex(m_gpu.queue_family)
95+
.setDstQueueFamilyIndex(m_gpu.queue_family);
96+
return ret;
9397
}
9498
```

src/app.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ void App::main_loop() {
193193
.setImageLayout(vk::ImageLayout::eAttachmentOptimal)
194194
.setLoadOp(vk::AttachmentLoadOp::eClear)
195195
.setStoreOp(vk::AttachmentStoreOp::eStore)
196+
// temporarily red.
196197
.setClearValue(vk::ClearColorValue{1.0f, 0.0f, 0.0f, 1.0f});
197198
auto rendering_info = vk::RenderingInfo{};
198199
auto const render_area =

src/swapchain.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ auto Swapchain::acquire_next_image(vk::Semaphore const to_signal)
130130
-> std::optional<RenderTarget> {
131131
assert(!m_image_index);
132132
static constexpr auto timeout_v = std::numeric_limits<std::uint64_t>::max();
133+
// avoid VulkanHPP ErrorOutOfDateKHR exceptions by using alternate API that
134+
// returns a Result.
133135
auto image_index = std::uint32_t{};
134136
auto const result = m_device.acquireNextImageKHR(
135137
*m_swapchain, timeout_v, to_signal, {}, &image_index);
@@ -160,6 +162,7 @@ auto Swapchain::present(vk::Queue const queue, vk::Semaphore const to_wait)
160162
present_info.setSwapchains(*m_swapchain)
161163
.setImageIndices(image_index)
162164
.setWaitSemaphores(to_wait);
165+
// avoid VulkanHPP ErrorOutOfDateKHR exceptions by using alternate API.
163166
auto const result = queue.presentKHR(&present_info);
164167
m_image_index.reset();
165168
return !needs_recreation(result);

0 commit comments

Comments
 (0)