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