1#ifndef LIBSBX_GRAPHICS_RENDER_GRAPH_HPP_
2#define LIBSBX_GRAPHICS_RENDER_GRAPH_HPP_
8#include <unordered_map>
12#include <vulkan/vulkan.h>
14#include <libsbx/utility/enum.hpp>
15#include <libsbx/utility/exception.hpp>
16#include <libsbx/utility/hashed_string.hpp>
17#include <libsbx/utility/logger.hpp>
19#include <libsbx/math/color.hpp>
21#include <libsbx/memory/observer_ptr.hpp>
23#include <libsbx/graphics/viewport.hpp>
24#include <libsbx/graphics/draw_list.hpp>
26#include <libsbx/graphics/images/image2d.hpp>
27#include <libsbx/graphics/images/depth_image.hpp>
29#include <libsbx/graphics/render_pass/swapchain.hpp>
31namespace sbx::graphics {
33enum class format : std::int32_t {
34 undefined = VK_FORMAT_UNDEFINED,
35 r16_sfloat = VK_FORMAT_R16_SFLOAT,
36 r32_sfloat = VK_FORMAT_R32_SFLOAT,
37 r32_uint = VK_FORMAT_R32_UINT,
38 r64_uint = VK_FORMAT_R64_UINT,
39 r32g32_sfloat = VK_FORMAT_R32G32_SFLOAT,
40 r32g32_uint = VK_FORMAT_R32G32_UINT,
41 r8g8b8a8_unorm = VK_FORMAT_R8G8B8A8_UNORM,
42 b8g8r8a8_srgb = VK_FORMAT_B8G8R8A8_SRGB,
43 r16g16b16a16_sfloat = VK_FORMAT_R16G16B16A16_SFLOAT,
44 r32g32b32a32_sfloat = VK_FORMAT_R32G32B32A32_SFLOAT
47enum class address_mode : std::uint32_t {
48 repeat = VK_SAMPLER_ADDRESS_MODE_REPEAT,
49 clamp_to_edge = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
52enum class blend_factor : std::uint32_t {
53 zero = VK_BLEND_FACTOR_ZERO,
54 one = VK_BLEND_FACTOR_ONE,
55 source_color = VK_BLEND_FACTOR_SRC_COLOR,
56 one_minus_source_color = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
57 source_alpha = VK_BLEND_FACTOR_SRC_ALPHA,
58 one_minus_source_alpha = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
59 destination_color = VK_BLEND_FACTOR_DST_COLOR,
60 one_minus_destination_color = VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
61 destination_alpha = VK_BLEND_FACTOR_DST_ALPHA,
62 one_minus_destination_alpha = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
63 constant_color = VK_BLEND_FACTOR_CONSTANT_COLOR,
64 one_minus_constant_color = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
65 constant_alpha = VK_BLEND_FACTOR_CONSTANT_ALPHA,
66 one_minus_constant_alpha = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
67 source_alpha_saturate = VK_BLEND_FACTOR_SRC_ALPHA_SATURATE
70enum class blend_operation : std::uint32_t {
71 add = VK_BLEND_OP_ADD,
72 subtract = VK_BLEND_OP_SUBTRACT,
73 reverse_subtract = VK_BLEND_OP_REVERSE_SUBTRACT,
74 min = VK_BLEND_OP_MIN,
78enum class color_component : std::uint32_t {
79 r = VK_COLOR_COMPONENT_R_BIT,
80 g = VK_COLOR_COMPONENT_G_BIT,
81 b = VK_COLOR_COMPONENT_B_BIT,
82 a = VK_COLOR_COMPONENT_A_BIT
85inline constexpr auto operator|(
const color_component lhs,
const color_component rhs)
noexcept -> color_component {
86 return static_cast<color_component
>(
static_cast<std::underlying_type_t<color_component>
>(lhs) |
static_cast<std::underlying_type_t<color_component>
>(rhs));
89inline constexpr auto operator&(
const color_component lhs,
const color_component rhs)
noexcept -> color_component {
90 return static_cast<color_component
>(
static_cast<std::underlying_type_t<color_component>
>(lhs) &
static_cast<std::underlying_type_t<color_component>
>(rhs));
94 blend_factor color_source{blend_factor::source_alpha};
95 blend_factor color_destination{blend_factor::one_minus_source_alpha};
96 blend_operation color_operation{blend_operation::add};
97 blend_factor alpha_source{blend_factor::one};
98 blend_factor alpha_destination{blend_factor::zero};
99 blend_operation alpha_operation{blend_operation::add};
100 color_component color_write_mask{color_component::r | color_component::g | color_component::b | color_component::a};
120 auto image_type()
const noexcept -> type;
122 auto format()
const noexcept -> graphics::format;
124 auto address_mode()
const noexcept -> graphics::address_mode;
126 auto clear_color()
const noexcept ->
const math::color&;
135 graphics::format _format;
136 graphics::address_mode _address_mode;
159 std::vector<utility::hashed_string> _inputs;
160 std::vector<attachment> _outputs;
186 template<
typename Type,
typename... Args>
187 auto emplace_back(Args&&... args) -> Type&;
189 auto reserve(
const std::size_t graphics,
const std::size_t compute) -> void;
193 std::vector<graphics_node> _graphics_nodes;
194 std::vector<compute_node> _compute_nodes;
195 std::unordered_map<utility::hashed_string, std::unique_ptr<graphics::draw_list>> _draw_lists;
205 template<
typename... Names>
206 requires (... && (std::is_same_v<std::remove_cvref_t<Names>,
utility::hashed_string> || std::is_constructible_v<utility::hashed_string, Names>))
207 auto uses(Names&&... names) -> void;
209 template<
typename... Args>
210 requires (std::is_constructible_v<
attachment, Args...>)
211 auto produces(Args&&... args) -> void;
219 auto inputs()
const ->
const std::vector<utility::hashed_string>& ;
221 auto outputs()
const ->
const std::vector<attachment>&;
223 template<
typename Type>
224 requires (std::is_base_of_v<draw_list, Type>)
226 if (
auto entry = _graph._draw_lists.find(name); entry != _graph._draw_lists.end()) {
227 return *
static_cast<Type*
>(entry->second.get());
230 throw utility::runtime_error{
"Draw list with name '{}' not found in graphics pass '{}'", name.str(), _node._name.str()};
276 VkImageLayout old_layout;
277 VkImageLayout new_layout;
282 std::vector<utility::hashed_string> attachments;
285using instruction = std::variant<transition_instruction, pass_instruction>;
287template<
typename... Callables>
289 using Callables::operator()...;
293template<
typename... Callables>
303 _clear_all_attachments();
306 template <
typename Callable>
307 requires (std::is_invocable_r_v<graphics_pass, Callable, context&>)
310 template <
typename Callable>
311 requires (std::is_invocable_r_v<compute_pass, Callable, context&>)
314 template<
typename... Callables>
315 requires (
sizeof...(Callables) > 1u)
316 auto emplace(Callables&&... callables) ->
decltype(
auto);
318 template<
typename Type,
typename... Args>
319 requires (std::is_constructible_v<Type, Args...>)
321 auto result = _graph._draw_lists.emplace(name, std::make_unique<Type>(std::forward<Args>(args)...));
322 return *
static_cast<Type*
>(result.first->second.get());
325 auto build() -> void;
327 auto resize(
const viewport::type flags) -> void;
331 template<
typename Callable>
333 for (
auto& [key,
draw_list] : _graph._draw_lists) {
339 for (
auto& [key, state] : _attachment_states) {
340 state.is_first_use =
true;
343 for (
const auto& instruction : _instructions) {
346 auto& state = _attachment_states.at(instruction.attachment);
348 if (state.type == attachment::type::swapchain) {
349 image::transition_image_layout(
command_buffer,
swapchain.image(
swapchain.active_image_index()),
swapchain.formt(), instruction.old_layout, instruction.new_layout, VK_IMAGE_ASPECT_COLOR_BIT, 1, 0, 1, 0);
351 image::transition_image_layout(
command_buffer, state.image, state.format, instruction.old_layout, instruction.new_layout, (state.type == attachment::type::depth) ? (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) : VK_IMAGE_ASPECT_COLOR_BIT, 1, 0, 1, 0);
355 const auto& area = _pass_render_areas[instruction.node._name];
357 const auto& offset = area.offset();
358 const auto& extent = area.extent();
361 render_area.offset = VkOffset2D{offset.x(), offset.y()};
362 render_area.extent = VkExtent2D{extent.x(), extent.y()};
374 auto scissor = VkRect2D{};
380 auto color_attachments = std::vector<VkRenderingAttachmentInfo>{};
381 auto depth_attachment = std::optional<VkRenderingAttachmentInfo>{};
383 for (
const auto&
attachment : instruction.attachments) {
384 const auto& clear_value = _clear_values[
attachment];
387 auto load_operation = VK_ATTACHMENT_LOAD_OP_LOAD;
389 if (state.is_first_use) {
390 load_operation = VK_ATTACHMENT_LOAD_OP_CLEAR;
391 state.is_first_use =
false;
394 if (state.type == attachment::type::image) {
395 auto rendering_attachment_info = VkRenderingAttachmentInfo{};
396 rendering_attachment_info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
397 rendering_attachment_info.imageView = state.view;
398 rendering_attachment_info.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
399 rendering_attachment_info.resolveMode = VK_RESOLVE_MODE_NONE;
400 rendering_attachment_info.loadOp = load_operation;
401 rendering_attachment_info.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
402 rendering_attachment_info.clearValue = clear_value;
404 color_attachments.push_back(rendering_attachment_info);
405 }
else if (state.type == attachment::type::depth) {
406 auto rendering_attachment_info = VkRenderingAttachmentInfo{};
407 rendering_attachment_info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
408 rendering_attachment_info.imageView = state.view;
409 rendering_attachment_info.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
410 rendering_attachment_info.resolveMode = VK_RESOLVE_MODE_NONE;
411 rendering_attachment_info.loadOp = load_operation;
412 rendering_attachment_info.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
413 rendering_attachment_info.clearValue = clear_value;
415 depth_attachment = rendering_attachment_info;
416 }
else if (state.type == attachment::type::swapchain) {
417 auto rendering_attachment_info = VkRenderingAttachmentInfo{};
418 rendering_attachment_info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
419 rendering_attachment_info.imageView =
swapchain.image_view(
swapchain.active_image_index());
420 rendering_attachment_info.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
421 rendering_attachment_info.resolveMode = VK_RESOLVE_MODE_NONE;
422 rendering_attachment_info.loadOp = load_operation;
423 rendering_attachment_info.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
424 rendering_attachment_info.clearValue = clear_value;
426 color_attachments.push_back(rendering_attachment_info);
430 auto rendering_info = VkRenderingInfo{};
431 rendering_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
433 rendering_info.layerCount = 1;
434 rendering_info.colorAttachmentCount =
static_cast<std::uint32_t
>(color_attachments.size());
435 rendering_info.pColorAttachments = color_attachments.data();
436 rendering_info.pDepthAttachment = depth_attachment.has_value() ? &depth_attachment.value() :
nullptr;
437 rendering_info.pStencilAttachment = depth_attachment.has_value() ? &depth_attachment.value() :
nullptr;
441 std::invoke(callable, instruction.node._name);
451 struct attachment_state {
454 VkImageLayout current_layout = VK_IMAGE_LAYOUT_UNDEFINED;
457 attachment::type type;
461 auto _update_viewports() -> void;
463 auto _clear_all_attachments() -> void;
465 auto _clear_attachments(
const viewport::type flags) -> void;
467 auto _create_attachments(
const viewport::type flags,
const graphics_node&
node) -> void;
471 std::unordered_map<utility::hashed_string, image2d_handle> _color_images;
472 std::unordered_map<utility::hashed_string, depth_image_handle> _depth_images;
473 std::unordered_map<utility::hashed_string, VkClearValue> _clear_values;
475 std::vector<instruction> _instructions;
477 std::unordered_map<utility::hashed_string, attachment_state> _attachment_states;
479 std::unordered_map<utility::hashed_string, render_area> _pass_render_areas;
507#include <libsbx/graphics/render_graph.ipp>
Definition: render_graph.hpp:103
Definition: command_buffer.hpp:14
Definition: descriptor.hpp:37
Definition: render_graph.hpp:164
Definition: render_graph.hpp:242
Definition: render_graph.hpp:256
Definition: render_graph.hpp:179
Definition: render_graph.hpp:296
Definition: render_graph.hpp:143
Definition: render_graph.hpp:199
Definition: draw_list.hpp:24
Definition: viewport.hpp:98
Definition: render_graph.hpp:485
Definition: swapchain.hpp:12
Definition: viewport.hpp:12
Definition: hashed_string.hpp:15
Definition: render_graph.hpp:93
Definition: render_graph.hpp:288
Definition: render_graph.hpp:280
Definition: render_graph.hpp:274
Definition: exception.hpp:17