sandbox
Loading...
Searching...
No Matches
graphics_module.hpp
1#ifndef LIBSBX_GRAPHICS_GRAPHICS_MODULE_HPP_
2#define LIBSBX_GRAPHICS_GRAPHICS_MODULE_HPP_
3
4#include <memory>
5#include <unordered_map>
6#include <vector>
7#include <typeindex>
8
9#include <libsbx/core/module.hpp>
11
12#include <libsbx/math/uuid.hpp>
13
14#include <libsbx/devices/devices_module.hpp>
15
17#include <libsbx/utility/concepts.hpp>
18
19#include <libsbx/signals/signal.hpp>
20
21#include <libsbx/graphics/devices/instance.hpp>
22#include <libsbx/graphics/devices/physical_device.hpp>
23#include <libsbx/graphics/devices/logical_device.hpp>
24#include <libsbx/graphics/devices/allocator.hpp>
25#include <libsbx/graphics/devices/surface.hpp>
26
27#include <libsbx/graphics/commands/command_pool.hpp>
28#include <libsbx/graphics/commands/command_buffer.hpp>
29
30#include <libsbx/graphics/render_pass/swapchain.hpp>
31
32#include <libsbx/graphics/pipeline/pipeline.hpp>
33#include <libsbx/graphics/pipeline/shader.hpp>
34#include <libsbx/graphics/pipeline/graphics_pipeline.hpp>
35#include <libsbx/graphics/pipeline/compute_pipeline.hpp>
36#include <libsbx/graphics/pipeline/compiler.hpp>
37
38#include <libsbx/graphics/buffers/buffer.hpp>
39#include <libsbx/graphics/buffers/storage_buffer.hpp>
40
41#include <libsbx/graphics/images/image2d.hpp>
42#include <libsbx/graphics/images/cube_image.hpp>
43
44#include <libsbx/graphics/renderer.hpp>
45
46#include <libsbx/graphics/resource_storage.hpp>
47
48namespace sbx::graphics {
49
55auto validate(VkResult result) -> void;
56
57template<typename VkEnum, typename Enum>
58requires ((std::is_enum_v<VkEnum> || std::is_same_v<VkEnum, VkFlags>) && std::is_enum_v<Enum>)
59constexpr auto to_vk_enum(Enum value) -> VkEnum {
60 return static_cast<VkEnum>(value);
61}
62
68class graphics_module final : public core::module<graphics_module> {
69
70 inline static const auto is_registered = register_module(stage::rendering, dependencies<devices::devices_module>{});
71
72 inline static constexpr auto max_deletion_queue_size = std::size_t{16u};
73
74public:
75
77
78 ~graphics_module() override;
79
80 auto update() -> void override;
81
82 auto instance() -> instance&;
83
85
87
88 auto surface() -> surface&;
89
90 auto command_pool(VkQueueFlagBits queue_type = VK_QUEUE_GRAPHICS_BIT, const std::thread::id& thread_id = std::this_thread::get_id()) -> const std::shared_ptr<command_pool>&;
91
92 auto swapchain() -> swapchain&;
93
94 template<utility::implements<renderer> Renderer, typename... Args>
95 requires (std::is_constructible_v<Renderer, Args...>)
96 auto set_renderer(Args&&... args) -> void {
97 _renderer = std::make_unique<Renderer>(std::forward<Args>(args)...);
98 _recreate_swapchain();
99 }
100
101 // auto render_stage(const pipeline::stage& stage) -> graphics::render_stage&;
102
103 auto current_frame() const noexcept -> std::uint32_t {
104 return _current_frame;
105 }
106
107 auto attachment(const std::string& name) const -> const descriptor&;
108
109 template<typename Type, typename... Args>
110 requires (std::is_constructible_v<Type, Args...>)
111 auto add_resource(Args&&... args) -> resource_handle<Type> {
112 return _storage<Type>().emplace(std::forward<Args>(args)...);
113 }
114
115 template<typename Type>
116 auto get_resource(const resource_handle<Type>& handle) -> Type& {
117 return _storage<Type>().get(handle);
118 }
119
120 template<typename Type>
121 auto get_resource(const resource_handle<Type>& handle) const -> const Type& {
122 return _storage<Type>().get(handle);
123 }
124
125 template<typename Type>
126 auto remove_resource(const resource_handle<Type>& handle) -> void {
127 return _storage<Type>().remove(handle);
128 }
129
130 auto allocator() const noexcept -> const graphics::allocator& {
131 return _allocator;
132 }
133
134 template<queue::type Source, queue::type Destination, typename Type>
135 requires (std::is_same_v<Type, graphics::buffer> || std::is_same_v<Type, graphics::storage_buffer>)
136 auto transfer_ownership(const resource_handle<Type>& handle, const VkPipelineStageFlagBits2 stage = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT) -> void {
137 auto& buffer = get_resource<Type>(handle);
138
139 _release_ownership_data.push_back(command_buffer::release_ownership_data{
140 .src_stage_mask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
141 .src_access_mask = VK_ACCESS_2_SHADER_WRITE_BIT,
142 .src_queue_family = _logical_device->queue<Source>().family(),
143 .dst_queue_family = _logical_device->queue<Destination>().family(),
144 .buffer = buffer
145 });
146
147 _acquire_ownership_data.push_back(command_buffer::acquire_ownership_data{
148 .dst_stage_mask = stage,
149 .dst_access_mask = _access_mask_from_stage(stage),
150 .src_queue_family = _logical_device->queue<Source>().family(),
151 .dst_queue_family = _logical_device->queue<Destination>().family(),
152 .buffer = buffer
153 });
154 }
155
156 template<typename Callable>
157 requires (std::is_invocable_r_v<math::vector2u, Callable>)
158 auto set_dynamic_size_callback(Callable&& callback) -> void {
159 _dynamic_size_callback = std::forward<Callable>(callback);
160 }
161
162 auto dynamic_viewport() const -> const math::vector2u& {
163 return _viewport;
164 }
165
166 auto on_viewport_changed() -> signals::signal<const math::vector2u&>& {
167 return _on_viewport_changed;
168 }
169
170 auto compiler() -> graphics::compiler& {
171 return _compiler;
172 }
173
174private:
175
176 static constexpr auto _access_mask_from_stage(VkPipelineStageFlagBits2 stage) -> VkAccessFlagBits2 {
177 switch (stage) {
178 case VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT: {
179 return VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT;
180 }
181 case VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT:
182 case VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT:
183 case VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT:
184 case VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT:
185 case VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT: {
186 return VK_ACCESS_2_SHADER_READ_BIT;
187 }
188 case VK_PIPELINE_STAGE_2_TRANSFER_BIT: {
189 return VK_ACCESS_2_TRANSFER_READ_BIT;
190 }
191 default: {
192 return VK_ACCESS_2_MEMORY_READ_BIT;
193 }
194 }
195 }
196
197 // auto _start_render_pass(const utility::hashed_string& pass, graphics::command_buffer& command_buffer) -> void;
198
199 // auto _end_render_pass(const utility::hashed_string& pass, graphics::command_buffer& command_buffer) -> void;
200
201 auto _reset_render_stages() -> void;
202
203 auto _recreate_viewport() -> void;
204
205 auto _recreate_swapchain() -> void;
206
207 auto _recreate_per_frame_data() -> void;
208
209 auto _recreate_per_image_data() -> void;
210
211 auto _recreate_command_buffers() -> void;
212
213 auto _recreate_attachments() -> void;
214
215 struct per_frame_data {
216 // graphics
217 VkSemaphore image_available_semaphore{};
218 VkFence graphics_in_flight_fence{};
219 // compute
220 VkSemaphore compute_finished_semaphore{};
221 VkFence compute_in_flight_fence{};
222 }; // struct per_frame_data
223
224 struct per_image_data {
225 VkSemaphore render_finished_semaphore{};
226 }; // struct per_image_data
227
228 struct command_pool_key {
229 VkQueueFlagBits queue_type;
230 std::thread::id thread_id;
231 }; // struct command_pool_key
232
233 struct command_pool_key_hash {
234 auto operator()(const command_pool_key& key) const noexcept -> std::size_t {
235 auto hast = std::size_t{0};
236 utility::hash_combine(hast, key.queue_type, key.thread_id);
237 return hast;
238 }
239 }; // struct command_pool_key_hash
240
241 struct command_pool_key_equality {
242 auto operator()(const command_pool_key& lhs, const command_pool_key& rhs) const noexcept -> bool {
243 return lhs.queue_type == rhs.queue_type && lhs.thread_id == rhs.thread_id;
244 }
245 }; // struct command_pool_key_equal
246
247
248 static_assert(std::is_class_v<graphics::graphics_pipeline>, "graphics_pipeline is not a class in sbx::graphics");
249
250 template<typename Type>
251 auto _storage() -> resource_storage<Type>& {
252 if constexpr (std::is_same_v<Type, shader>) {
253 return _shaders;
254 } else if constexpr (std::is_same_v<Type, graphics_pipeline>) {
255 return _graphics_pipelines;
256 } else if constexpr (std::is_same_v<Type, compute_pipeline>) {
257 return _compute_pipelines;
258 } else if constexpr (std::is_same_v<Type, buffer>) {
259 return _buffers;
260 } else if constexpr (std::is_same_v<Type, storage_buffer>) {
261 return _storage_buffers;
262 } else if constexpr (std::is_same_v<Type, uniform_buffer>) {
263 return _uniform_buffers;
264 } if constexpr (std::is_same_v<Type, image2d>) {
265 return _images;
266 } else if constexpr (std::is_same_v<Type, depth_image>) {
267 return _depth_images;
268 } else if constexpr (std::is_same_v<Type, cube_image>) {
269 return _cube_images;
270 }
271
272 utility::assert_that(false, "Invalid resource type");
273 }
274
275 template<typename Type>
276 auto _storage() const -> const resource_storage<Type>& {
277 if constexpr (std::is_same_v<Type, shader>) {
278 return _shaders;
279 } else if constexpr (std::is_same_v<Type, graphics_pipeline>) {
280 return _graphics_pipelines;
281 } else if constexpr (std::is_same_v<Type, compute_pipeline>) {
282 return _compute_pipelines;
283 } else if constexpr (std::is_same_v<Type, buffer>) {
284 return _buffers;
285 } else if constexpr (std::is_same_v<Type, storage_buffer>) {
286 return _storage_buffers;
287 } else if constexpr (std::is_same_v<Type, uniform_buffer>) {
288 return _uniform_buffers;
289 } if constexpr (std::is_same_v<Type, image2d>) {
290 return _images;
291 } else if constexpr (std::is_same_v<Type, depth_image>) {
292 return _depth_images;
293 } else if constexpr (std::is_same_v<Type, cube_image>) {
294 return _cube_images;
295 }
296
297 utility::assert_that(false, "Invalid resource type");
298 }
299
300 std::unique_ptr<graphics::instance> _instance{};
301 std::unique_ptr<graphics::physical_device> _physical_device{};
302 std::unique_ptr<graphics::logical_device> _logical_device{};
303
304 std::unordered_map<command_pool_key, std::shared_ptr<graphics::command_pool>, command_pool_key_hash, command_pool_key_equality> _command_pools{};
305
306 std::map<std::string, memory::observer_ptr<const descriptor>> _attachments{};
307
308 std::unique_ptr<graphics::surface> _surface{};
309
310 std::unique_ptr<graphics::swapchain> _swapchain{};
311
312 std::vector<per_frame_data> _per_frame_data{};
313 std::vector<per_image_data> _per_image_data{};
314 std::vector<graphics::command_buffer> _graphics_command_buffers{};
315 std::vector<graphics::command_buffer> _compute_command_buffers{};
316
317 std::unique_ptr<graphics::renderer> _renderer{};
318
328
329 graphics::allocator _allocator;
330
331 graphics::compiler _compiler;
332
333 std::vector<command_buffer::acquire_ownership_data> _acquire_ownership_data;
334 std::vector<command_buffer::release_ownership_data> _release_ownership_data;
335
336 std::uint32_t _current_frame{};
337 bool _is_framebuffer_resized{};
338 bool _is_viewport_resized{};
339
340 math::vector2u _viewport{};
341
342 signals::signal<const math::vector2u&> _on_viewport_changed;
343
344 core::delegate<math::vector2u()> _dynamic_size_callback;
345
346}; // class graphics_module
347
348} // namespace sbx::graphics
349
350#endif // LIBSBX_GRAPHICS_GRAPHICS_MODULE_HPP_
Definition: delegate.hpp:55
Definition: module.hpp:90
Definition: allocator.hpp:12
Definition: render_graph.hpp:103
Definition: buffer.hpp:20
Definition: command_pool.hpp:12
Definition: compiler.hpp:18
Definition: descriptor.hpp:37
Module for managing rendering specific tasks.
Definition: graphics_module.hpp:68
Definition: instance.hpp:10
Definition: logical_device.hpp:60
Definition: physical_device.hpp:16
Definition: resource_storage.hpp:17
Definition: resource_storage.hpp:67
Definition: surface.hpp:14
Definition: swapchain.hpp:12
A vector in two-dimensional space.
Definition: vector2.hpp:27
Definition: signal.hpp:16