Skip to content

Commit 10c6019

Browse files
committed
WIP
1 parent 5a220f3 commit 10c6019

File tree

8 files changed

+40
-0
lines changed

8 files changed

+40
-0
lines changed

guide/src/SUMMARY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@
1616
- [Vulkan Device](initialization/device.md)
1717
- [Scoped Waiter](initialization/scoped_waiter.md)
1818
- [Swapchain](initialization/swapchain.md)
19+
- [Rendering](rendering/README.md)
20+
- [Swapchain Loop](rendering/swapchain_loop.md)
21+
- [Render Sync](rendering/render_sync.md)

guide/src/rendering/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Rendering
2+
3+
This section implements the Swapchain loop, integrates Dear ImGui, and introduces Dynamic Rendering.

guide/src/rendering/render_sync.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Render Sync
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Swapchain Loop
2+
3+
One part of rendering in the main loop is the Swapchain loop, which at a high level comprises of these steps:
4+
5+
1. Acquire a Swapchain Image (and its view)
6+
1. Render to the acquired Image
7+
1. Present the Image (this releases the image back to the Swapchain)
8+
9+
![WSI Engine](./wsi_engine.png)
10+
11+
There are a few nuances to deal with, for instance:
12+
13+
1. Acquiring (and/or presenting) will sometimes fail (eg because the Swapchain is out of date), in which case the remaining steps need to be skipped
14+
1. The acquire command can return before the image is actually ready for use, rendering needs to be synchronized to only start after the image is ready
15+
1. The images need appropriate Layout Transitions at each stage
16+
17+
Additionally, the number of swapchain images can vary, whereas the engine should use a fixed number of _virtual frames_: 2 for double buffering, 3 for triple (more is usually overkill). It's also possible for the main loop to acquire the same image before a previous render command has finished (or even started), if the Swapchain is using Mailbox Present Mode. While FIFO will block until the oldest submitted image is available (also known as vsync), we should still synchronize and wait until the acquired image has finished rendering.
18+
19+
## Virtual Frames
20+
21+
All the dynamic resources used during the rendering of a frame comprise a virtual frame. The application has a fixed number of virtual frames which it cycles through on each render pass. Each frame will be associated with a `vk::Fence` which will be waited on before rendering to it again. It will also have a pair of `vk::Semaphore`s to synchronize the acquire, render, and present calls on the GPU (we don't need to wait for them in the code). Lastly, there will be a Command Buffer per virtual frame, where all rendering commands for that frame (including layout transitions) will be recorded.
22+
23+
## Image Layouts
24+
25+
Vulkan Images have a property known as Image Layout. Most operations on images require them to be in certain specific layouts, requiring transitions before (and after). A layout transition conveniently also functions as a Pipeline Barrier (think memory barrier on the GPU), enabling us to synchronize operations before and after the transition.
26+
27+
Vulkan Synchronization is arguably the most complicated aspect of the API, a good amount of research is recommended. Here is an [article explaining barriers](https://gpuopen.com/learn/vulkan-barriers-explained/).

guide/src/rendering/wsi_engine.png

40.5 KB
Loading

src/app.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,11 @@ void App::create_swapchain() {
9191
}
9292

9393
void App::main_loop() {
94+
auto count = 0;
9495
while (glfwWindowShouldClose(m_window.get()) == GLFW_FALSE) {
9596
glfwPollEvents();
97+
if (++count > 500) { break; }
98+
std::this_thread::sleep_for(std::chrono::milliseconds{10});
9699
}
97100
}
98101
} // namespace lvk

src/swapchain.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ auto Swapchain::recreate(glm::ivec2 size) -> bool {
9090

9191
m_device.waitIdle();
9292
m_swapchain = m_device.createSwapchainKHRUnique(m_ci);
93+
m_image_index.reset();
9394

9495
populate_images();
9596
create_image_views();

src/swapchain.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22
#include <glm/vec2.hpp>
33
#include <gpu.hpp>
4+
#include <optional>
45
#include <vector>
56

67
namespace lvk {
@@ -26,5 +27,6 @@ class Swapchain {
2627
vk::UniqueSwapchainKHR m_swapchain{};
2728
std::vector<vk::Image> m_images{};
2829
std::vector<vk::UniqueImageView> m_image_views{};
30+
std::optional<std::size_t> m_image_index{};
2931
};
3032
} // namespace lvk

0 commit comments

Comments
 (0)