sandbox
Loading...
Searching...
No Matches
renderer.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_GRAPHICS_RENDERER_HPP_
3#define LIBSBX_GRAPHICS_RENDERER_HPP_
4
5#include <memory>
6#include <vector>
7#include <typeindex>
8
9#include <easy/profiler.h>
10
11#include <libsbx/utility/noncopyable.hpp>
12#include <libsbx/utility/concepts.hpp>
14#include <libsbx/utility/type_id.hpp>
15#include <libsbx/utility/type_name.hpp>
16
17#include <libsbx/graphics/commands/command_buffer.hpp>
18
19#include <libsbx/graphics/pipeline/pipeline.hpp>
20
21#include <libsbx/graphics/task.hpp>
22#include <libsbx/graphics/subrenderer.hpp>
23#include <libsbx/graphics/render_graph.hpp>
24#include <libsbx/graphics/draw_list.hpp>
25#include <libsbx/graphics/viewport.hpp>
26
27namespace sbx::graphics {
28
29namespace detail {
30
32
33} // namespace detail
34
40template<typename Type>
42
44
45public:
46
47 renderer() = default;
48
49 virtual ~renderer() = default;
50
51 auto render(command_buffer& command_buffer, const swapchain& swapchain) -> void {
52 for (auto& [key, draw_list] : _draw_lists) {
53 draw_list->clear();
54 draw_list->update();
55 }
56
57 auto compute_callback = [this, &command_buffer](const pass_handle& pass) -> void {
58 if (pass.index >= _tasks.size()) {
59 return;
60 }
61
62 for (const auto& task : _tasks[pass.index]) {
63 task->execute(command_buffer);
64 }
65 };
66
67 auto pass_callback = [this, &command_buffer](const pass_handle& pass) -> void {
68 if (pass.index >= _subrenderers.size()) {
69 return;
70 }
71
72 for (const auto& subrenderer : _subrenderers[pass.index]) {
74 }
75 };
76
77 _graph.execute(command_buffer, swapchain, pass_callback, compute_callback);
78 }
79
80 auto resize(const std::string& viewport_name) -> void {
81 _graph.resize(viewport_name);
82 }
83
84 auto attachment(const std::string& name) const -> const descriptor& {
85 return _graph.find_attachment(name);
86 }
87
88 template<typename Type>
89 requires (std::is_base_of_v<graphics::draw_list, Type>)
90 auto draw_list() -> Type& {
91 const auto name = utility::hashed_string{std::string{utility::type_name<Type>()}};
92
93 if (auto entry = _draw_lists.find(name); entry != _draw_lists.end()) {
94 return *static_cast<Type*>(entry->second.get());
95 }
96
97 throw utility::runtime_error{"Draw list with name '{}' not found", name.str()};
98 }
99
100 template<typename Type>
101 requires (std::is_base_of_v<graphics::task, Type>)
103 const auto type = type_id<Type>::value();
104
105 if (auto entry = _task_by_id.find(type); entry != _task_by_id.end()) {
106 auto [pass, index] = entry->second;
107
108 return memory::observer_ptr<Type>{static_cast<Type*>(_tasks[pass][index].get())};
109 }
110
111 return nullptr;
112 }
113
114 template<typename Type>
115 requires (std::is_base_of_v<graphics::task, Type>)
116 auto task() const -> memory::observer_ptr<const Type> {
117 const auto type = type_id<Type>::value();
118
119 if (auto entry = _task_by_id.find(type); entry != _task_by_id.end()) {
120 auto [pass, index] = entry->second;
121
122 return memory::observer_ptr<const Type>{static_cast<const Type*>(_tasks[pass][index].get())};
123 }
124
125 return nullptr;
126 }
127
128protected:
129
130 template<typename Type, typename... Args>
131 requires (std::is_base_of_v<graphics::subrenderer, Type> && std::is_constructible_v<Type, const std::vector<sbx::graphics::attachment_description>&, Args...>)
132 auto add_subrenderer(const pass_handle handle, Args&&... args) -> Type& {
133 utility::assert_that(handle.is_valid(), "Invalid pass handle in add_subrenderer()");
134
135 if (_graph.pass_kind(handle) != pass_node::kind::graphics) {
136 throw utility::runtime_error{"add_subrenderer() can only be used with graphics passes"};
137 }
138
139 _subrenderers.resize(std::max(_subrenderers.size(), static_cast<std::size_t>(handle.index + 1)));
140
141 auto& subrenderers = _subrenderers[handle.index];
142
143 subrenderers.emplace_back(std::make_unique<Type>(_graph.attachment_descriptions(handle), std::forward<Args>(args)...));
144
145 return *static_cast<Type*>(subrenderers.back().get());
146 }
147
148 template<typename Type, typename... Args>
149 requires (std::is_base_of_v<graphics::task, Type> && std::is_constructible_v<Type, Args...>)
150 auto add_task(const pass_handle handle, Args&&... args) -> Type& {
151 utility::assert_that(handle.is_valid(), "Invalid pass handle in add_compute_task()");
152
153 const auto type = type_id<Type>::value();
154
155 if (_graph.pass_kind(handle) != pass_node::kind::compute) {
156 throw utility::runtime_error{"add_compute_task() can only be used with compute passes"};
157 }
158
159 _tasks.resize(std::max(_tasks.size(), static_cast<std::size_t>(handle.index + 1)));
160
161 auto& tasks = _tasks[handle.index];
162
163 _task_by_id.emplace(type, std::make_pair(handle.index, tasks.size()));
164
165 tasks.emplace_back(std::make_unique<Type>(std::forward<Args>(args)...));
166
167 return *static_cast<Type*>(tasks.back().get());
168 }
169
170 template<typename Type, typename... Args>
171 requires (std::is_constructible_v<Type, Args...>)
172 auto add_draw_list(Args&&... args) -> Type& {
173 auto name = utility::hashed_string{std::string{utility::type_name<Type>()}};
174
175 auto result = _draw_lists.emplace(name, std::make_unique<Type>(std::forward<Args>(args)...));
176
177 return *static_cast<Type*>(result.first->second.get());
178 }
179
180 template<typename... Args>
181 auto create_attachment(Args&&... args) -> attachment_handle {
182 return _graph.create_attachment(std::forward<Args>(args)...);
183 }
184
185 template<typename Callable>
186 auto create_pass(Callable&& callable) -> pass_handle {
187 return _graph.create_pass(std::forward<Callable>(callable));
188 }
189
190 auto build_render_graph() -> void {
191 _graph.build();
192 }
193
194 auto attachment_descriptions(const pass_handle handle) const -> std::vector<attachment_description> {
195 return _graph.attachment_descriptions(handle);
196 }
197
198private:
199
200 std::vector<std::vector<std::unique_ptr<graphics::subrenderer>>> _subrenderers;
201
202 std::vector<std::vector<std::unique_ptr<graphics::task>>> _tasks;
203 std::unordered_map<std::uint32_t, std::pair<std::uint32_t, std::size_t>> _task_by_id;
204
205 std::unordered_map<utility::hashed_string, std::unique_ptr<graphics::draw_list>> _draw_lists;
206
207 render_graph _graph;
208
209}; // class renderer
210
211} // namespace sbx::graphics
212
213#endif // LIBSBX_GRAPHICS_RENDERER_HPP_
Definition: render_graph.hpp:93
Definition: command_buffer.hpp:15
Definition: descriptor.hpp:38
Definition: draw_list.hpp:28
Definition: render_graph.hpp:240
Definition: renderer.hpp:43
Definition: subrenderer.hpp:14
Definition: swapchain.hpp:15
Definition: task.hpp:9
A non-owning pointer that can be used to observe the value of a pointer.
Definition: observer_ptr.hpp:29
Definition: hashed_string.hpp:17
Definition: render_graph.hpp:142
Definition: render_graph.hpp:152
Definition: noncopyable.hpp:7
Definition: exception.hpp:18
A scoped type ID generator. Allows for generating unique IDs for types within a specific scope.
Definition: type_id.hpp:31
static auto value() noexcept -> std::uint32_t
Generates a unique ID for the type.
Definition: type_id.hpp:41