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