Skip to content

Commit 1f2d1cc

Browse files
committed
Add Imageless Framebuffer
1 parent e149ed5 commit 1f2d1cc

File tree

12 files changed

+976
-16
lines changed

12 files changed

+976
-16
lines changed

docs/codes/04/20_imageless/App.cppm

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
export module App;
2+
3+
import std;
4+
import glfw;
5+
import vulkan_hpp;
6+
7+
import DataLoader;
8+
import Context;
9+
import Window;
10+
import Device;
11+
import Swapchain;
12+
import DepthImage;
13+
import RenderPass;
14+
import GraphicsPipeline;
15+
import CommandPool;
16+
import InputAssembly;
17+
import UniformBuffer;
18+
import TextureSampler;
19+
import Descriptor;
20+
import Drawer;
21+
22+
export namespace vht {
23+
class App {
24+
std::shared_ptr<vht::DataLoader> m_data_loader{ nullptr };
25+
std::shared_ptr<vht::Context> m_context{ nullptr };
26+
std::shared_ptr<vht::Window> m_window{ nullptr };
27+
std::shared_ptr<vht::Device> m_device{ nullptr };
28+
std::shared_ptr<vht::Swapchain> m_swapchain{ nullptr };
29+
std::shared_ptr<vht::DepthImage> m_depth_image{ nullptr };
30+
std::shared_ptr<vht::RenderPass> m_render_pass{ nullptr };
31+
std::shared_ptr<vht::GraphicsPipeline> m_graphics_pipeline{ nullptr };
32+
std::shared_ptr<vht::CommandPool> m_command_pool{ nullptr };
33+
std::shared_ptr<vht::InputAssembly> m_input_assembly{ nullptr };
34+
std::shared_ptr<vht::UniformBuffer> m_uniform_buffer{ nullptr };
35+
std::shared_ptr<vht::TextureSampler> m_texture_sampler{ nullptr };
36+
std::shared_ptr<vht::Descriptor> m_descriptor{ nullptr };
37+
std::shared_ptr<vht::Drawer> m_drawer{ nullptr };
38+
public:
39+
void run() {
40+
init();
41+
while (!glfw::window_should_close(m_window->ptr())) {
42+
glfw::poll_events();
43+
m_drawer->draw();
44+
}
45+
std::println("device waitIdle");
46+
m_device->device().waitIdle();
47+
std::println("finished");
48+
}
49+
private:
50+
void init() {
51+
init_data_loader();
52+
init_context();
53+
init_window();
54+
std::println("window created");
55+
init_device();
56+
std::println("device created");
57+
init_swapchain();
58+
std::println("swapchain created");
59+
init_depth_image();
60+
std::println("depth image created");
61+
init_render_pass();
62+
std::println("render pass created");
63+
init_graphics_pipeline();
64+
std::println("graphics pipeline created");
65+
init_command_pool();
66+
std::println("command pool created");
67+
init_uniform_buffer();
68+
std::println("uniform buffer created");
69+
init_texture_sampler();
70+
std::println("texture sampler created");
71+
init_input_assembly();
72+
std::println("input assembly created");
73+
init_descriptor();
74+
std::println("descriptor created");
75+
init_drawer();
76+
std::println("drawer created");
77+
}
78+
void init_data_loader() { m_data_loader = std::make_shared<vht::DataLoader>(); }
79+
void init_context() { m_context = std::make_shared<vht::Context>( true ); }
80+
void init_window() { m_window = std::make_shared<vht::Window>( m_context ); }
81+
void init_device() { m_device = std::make_shared<vht::Device>( m_context, m_window ); }
82+
void init_swapchain() { m_swapchain = std::make_shared<vht::Swapchain>( m_window, m_device ); }
83+
void init_depth_image() { m_depth_image = std::make_shared<vht::DepthImage>( m_device, m_swapchain ); }
84+
void init_render_pass() { m_render_pass = std::make_shared<vht::RenderPass>( m_window, m_device, m_swapchain, m_depth_image ); }
85+
void init_graphics_pipeline() { m_graphics_pipeline = std::make_shared<vht::GraphicsPipeline>( m_device, m_render_pass ); }
86+
void init_command_pool() { m_command_pool = std::make_shared<vht::CommandPool>( m_device ); }
87+
void init_input_assembly() { m_input_assembly = std::make_shared<vht::InputAssembly>( m_data_loader, m_device, m_command_pool ); }
88+
void init_uniform_buffer() { m_uniform_buffer = std::make_shared<vht::UniformBuffer>( m_window, m_device, m_swapchain ); }
89+
void init_texture_sampler() { m_texture_sampler = std::make_shared<vht::TextureSampler>( m_device, m_command_pool ); }
90+
void init_descriptor() { m_descriptor = std::make_shared<vht::Descriptor>( m_device, m_graphics_pipeline, m_uniform_buffer, m_texture_sampler ); }
91+
void init_drawer() {
92+
m_drawer = std::make_shared<vht::Drawer>(
93+
m_data_loader,
94+
m_window,
95+
m_device,
96+
m_swapchain,
97+
m_depth_image,
98+
m_render_pass,
99+
m_graphics_pipeline,
100+
m_command_pool,
101+
m_input_assembly,
102+
m_uniform_buffer,
103+
m_descriptor
104+
);
105+
}
106+
};
107+
}

docs/codes/04/20_imageless/App.diff

796 Bytes
Binary file not shown.
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
export module Device;
2+
3+
import std;
4+
import vulkan_hpp;
5+
6+
import Context;
7+
import Window;
8+
9+
constexpr std::array<const char*, 1> DEVICE_EXTENSIONS { vk::KHRSwapchainExtensionName };
10+
11+
export namespace vht {
12+
/**
13+
* @brief 队列族索引
14+
* @details
15+
* - graphics_family: 图形队列族索引
16+
* - present_family: 呈现队列族索引
17+
* - is_complete(): 检查是否已找到所需的队列族索引
18+
*/
19+
struct QueueFamilyIndices {
20+
std::optional<std::uint32_t> graphics_family;
21+
std::optional<std::uint32_t> present_family;
22+
[[nodiscard]]
23+
bool is_complete() const {
24+
return graphics_family.has_value() && present_family.has_value();
25+
}
26+
};
27+
28+
/**
29+
* @brief 交换链支持的详细信息
30+
* @details
31+
* - capabilities: 交换链的能力
32+
* - formats: 支持的表面格式
33+
* - present_modes: 支持的呈现模式
34+
*/
35+
struct SwapchainSupportDetails {
36+
vk::SurfaceCapabilitiesKHR capabilities;
37+
std::vector<vk::SurfaceFormatKHR> formats;
38+
std::vector<vk::PresentModeKHR> present_modes;
39+
};
40+
/**
41+
* @brief 设备相关
42+
* @details
43+
* - 依赖:
44+
* - m_context: Vulkan上下文
45+
* - m_window: 窗口相关
46+
* - 工作:
47+
* - 选择合适的物理设备
48+
* - 创建逻辑设备和队列
49+
* - 可访问成员:
50+
* - physical_device(): 获取物理设备
51+
* - device(): 获取逻辑设备
52+
* - graphics_queue(): 获取图形队列
53+
* - present_queue(): 获取呈现队列
54+
* - swapchain_support(): 获取交换链支持的详细信息
55+
* - queue_family_indices(): 获取队列族索引
56+
*/
57+
class Device {
58+
std::shared_ptr<vht::Context> m_context{ nullptr };
59+
std::shared_ptr<vht::Window> m_window{ nullptr };
60+
vk::raii::PhysicalDevice m_physical_device{ nullptr };
61+
vk::raii::Device m_device{ nullptr };
62+
QueueFamilyIndices m_queue_family_indices{};
63+
vk::raii::Queue m_graphics_queue{ nullptr };
64+
vk::raii::Queue m_present_queue{ nullptr };
65+
public:
66+
explicit Device(std::shared_ptr<vht::Context> context, std::shared_ptr<vht::Window> window)
67+
: m_context(std::move(context)),
68+
m_window(std::move(window)) {
69+
pick_physical_device();
70+
create_device();
71+
}
72+
73+
[[nodiscard]]
74+
const vk::raii::PhysicalDevice& physical_device() const { return m_physical_device; }
75+
[[nodiscard]]
76+
const vk::raii::Device& device() const { return m_device; }
77+
[[nodiscard]]
78+
const vk::raii::Queue& graphics_queue() const { return m_graphics_queue; }
79+
[[nodiscard]]
80+
const vk::raii::Queue& present_queue() const { return m_present_queue; }
81+
[[nodiscard]]
82+
SwapchainSupportDetails swapchain_support() const { return query_swapchain_support(m_physical_device); }
83+
[[nodiscard]]
84+
QueueFamilyIndices queue_family_indices() const { return m_queue_family_indices; }
85+
private:
86+
/**
87+
* @brief 挑选物理设备
88+
*/
89+
void pick_physical_device() {
90+
const auto physical_devices = m_context->instance().enumeratePhysicalDevices();
91+
if (physical_devices.empty()) throw std::runtime_error("failed to enumerate physical devices");
92+
for (const auto& it : physical_devices) {
93+
if (is_device_suitable(it)) {
94+
m_physical_device = it;
95+
return;
96+
}
97+
}
98+
throw std::runtime_error("failed to get physical device");
99+
}
100+
101+
/**
102+
* @brief 判断物理设备是否可用
103+
* @param physical_device 物理设备
104+
* @return bool 是否适合使用
105+
*/
106+
[[nodiscard]]
107+
bool is_device_suitable(const vk::raii::PhysicalDevice& physical_device) const {
108+
// 检查是否支持交换链扩展
109+
std::set<std::string> extension_set( DEVICE_EXTENSIONS.begin(), DEVICE_EXTENSIONS.end() );
110+
for (const auto& it : physical_device.enumerateDeviceExtensionProperties()) {
111+
extension_set.erase(it.extensionName);
112+
}
113+
if (!extension_set.empty()) return false;
114+
// 交换链格式支持
115+
if (const auto supports = query_swapchain_support(physical_device);
116+
supports.formats.empty() || supports.present_modes.empty()
117+
) return false;
118+
// 队列族支持
119+
const auto indices = find_queue_families(physical_device);
120+
return indices.is_complete();
121+
}
122+
123+
/**
124+
* @brief 获取交换链支持的详细信息
125+
* @param physical_device 物理设备
126+
* @return 交换链支持的详细信息
127+
*/
128+
[[nodiscard]]
129+
SwapchainSupportDetails query_swapchain_support(const vk::raii::PhysicalDevice& physical_device) const {
130+
return {
131+
physical_device.getSurfaceCapabilitiesKHR( m_window->surface() ),
132+
physical_device.getSurfaceFormatsKHR( m_window->surface() ),
133+
physical_device.getSurfacePresentModesKHR( m_window->surface() )
134+
};
135+
}
136+
137+
/**
138+
* @brief 查询需要的队列族索引
139+
* @param physical_device 物理设备
140+
* @return QueueFamilyIndices 队列族索引
141+
*/
142+
[[nodiscard]]
143+
QueueFamilyIndices find_queue_families(const vk::raii::PhysicalDevice& physical_device) const {
144+
QueueFamilyIndices indices{};
145+
const auto queue_families = physical_device.getQueueFamilyProperties();
146+
for (std::uint32_t i = 0; const auto& queue_family : queue_families) {
147+
if (queue_family.queueFlags & vk::QueueFlagBits::eGraphics) {
148+
indices.graphics_family = i;
149+
}
150+
if(physical_device.getSurfaceSupportKHR(i, m_window->surface())){
151+
indices.present_family = i;
152+
}
153+
if (indices.is_complete()) break;
154+
++i;
155+
}
156+
return indices;
157+
}
158+
159+
/**
160+
* @brief 创建逻辑设备与队列
161+
*/
162+
void create_device() {
163+
// 已在物理设备创建时保证内容不为空
164+
m_queue_family_indices = find_queue_families(m_physical_device);
165+
const auto [graphics_family, present_family] = m_queue_family_indices;
166+
167+
std::set<std::uint32_t> unique_queue_families { graphics_family.value(), present_family.value() };
168+
169+
std::vector<vk::DeviceQueueCreateInfo> queue_create_infos;
170+
queue_create_infos.reserve(unique_queue_families.size());
171+
float queue_priority = 1.0f;
172+
for (const std::uint32_t queue_family : unique_queue_families) {
173+
vk::DeviceQueueCreateInfo queue_create_info;
174+
queue_create_info.queueFamilyIndex = queue_family;
175+
queue_create_info.setQueuePriorities( queue_priority );
176+
queue_create_infos.emplace_back( queue_create_info );
177+
}
178+
179+
vk::StructureChain<
180+
vk::DeviceCreateInfo,
181+
vk::PhysicalDeviceFeatures2,
182+
vk::PhysicalDeviceVulkan11Features,
183+
vk::PhysicalDeviceVulkan12Features,
184+
vk::PhysicalDeviceVulkan13Features
185+
> device_create_info;
186+
187+
device_create_info.get()
188+
.setQueueCreateInfos( queue_create_infos )
189+
.setPEnabledExtensionNames( DEVICE_EXTENSIONS );
190+
device_create_info.get<vk::PhysicalDeviceFeatures2>().features
191+
.setSamplerAnisotropy( true );
192+
device_create_info.get<vk::PhysicalDeviceVulkan12Features>()
193+
.setTimelineSemaphore( true )
194+
.setImagelessFramebuffer( true );
195+
device_create_info.get<vk::PhysicalDeviceVulkan13Features>()
196+
.setSynchronization2( true );
197+
198+
m_device = m_physical_device.createDevice( device_create_info.get() );
199+
m_graphics_queue = m_device.getQueue( graphics_family.value(), 0 );
200+
m_present_queue = m_device.getQueue( present_family.value(), 0 );
201+
}
202+
203+
};
204+
}
205+
1.29 KB
Binary file not shown.

0 commit comments

Comments
 (0)