sandbox
Loading...
Searching...
No Matches
render_graph.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_GRAPHICS_RENDER_GRAPH_HPP_
3#define LIBSBX_GRAPHICS_RENDER_GRAPH_HPP_
4
5#include <vector>
6#include <variant>
7#include <string>
8#include <memory>
9#include <unordered_map>
10#include <optional>
11#include <functional>
12#include <queue>
13
14#include <vulkan/vulkan.h>
15
16#include <libsbx/utility/enum.hpp>
17#include <libsbx/utility/exception.hpp>
18#include <libsbx/utility/hashed_string.hpp>
19#include <libsbx/utility/logger.hpp>
20#include <libsbx/utility/overload.hpp>
21
22#include <libsbx/math/color.hpp>
23#include <libsbx/math/vector4.hpp>
24
25#include <libsbx/memory/observer_ptr.hpp>
26
27#include <libsbx/graphics/viewport.hpp>
28#include <libsbx/graphics/draw_list.hpp>
29
30#include <libsbx/graphics/images/image2d.hpp>
31#include <libsbx/graphics/images/depth_image.hpp>
32
33#include <libsbx/graphics/render_pass/swapchain.hpp>
34
35namespace sbx::graphics {
36
37enum class blend_factor : std::int32_t {
38 zero = VK_BLEND_FACTOR_ZERO,
39 one = VK_BLEND_FACTOR_ONE,
40 source_color = VK_BLEND_FACTOR_SRC_COLOR,
41 one_minus_source_color = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
42 source_alpha = VK_BLEND_FACTOR_SRC_ALPHA,
43 one_minus_source_alpha = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
44 destination_color = VK_BLEND_FACTOR_DST_COLOR,
45 one_minus_destination_color = VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
46 destination_alpha = VK_BLEND_FACTOR_DST_ALPHA,
47 one_minus_destination_alpha = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
48 constant_color = VK_BLEND_FACTOR_CONSTANT_COLOR,
49 one_minus_constant_color = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
50 constant_alpha = VK_BLEND_FACTOR_CONSTANT_ALPHA,
51 one_minus_constant_alpha = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
52 source_alpha_saturate = VK_BLEND_FACTOR_SRC_ALPHA_SATURATE
53}; // enum class blend_factor
54
55enum class blend_operation : std::int32_t {
56 add = VK_BLEND_OP_ADD,
57 subtract = VK_BLEND_OP_SUBTRACT,
58 reverse_subtract = VK_BLEND_OP_REVERSE_SUBTRACT,
59 min = VK_BLEND_OP_MIN,
60 max = VK_BLEND_OP_MAX
61}; // enum class blend_operation
62
63enum class color_component : std::int32_t {
64 r = VK_COLOR_COMPONENT_R_BIT,
65 g = VK_COLOR_COMPONENT_G_BIT,
66 b = VK_COLOR_COMPONENT_B_BIT,
67 a = VK_COLOR_COMPONENT_A_BIT
68}; // enum class color_component
69
70inline constexpr auto operator|(const color_component lhs, const color_component rhs) noexcept -> color_component {
71 return static_cast<color_component>(static_cast<std::underlying_type_t<color_component>>(lhs) | static_cast<std::underlying_type_t<color_component>>(rhs));
72}
73
74inline constexpr auto operator&(const color_component lhs, const color_component rhs) noexcept -> color_component {
75 return static_cast<color_component>(static_cast<std::underlying_type_t<color_component>>(lhs) & static_cast<std::underlying_type_t<color_component>>(rhs));
76}
77
79 blend_factor color_source{blend_factor::source_alpha};
80 blend_factor color_destination{blend_factor::one_minus_source_alpha};
81 blend_operation color_operation{blend_operation::add};
82 blend_factor alpha_source{blend_factor::one};
83 blend_factor alpha_destination{blend_factor::zero};
84 blend_operation alpha_operation{blend_operation::add};
85 color_component color_write_mask{color_component::r | color_component::g | color_component::b | color_component::a};
86}; // struct blend_state
87
88enum class attachment_load_operation : std::int32_t {
89 load = VK_ATTACHMENT_LOAD_OP_LOAD,
90 clear = VK_ATTACHMENT_LOAD_OP_CLEAR,
91 dont_care = VK_ATTACHMENT_LOAD_OP_DONT_CARE
92}; // enum class color_component
93
95
96public:
97
98 enum class type {
99 image,
100 depth,
101 storage,
103 }; // enum class type
104
105 using clear_value_type = std::variant<math::color, math::vector4i, math::vector4u>;
106
107 attachment(const utility::hashed_string& name, type type, const clear_value_type& clear_value = math::color::black(), const format format = format::r8g8b8a8_unorm, const graphics::blend_state& blend_state = graphics::blend_state{}, const filter filter = filter::linear, const address_mode address_mode = address_mode::repeat, std::uint32_t array_layers = 1u) noexcept;
108
109 attachment(const utility::hashed_string& name, type type, const clear_value_type& clear_value, const format format, const filter filter, const address_mode address_mode, std::uint32_t array_layers = 1u) noexcept;
110
111 auto name() const noexcept -> const utility::hashed_string&;
112
113 auto image_type() const noexcept -> type;
114
115 auto format() const noexcept -> graphics::format;
116
117 auto address_mode() const noexcept -> graphics::address_mode;
118
119 auto clear_value() const noexcept -> const clear_value_type&;
120
121 auto blend_state() const noexcept -> const graphics::blend_state&;
122
123 auto array_layers() const noexcept -> std::uint32_t;
124
125private:
126
128 type _type;
129 clear_value_type _clear_value;
130 graphics::format _format;
131 graphics::filter _filter;
132 graphics::address_mode _address_mode;
133 graphics::blend_state _blend_state;
134 std::uint32_t _array_layers;
135
136}; // class attachment
137
139 attachment::type image_type;
140 graphics::format format;
142 std::uint32_t array_layers{1u};
143}; // struct attachment_description
144
146
147 std::uint32_t index{0xFFFFFFFF};
148
149 [[nodiscard]] auto is_valid() const noexcept -> bool {
150 return index != 0xFFFFFFFF;
151 }
152
153}; // struct attachment_handle
154
156
157 std::uint32_t index{0xFFFFFFFF};
158
159 [[nodiscard]] auto is_valid() const noexcept -> bool {
160 return index != 0xFFFFFFFF;
161 }
162
163}; // struct pass_handle
164
166
167 friend class render_graph;
168
169public:
170
171 enum class kind : std::uint8_t {
172 graphics,
173 compute
174 }; // enum class kind
175
176 pass_node(const utility::hashed_string& name, const viewport& viewport, const kind kind)
177 : _name{name},
178 _viewport{viewport},
179 _kind{kind} { }
180
181 auto reads(const attachment_handle attachment) -> void {
182 _reads.emplace_back(attachment);
183 }
184
185 template<typename... Attachments>
186 requires (sizeof...(Attachments) > 1u && (std::is_same_v<std::remove_cvref_t<Attachments>, attachment_handle> && ...))
187 auto reads(Attachments&&... attachments) -> void {
188 (reads(attachments), ...);
189 }
190
191 auto writes(const attachment_handle attachment, const attachment_load_operation load_operation = attachment_load_operation::clear) -> void {
192 _writes.emplace_back(attachment, load_operation);
193 }
194
195 auto depends_on(const pass_handle pass) -> void {
196 _dependencies.emplace_back(pass);
197 }
198
199 template<typename... Passes>
200 requires (sizeof...(Passes) > 1u && (std::is_same_v<std::remove_cvref_t<Passes>, pass_handle> && ...))
201 auto depends_on(Passes&&... passes) -> void {
202 (depends_on(passes), ...);
203 }
204
205private:
206
208 std::vector<attachment_handle> _reads;
209 std::vector<std::pair<attachment_handle, attachment_load_operation>> _writes;
210 std::vector<pass_handle> _dependencies;
211 viewport _viewport;
212 render_area _render_area;
213 kind _kind;
214
215}; // struct pass_node
216
219 VkImageLayout new_layout;
220}; // struct transition_instruction
221
223 pass_handle pass;
224 std::vector<std::pair<attachment_handle, attachment_load_operation>> attachments;
225}; // struct pass_instruction
226
228 pass_handle pass;
229}; // struct compute_instruction
230
231using instruction = std::variant<transition_instruction, pass_instruction, compute_instruction>;
232
234 VkImage image;
235 VkImageView view;
236 VkImageLayout current_layout = VK_IMAGE_LAYOUT_UNDEFINED;
237 VkFormat format;
238 VkExtent2D extent;
239 attachment::type type;
240 std::uint32_t array_layers{1u};
241}; // struct attachment_state
242
244
245public:
246
247 struct context {
248 auto graphics_pass(const utility::hashed_string& name, const viewport& viewport = viewport::window()) const -> pass_node;
249 auto compute_pass(const utility::hashed_string& name) const -> pass_node;
250 }; // struct context
251
252 render_graph();
253
255
256 template<typename... Args>
257 requires (std::is_constructible_v<attachment, Args...>)
258 auto create_attachment(Args&&... args) -> attachment_handle;
259
260 template<typename Callable>
261 requires (std::is_invocable_r_v<pass_node, Callable, context&>)
262 auto create_pass(Callable&& callable) -> pass_handle;
263
264 auto find_attachment(const std::string& name) const -> const image2d&;
265
266 auto attachment_descriptions(const pass_handle handle) const -> std::vector<attachment_description>;
267
268 auto build() -> void;
269
270 auto resize(const std::string& viewport_name) -> void;
271
272 auto pass_kind(const pass_handle handle) const -> pass_node::kind {
273 utility::assert_that(handle.is_valid() && handle.index < _passes.size(), "Invalid pass handle");
274
275 return _passes[handle.index]._kind;
276 }
277
278 template<typename PassCallback, typename ComputeCallback>
279 requires (std::is_invocable_v<PassCallback, const pass_handle&> && std::is_invocable_v<ComputeCallback, const pass_handle&>)
280 auto execute(command_buffer& command_buffer, const swapchain& swapchain, PassCallback&& pass_callback, ComputeCallback&& compute_callback) -> void {
281 for (auto& state : _attachment_states) {
282 if (state.type == attachment::type::swapchain) {
283 state.current_layout = VK_IMAGE_LAYOUT_UNDEFINED;
284 }
285 }
286
287 for (const auto& instruction : _instructions) {
288 std::visit(utility::overload{
289 [&](const transition_instruction& instruction) { _execute_transition_instruction(command_buffer, swapchain, instruction); },
290 [&](const pass_instruction& instruction) { _execute_pass_instruction(command_buffer, swapchain, instruction, std::forward<PassCallback>(pass_callback)); },
291 [&](const compute_instruction& instruction) { _execute_compute_instruction(command_buffer, instruction, std::forward<ComputeCallback>(compute_callback)); },
292 }, instruction);
293 }
294 }
295
296private:
297
298 auto _update_viewports() -> void;
299
300 auto _clear_attachments(const std::string& viewport_name) -> void;
301
302 auto _create_attachments(const pass_node& node) -> void;
303
304 auto _pass_matches(const pass_node& pass, const std::string& viewport_name) const -> bool;
305
306 auto _build_color_attachment_info(const attachment& attachment, const attachment_state& state, const swapchain& swapchain, const attachment_load_operation load_op) -> VkRenderingAttachmentInfo;
307
308 auto _build_depth_attachment_info(const attachment& attachment, const attachment_state& state, const attachment_load_operation load_op) -> VkRenderingAttachmentInfo;
309
310 template<typename Callable>
311 auto _execute_pass_instruction(command_buffer& command_buffer, const swapchain& swapchain, const pass_instruction& instruction, Callable&& callable) -> void;
312
313 template<typename Callable>
314 auto _execute_compute_instruction(command_buffer& command_buffer, const compute_instruction& instruction, Callable&& callable) -> void;
315
316 auto _execute_transition_instruction(command_buffer& command_buffer, const swapchain& swapchain, const transition_instruction& instruction) -> void;
317
318 std::vector<attachment> _attachments;
319 std::vector<pass_node> _passes;
320
321 std::vector<image2d_handle> _color_images;
322 std::vector<depth_image_handle> _depth_images;
323
324 std::vector<attachment_state> _attachment_states;
325
326 std::unordered_map<utility::hashed_string, std::uint32_t> _image_by_name;
327
328 std::vector<instruction> _instructions;
329
330}; // class render_graph
331
332} // namespace sbx::graphics
333
334#include <libsbx/graphics/render_graph.ipp>
335
336#endif // LIBSBX_GRAPHICS_RENDER_GRAPH_HPP_
Definition: tests.cpp:6
Definition: render_graph.hpp:94
Definition: command_buffer.hpp:15
Definition: image2d.hpp:53
Definition: image.hpp:21
Definition: render_graph.hpp:165
Definition: viewport.hpp:81
Definition: render_graph.hpp:243
Definition: swapchain.hpp:15
Definition: viewport.hpp:13
static auto black() noexcept -> color
Returns a black color.
Definition: color.cpp:45
Definition: hashed_string.hpp:17
RGBA color representation and utilities.
Definition: render_graph.hpp:138
Definition: render_graph.hpp:145
Definition: render_graph.hpp:233
Definition: render_graph.hpp:78
Definition: render_graph.hpp:227
Definition: render_graph.hpp:155
Definition: render_graph.hpp:222
Definition: render_graph.hpp:247
Definition: render_graph.hpp:217