diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 687ac3989f0..a2ba66fcc70 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -271,6 +271,8 @@ set(VULKAN_SRC vulkan/vk_push_constants.hh vulkan/vk_query.hh vulkan/render_graph/nodes/vk_blit_image_node.hh + vulkan/render_graph/nodes/vk_begin_rendering_node.hh + vulkan/render_graph/nodes/vk_clear_attachments_node.hh vulkan/render_graph/nodes/vk_clear_color_image_node.hh vulkan/render_graph/nodes/vk_clear_depth_stencil_image_node.hh vulkan/render_graph/nodes/vk_copy_buffer_node.hh @@ -278,6 +280,7 @@ set(VULKAN_SRC vulkan/render_graph/nodes/vk_copy_image_node.hh vulkan/render_graph/nodes/vk_copy_image_to_buffer_node.hh vulkan/render_graph/nodes/vk_dispatch_node.hh + vulkan/render_graph/nodes/vk_end_rendering_node.hh vulkan/render_graph/nodes/vk_fill_buffer_node.hh vulkan/render_graph/nodes/vk_node_info.hh vulkan/render_graph/nodes/vk_pipeline_data.hh @@ -944,6 +947,7 @@ if(WITH_GTESTS) vulkan/tests/vk_memory_layout_test.cc vulkan/render_graph/tests/vk_render_graph_test_compute.cc vulkan/render_graph/tests/vk_render_graph_test_present.cc + vulkan/render_graph/tests/vk_render_graph_test_render.cc vulkan/render_graph/tests/vk_render_graph_test_transfer.cc ) endif() diff --git a/source/blender/gpu/vulkan/render_graph/nodes/vk_begin_rendering_node.hh b/source/blender/gpu/vulkan/render_graph/nodes/vk_begin_rendering_node.hh new file mode 100644 index 00000000000..ada12095cfc --- /dev/null +++ b/source/blender/gpu/vulkan/render_graph/nodes/vk_begin_rendering_node.hh @@ -0,0 +1,109 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "render_graph/vk_resource_access_info.hh" +#include "vk_node_info.hh" + +namespace blender::gpu::render_graph { + +/** + * Information stored inside the render graph node. See `VKRenderGraphNode`. + */ +struct VKBeginRenderingData { + VkRenderingAttachmentInfo color_attachments[8]; + VkRenderingAttachmentInfo depth_attachment; + VkRenderingAttachmentInfo stencil_attachment; + VkRenderingInfoKHR vk_rendering_info; +}; + +struct VKBeginRenderingCreateInfo { + VKBeginRenderingData node_data; + const VKResourceAccessInfo &resources; + VKBeginRenderingCreateInfo(const VKResourceAccessInfo &resources) : resources(resources) + { + /* Using memset as MSVC didn't clear the color_attachments array. */ + memset(&node_data, 0, sizeof(node_data)); + } +}; + +/** + * Begin rendering node + * + * - Contains logic to copy relevant data to the VKRenderGraphNode. + * - Determine read/write resource dependencies. + * - Add commands to a command builder. + */ +class VKBeginRenderingNode : public VKNodeInfo { + public: + /** + * Update the node data with the data inside create_info. + * + * Has been implemented as a template to ensure all node specific data + * (`VK*Data`/`VK*CreateInfo`) types can be included in the same header file as the logic. The + * actual node data (`VKRenderGraphNode` includes all header files.) + */ + template void set_node_data(Node &node, const CreateInfo &create_info) + { + BLI_assert_msg(ELEM(create_info.node_data.vk_rendering_info.pColorAttachments, + nullptr, + create_info.node_data.color_attachments), + "When create_info.node_data.vk_rendering_info.pColorAttachments points to " + "something, it should point to create_info.node_data.color_attachments."); + BLI_assert_msg(ELEM(create_info.node_data.vk_rendering_info.pDepthAttachment, + nullptr, + &create_info.node_data.depth_attachment), + "When create_info.node_data.vk_rendering_info.pDepthAttachment points to " + "something, it should point to create_info.node_data.depth_attachment."); + BLI_assert_msg(ELEM(create_info.node_data.vk_rendering_info.pStencilAttachment, + nullptr, + &create_info.node_data.stencil_attachment), + "When create_info.node_data.vk_rendering_info.pStencilAttachment points to " + "something, it should point to create_info.node_data.stencil_attachment."); + node.begin_rendering = create_info.node_data; + /* Localize pointers when set.*/ + if (node.begin_rendering.vk_rendering_info.pColorAttachments) { + node.begin_rendering.vk_rendering_info.pColorAttachments = + node.begin_rendering.color_attachments; + } + if (node.begin_rendering.vk_rendering_info.pDepthAttachment) { + node.begin_rendering.vk_rendering_info.pDepthAttachment = + &node.begin_rendering.depth_attachment; + } + if (node.begin_rendering.vk_rendering_info.pStencilAttachment) { + node.begin_rendering.vk_rendering_info.pStencilAttachment = + &node.begin_rendering.stencil_attachment; + } + } + + /** + * Extract read/write resource dependencies from `create_info` and add them to `node_links`. + */ + void build_links(VKResourceStateTracker &resources, + VKRenderGraphNodeLinks &node_links, + const CreateInfo &create_info) override + { + create_info.resources.build_links(resources, node_links); + } + + /** + * Build the commands and add them to the command_buffer. + */ + void build_commands(VKCommandBufferInterface &command_buffer, + const Data &data, + VKBoundPipelines & /*r_bound_pipelines*/) override + { + command_buffer.begin_rendering(&data.vk_rendering_info); + } +}; +} // namespace blender::gpu::render_graph diff --git a/source/blender/gpu/vulkan/render_graph/nodes/vk_clear_attachments_node.hh b/source/blender/gpu/vulkan/render_graph/nodes/vk_clear_attachments_node.hh new file mode 100644 index 00000000000..109e860b9e7 --- /dev/null +++ b/source/blender/gpu/vulkan/render_graph/nodes/vk_clear_attachments_node.hh @@ -0,0 +1,66 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "render_graph/vk_resource_access_info.hh" +#include "vk_node_info.hh" + +namespace blender::gpu::render_graph { + +/** + * Information stored inside the render graph node. See `VKRenderGraphNode`. + */ +struct VKClearAttachmentsData { + uint32_t attachment_count; + VkClearAttachment attachments[8]; + VkClearRect vk_clear_rect; +}; + +class VKClearAttachmentsNode : public VKNodeInfo { + public: + /** + * Update the node data with the data inside create_info. + * + * Has been implemented as a template to ensure all node specific data + * (`VK*Data`/`VK*CreateInfo`) types can be included in the same header file as the logic. The + * actual node data (`VKRenderGraphNode` includes all header files.) + */ + template static void set_node_data(Node &node, const CreateInfo &create_info) + { + node.clear_attachments = create_info; + } + + /** + * Extract read/write resource dependencies from `create_info` and add them to `node_links`. + */ + void build_links(VKResourceStateTracker &resources, + VKRenderGraphNodeLinks &node_links, + const CreateInfo &create_info) override + { + UNUSED_VARS(resources, node_links, create_info); + } + + /** + * Build the commands and add them to the command_buffer. + */ + void build_commands(VKCommandBufferInterface &command_buffer, + const Data &data, + VKBoundPipelines & /*r_bound_pipelines*/) override + { + command_buffer.clear_attachments( + data.attachment_count, data.attachments, 1, &data.vk_clear_rect); + } +}; +} // namespace blender::gpu::render_graph diff --git a/source/blender/gpu/vulkan/render_graph/nodes/vk_end_rendering_node.hh b/source/blender/gpu/vulkan/render_graph/nodes/vk_end_rendering_node.hh new file mode 100644 index 00000000000..5ffe94dba64 --- /dev/null +++ b/source/blender/gpu/vulkan/render_graph/nodes/vk_end_rendering_node.hh @@ -0,0 +1,64 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "vk_node_info.hh" + +namespace blender::gpu::render_graph { + +/** + * Information stored inside the render graph node. See `VKRenderGraphNode`. + */ +struct VKEndRenderingData {}; + +/** + * End rendering node + * + * - Contains logic to copy relevant data to the VKRenderGraphNode. + * - Determine read/write resource dependencies. + * - Add commands to a command builder. + */ +class VKEndRenderingNode : public VKNodeInfo { + public: + /** + * Update the node data with the data inside create_info. + * + * Has been implemented as a template to ensure all node specific data + * (`VK*Data`/`VK*CreateInfo`) types can be included in the same header file as the logic. The + * actual node data (`VKRenderGraphNode` includes all header files.) + */ + template void set_node_data(Node &node, const CreateInfo &create_info) + { + node.end_rendering = create_info; + } + + /** + * Extract read/write resource dependencies from `create_info` and add them to `node_links`. + */ + void build_links(VKResourceStateTracker & /*resources*/, + VKRenderGraphNodeLinks & /*node_links*/, + const CreateInfo & /*create_info*/) override + { + } + + /** + * Build the commands and add them to the command_buffer. + */ + void build_commands(VKCommandBufferInterface &command_buffer, + const Data & /*data*/, + VKBoundPipelines & /*r_bound_pipelines*/) override + { + command_buffer.end_rendering(); + } +}; +} // namespace blender::gpu::render_graph diff --git a/source/blender/gpu/vulkan/render_graph/nodes/vk_node_info.hh b/source/blender/gpu/vulkan/render_graph/nodes/vk_node_info.hh index 7353b5218d4..6b1c15f267e 100644 --- a/source/blender/gpu/vulkan/render_graph/nodes/vk_node_info.hh +++ b/source/blender/gpu/vulkan/render_graph/nodes/vk_node_info.hh @@ -21,6 +21,9 @@ namespace blender::gpu::render_graph { */ enum class VKNodeType { UNUSED, + BEGIN_RENDERING, + END_RENDERING, + CLEAR_ATTACHMENTS, CLEAR_COLOR_IMAGE, CLEAR_DEPTH_STENCIL_IMAGE, FILL_BUFFER, @@ -47,7 +50,7 @@ enum class VKNodeType { template class VKNodeInfo : public NonCopyable { diff --git a/source/blender/gpu/vulkan/render_graph/tests/vk_render_graph_test_render.cc b/source/blender/gpu/vulkan/render_graph/tests/vk_render_graph_test_render.cc new file mode 100644 index 00000000000..cb6ea8ca3e3 --- /dev/null +++ b/source/blender/gpu/vulkan/render_graph/tests/vk_render_graph_test_render.cc @@ -0,0 +1,136 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +#include "testing/testing.h" + +#include "vk_render_graph_test_types.hh" + +namespace blender::gpu::render_graph { + +TEST(vk_render_graph, begin_clear_attachments_end_read_back) +{ + VkHandle image(1u); + VkHandle image_view(2u); + VkHandle buffer(3u); + + Vector log; + VKCommandBufferWrapper wrapper; + VKResourceStateTracker resources; + VKRenderGraph render_graph(std::make_unique(log), resources); + resources.add_image(image, VK_IMAGE_LAYOUT_UNDEFINED, ResourceOwner::APPLICATION); + resources.add_buffer(buffer); + + { + VKResourceAccessInfo access_info = {}; + access_info.images.append( + {image, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT}); + VKBeginRenderingNode::CreateInfo begin_rendering(access_info); + begin_rendering.node_data.color_attachments[0].sType = + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; + begin_rendering.node_data.color_attachments[0].imageLayout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + begin_rendering.node_data.color_attachments[0].imageView = image_view; + begin_rendering.node_data.color_attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + begin_rendering.node_data.color_attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + begin_rendering.node_data.vk_rendering_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; + begin_rendering.node_data.vk_rendering_info.colorAttachmentCount = 1; + begin_rendering.node_data.vk_rendering_info.layerCount = 1; + begin_rendering.node_data.vk_rendering_info.pColorAttachments = + begin_rendering.node_data.color_attachments; + + render_graph.add_node(begin_rendering); + } + + { + VKClearAttachmentsNode::CreateInfo clear_attachments = {}; + clear_attachments.attachment_count = 1; + clear_attachments.attachments[0].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + clear_attachments.attachments[0].clearValue.color.float32[0] = 0.2; + clear_attachments.attachments[0].clearValue.color.float32[1] = 0.4; + clear_attachments.attachments[0].clearValue.color.float32[2] = 0.6; + clear_attachments.attachments[0].clearValue.color.float32[3] = 1.0; + clear_attachments.attachments[0].colorAttachment = 0; + clear_attachments.vk_clear_rect.baseArrayLayer = 0; + clear_attachments.vk_clear_rect.layerCount = 1; + clear_attachments.vk_clear_rect.rect.extent.width = 1920; + clear_attachments.vk_clear_rect.rect.extent.height = 1080; + render_graph.add_node(clear_attachments); + } + + { + VKEndRenderingNode::CreateInfo end_rendering = {}; + render_graph.add_node(end_rendering); + } + + { + VKCopyImageToBufferNode::CreateInfo copy_image_to_buffer = {}; + copy_image_to_buffer.src_image = image; + copy_image_to_buffer.dst_buffer = buffer; + copy_image_to_buffer.region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + render_graph.add_node(copy_image_to_buffer); + } + + render_graph.submit_buffer_for_read(buffer); + EXPECT_EQ(6, log.size()); + EXPECT_EQ( + "pipeline_barrier(src_stage_mask=VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, " + "dst_stage_mask=VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT" + + endl() + + " - image_barrier(src_access_mask=, " + "dst_access_mask=VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, " + "old_layout=VK_IMAGE_LAYOUT_UNDEFINED, " + "new_layout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, image=0x1, " + "subresource_range=" + + endl() + + " aspect_mask=VK_IMAGE_ASPECT_COLOR_BIT, base_mip_level=0, level_count=4294967295, " + "base_array_layer=0, layer_count=4294967295 )" + + endl() + ")", + log[0]); + EXPECT_EQ("begin_rendering(p_rendering_info=flags=, render_area=" + endl() + + " offset=" + endl() + " x=0, y=0 , extent=" + endl() + + " width=0, height=0 , layer_count=1, view_mask=0, color_attachment_count=1, " + "p_color_attachments=" + + endl() + + " image_view=0x2, image_layout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, " + "resolve_mode=VK_RESOLVE_MODE_NONE, resolve_image_view=0, " + "resolve_image_layout=VK_IMAGE_LAYOUT_UNDEFINED, " + "load_op=VK_ATTACHMENT_LOAD_OP_DONT_CARE, store_op=VK_ATTACHMENT_STORE_OP_STORE" + + endl() + ")", + log[1]); + EXPECT_EQ( + "clear_attachments( - attachment(aspect_mask=VK_IMAGE_ASPECT_COLOR_BIT, " + "color_attachment=0)" + + endl() + " - rect(rect=" + endl() + " offset=" + endl() + + " x=0, y=0 , extent=" + endl() + + " width=1920, height=1080 , base_array_layer=0, layer_count=1)" + endl() + ")", + log[2]); + EXPECT_EQ("end_rendering()", log[3]); + EXPECT_EQ( + "pipeline_barrier(src_stage_mask=VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, " + "dst_stage_mask=VK_PIPELINE_STAGE_TRANSFER_BIT" + + endl() + + " - image_barrier(src_access_mask=VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, " + "dst_access_mask=VK_ACCESS_TRANSFER_READ_BIT, " + "old_layout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, " + "new_layout=VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image=0x1, subresource_range=" + + endl() + + " aspect_mask=VK_IMAGE_ASPECT_COLOR_BIT, base_mip_level=0, level_count=4294967295, " + "base_array_layer=0, layer_count=4294967295 )" + + endl() + ")", + log[4]); + EXPECT_EQ( + "copy_image_to_buffer(src_image=0x1, src_image_layout=VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, " + "dst_buffer=0x3" + + endl() + + " - region(buffer_offset=0, buffer_row_length=0, buffer_image_height=0, " + "image_subresource=" + + endl() + + " aspect_mask=VK_IMAGE_ASPECT_COLOR_BIT, mip_level=0, base_array_layer=0, " + "layer_count=0 , image_offset=" + + endl() + " x=0, y=0, z=0 , image_extent=" + endl() + + " width=0, height=0, depth=0 )" + endl() + ")", + log[5]); +} + +} // namespace blender::gpu::render_graph diff --git a/source/blender/gpu/vulkan/render_graph/tests/vk_render_graph_test_types.hh b/source/blender/gpu/vulkan/render_graph/tests/vk_render_graph_test_types.hh index 70d55c3bc7e..89278b3c5bd 100644 --- a/source/blender/gpu/vulkan/render_graph/tests/vk_render_graph_test_types.hh +++ b/source/blender/gpu/vulkan/render_graph/tests/vk_render_graph_test_types.hh @@ -332,7 +332,19 @@ class CommandBufferLog : public VKCommandBufferInterface { { UNUSED_VARS(attachment_count, p_attachments, rect_count, p_rects); EXPECT_TRUE(is_recording_); - GTEST_FAIL() << __func__ << " not implemented!"; + std::stringstream ss; + ss << "clear_attachments("; + for (const VkClearAttachment &attachment : + Span(p_attachments, attachment_count)) + { + ss << " - attachment(" << to_string(attachment, 1) << ")" << std::endl; + } + for (const VkClearRect &rect : Span(p_rects, rect_count)) { + ss << " - rect(" << to_string(rect, 1) << ")" << std::endl; + } + ss << ")"; + + log_.append(ss.str()); } void pipeline_barrier(VkPipelineStageFlags src_stage_mask, diff --git a/source/blender/gpu/vulkan/render_graph/vk_render_graph.hh b/source/blender/gpu/vulkan/render_graph/vk_render_graph.hh index 45fc6689b8c..3e72bcfa1fb 100644 --- a/source/blender/gpu/vulkan/render_graph/vk_render_graph.hh +++ b/source/blender/gpu/vulkan/render_graph/vk_render_graph.hh @@ -128,6 +128,18 @@ class VKRenderGraph : public NonCopyable { } public: + void add_node(const VKBeginRenderingNode::CreateInfo &begin_rendering) + { + add_node(begin_rendering); + } + void add_node(const VKEndRenderingNode::CreateInfo &end_rendering) + { + add_node(end_rendering); + } + void add_node(const VKClearAttachmentsNode::CreateInfo &clear_attachments) + { + add_node(clear_attachments); + } void add_node(const VKClearColorImageNode::CreateInfo &clear_color_image) { add_node(clear_color_image); diff --git a/source/blender/gpu/vulkan/render_graph/vk_render_graph_node.hh b/source/blender/gpu/vulkan/render_graph/vk_render_graph_node.hh index b8ee0db97fc..4e3d3896c85 100644 --- a/source/blender/gpu/vulkan/render_graph/vk_render_graph_node.hh +++ b/source/blender/gpu/vulkan/render_graph/vk_render_graph_node.hh @@ -8,7 +8,9 @@ #pragma once +#include "nodes/vk_begin_rendering_node.hh" #include "nodes/vk_blit_image_node.hh" +#include "nodes/vk_clear_attachments_node.hh" #include "nodes/vk_clear_color_image_node.hh" #include "nodes/vk_clear_depth_stencil_image_node.hh" #include "nodes/vk_copy_buffer_node.hh" @@ -17,6 +19,7 @@ #include "nodes/vk_copy_image_to_buffer_node.hh" #include "nodes/vk_dispatch_indirect_node.hh" #include "nodes/vk_dispatch_node.hh" +#include "nodes/vk_end_rendering_node.hh" #include "nodes/vk_fill_buffer_node.hh" #include "nodes/vk_synchronization_node.hh" @@ -38,12 +41,15 @@ struct VKRenderGraphNode { VKNodeType type; union { VKBlitImageNode::Data blit_image; + VKBeginRenderingNode::Data begin_rendering; + VKClearAttachmentsNode::Data clear_attachments; VKClearColorImageNode::Data clear_color_image; VKClearDepthStencilImageNode::Data clear_depth_stencil_image; VKCopyBufferNode::Data copy_buffer; VKCopyBufferToImageNode::Data copy_buffer_to_image; VKCopyImageNode::Data copy_image; VKCopyImageToBufferNode::Data copy_image_to_buffer; + VKEndRenderingNode::Data end_rendering; VKDispatchNode::Data dispatch; VKDispatchIndirectNode::Data dispatch_indirect; VKFillBufferNode::Data fill_buffer; @@ -94,10 +100,16 @@ struct VKRenderGraphNode { switch (type) { case VKNodeType::UNUSED: return VK_PIPELINE_STAGE_NONE; + case VKNodeType::BEGIN_RENDERING: + return VKBeginRenderingNode::pipeline_stage; + case VKNodeType::CLEAR_ATTACHMENTS: + return VKClearAttachmentsNode::pipeline_stage; case VKNodeType::CLEAR_COLOR_IMAGE: return VKClearColorImageNode::pipeline_stage; case VKNodeType::CLEAR_DEPTH_STENCIL_IMAGE: return VKClearDepthStencilImageNode::pipeline_stage; + case VKNodeType::END_RENDERING: + return VKEndRenderingNode::pipeline_stage; case VKNodeType::FILL_BUFFER: return VKFillBufferNode::pipeline_stage; case VKNodeType::COPY_BUFFER: @@ -135,6 +147,18 @@ struct VKRenderGraphNode { break; } + case VKNodeType::BEGIN_RENDERING: { + VKBeginRenderingNode node_info; + node_info.build_commands(command_buffer, begin_rendering, r_bound_pipelines); + break; + } + + case VKNodeType::CLEAR_ATTACHMENTS: { + VKClearAttachmentsNode node_info; + node_info.build_commands(command_buffer, clear_attachments, r_bound_pipelines); + break; + } + case VKNodeType::CLEAR_COLOR_IMAGE: { VKClearColorImageNode node_info; node_info.build_commands(command_buffer, clear_color_image, r_bound_pipelines); @@ -147,6 +171,12 @@ struct VKRenderGraphNode { break; } + case VKNodeType::END_RENDERING: { + VKEndRenderingNode node_info; + node_info.build_commands(command_buffer, end_rendering, r_bound_pipelines); + break; + } + case VKNodeType::FILL_BUFFER: { VKFillBufferNode node_info; node_info.build_commands(command_buffer, fill_buffer, r_bound_pipelines); @@ -222,8 +252,11 @@ struct VKRenderGraphNode { } case VKNodeType::UNUSED: + case VKNodeType::BEGIN_RENDERING: + case VKNodeType::CLEAR_ATTACHMENTS: case VKNodeType::CLEAR_COLOR_IMAGE: case VKNodeType::CLEAR_DEPTH_STENCIL_IMAGE: + case VKNodeType::END_RENDERING: case VKNodeType::FILL_BUFFER: case VKNodeType::COPY_BUFFER: case VKNodeType::COPY_IMAGE: diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index afd058b6752..85da0af7a23 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -174,7 +174,12 @@ void VKContext::activate_framebuffer(VKFrameBuffer &framebuffer) active_fb = &framebuffer; framebuffer.update_size(); framebuffer.update_srgb(); - command_buffers_get().begin_render_pass(framebuffer); + if (use_render_graph) { + framebuffer.rendering_reset(); + } + else { + command_buffers_get().begin_render_pass(framebuffer); + } } VKFrameBuffer *VKContext::active_framebuffer_get() const @@ -191,10 +196,23 @@ void VKContext::deactivate_framebuffer() { VKFrameBuffer *framebuffer = active_framebuffer_get(); BLI_assert(framebuffer != nullptr); - command_buffers_get().end_render_pass(*framebuffer); + if (use_render_graph) { + framebuffer->rendering_end(*this); + } + else { + command_buffers_get().end_render_pass(*framebuffer); + } active_fb = nullptr; } +void VKContext::rendering_end() +{ + VKFrameBuffer *framebuffer = active_framebuffer_get(); + if (framebuffer) { + framebuffer->rendering_end(*this); + } +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh index 13a1f081f24..b58a9156518 100644 --- a/source/blender/gpu/vulkan/vk_context.hh +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -72,6 +72,15 @@ class VKContext : public Context, NonCopyable { void deactivate_framebuffer(); VKFrameBuffer *active_framebuffer_get() const; + /** + * Ensure that the active framebuffer isn't rendering. + * + * Between `vkCmdBeginRendering` and `vkCmdEndRendering` the framebuffer is rendering. Dispatch + * and transfer commands cannot be called between these commands. They can call this method to + * ensure that the framebuffer is outside these calls. + */ + void rendering_end(); + void bind_compute_pipeline(); render_graph::VKResourceAccessInfo &update_and_get_access_info(); diff --git a/source/blender/gpu/vulkan/vk_framebuffer.cc b/source/blender/gpu/vulkan/vk_framebuffer.cc index de564227b9d..34f51754a35 100644 --- a/source/blender/gpu/vulkan/vk_framebuffer.cc +++ b/source/blender/gpu/vulkan/vk_framebuffer.cc @@ -99,19 +99,23 @@ void VKFrameBuffer::build_clear_attachments_depth_stencil( const eGPUFrameBufferBits buffers, float clear_depth, uint32_t clear_stencil, - Vector &r_attachments) const + render_graph::VKClearAttachmentsNode::CreateInfo &clear_attachments) const { - VkClearAttachment clear_attachment = {}; - clear_attachment.aspectMask = (buffers & GPU_DEPTH_BIT ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) | - (buffers & GPU_STENCIL_BIT ? VK_IMAGE_ASPECT_STENCIL_BIT : 0); + VkImageAspectFlags aspect_mask = (buffers & GPU_DEPTH_BIT ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) | + (buffers & GPU_STENCIL_BIT ? VK_IMAGE_ASPECT_STENCIL_BIT : 0); + + VkClearAttachment &clear_attachment = + clear_attachments.attachments[clear_attachments.attachment_count++]; + clear_attachment.aspectMask = aspect_mask; clear_attachment.clearValue.depthStencil.depth = clear_depth; clear_attachment.clearValue.depthStencil.stencil = clear_stencil; - r_attachments.append(clear_attachment); + clear_attachment.colorAttachment = 0; } -void VKFrameBuffer::build_clear_attachments_color(const float (*clear_colors)[4], - const bool multi_clear_colors, - Vector &r_attachments) const +void VKFrameBuffer::build_clear_attachments_color( + const float (*clear_colors)[4], + const bool multi_clear_colors, + render_graph::VKClearAttachmentsNode::CreateInfo &clear_attachments) const { int color_index = 0; for (int color_slot = 0; color_slot < GPU_FB_MAX_COLOR_ATTACHMENT; color_slot++) { @@ -119,13 +123,13 @@ void VKFrameBuffer::build_clear_attachments_color(const float (*clear_colors)[4] if (attachment.tex == nullptr) { continue; } - VkClearAttachment clear_attachment = {}; + VkClearAttachment &clear_attachment = + clear_attachments.attachments[clear_attachments.attachment_count++]; clear_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; clear_attachment.colorAttachment = color_slot; eGPUDataFormat data_format = to_data_format(GPU_texture_format(attachment.tex)); clear_attachment.clearValue.color = to_vk_clear_color_value(data_format, &clear_colors[color_index]); - r_attachments.append(clear_attachment); color_index += multi_clear_colors ? 1 : 0; } @@ -135,19 +139,19 @@ void VKFrameBuffer::build_clear_attachments_color(const float (*clear_colors)[4] /** \name Clear * \{ */ -void VKFrameBuffer::clear(const Span attachments) const +void VKFrameBuffer::clear(render_graph::VKClearAttachmentsNode::CreateInfo &clear_attachments) { - if (attachments.is_empty()) { - return; - } - VkClearRect clear_rect = {}; - clear_rect.rect = vk_render_areas_get()[0]; - clear_rect.baseArrayLayer = 0; - clear_rect.layerCount = 1; - VKContext &context = *VKContext::get(); - VKCommandBuffers &command_buffers = context.command_buffers_get(); - command_buffers.clear(attachments, Span(&clear_rect, 1)); + if (use_render_graph) { + rendering_ensure(context); + context.render_graph.add_node(clear_attachments); + } + else { + VKCommandBuffers &command_buffers = context.command_buffers_get(); + command_buffers.clear( + Span(clear_attachments.attachments, clear_attachments.attachment_count), + Span(&clear_attachments.vk_clear_rect, 1)); + } } void VKFrameBuffer::clear(const eGPUFrameBufferBits buffers, @@ -155,7 +159,11 @@ void VKFrameBuffer::clear(const eGPUFrameBufferBits buffers, float clear_depth, uint clear_stencil) { - Vector attachments; + render_graph::VKClearAttachmentsNode::CreateInfo clear_attachments = {}; + clear_attachments.vk_clear_rect.rect = vk_render_areas_get()[0]; + clear_attachments.vk_clear_rect.baseArrayLayer = 0; + clear_attachments.vk_clear_rect.layerCount = 1; + if (buffers & (GPU_DEPTH_BIT | GPU_STENCIL_BIT)) { VKContext &context = *VKContext::get(); eGPUWriteMask needed_mask = GPU_WRITE_NONE; @@ -169,7 +177,8 @@ void VKFrameBuffer::clear(const eGPUFrameBufferBits buffers, /* Clearing depth via vkCmdClearAttachments requires a render pass with write depth or stencil * enabled. When not enabled, clearing should be done via texture directly. */ if ((context.state_manager_get().state.write_mask & needed_mask) == needed_mask) { - build_clear_attachments_depth_stencil(buffers, clear_depth, clear_stencil, attachments); + build_clear_attachments_depth_stencil( + buffers, clear_depth, clear_stencil, clear_attachments); } else { VKTexture *depth_texture = unwrap(unwrap(depth_tex())); @@ -187,19 +196,25 @@ void VKFrameBuffer::clear(const eGPUFrameBufferBits buffers, if (buffers & GPU_COLOR_BIT) { float clear_color_single[4]; copy_v4_v4(clear_color_single, clear_color); - build_clear_attachments_color(&clear_color_single, false, attachments); + build_clear_attachments_color(&clear_color_single, false, clear_attachments); } - if (!attachments.is_empty()) { - clear(attachments); + if (clear_attachments.attachment_count) { + clear(clear_attachments); } } void VKFrameBuffer::clear_multi(const float (*clear_color)[4]) { - Vector attachments; - build_clear_attachments_color(clear_color, true, attachments); - clear(attachments); + render_graph::VKClearAttachmentsNode::CreateInfo clear_attachments = {}; + clear_attachments.vk_clear_rect.rect = vk_render_areas_get()[0]; + clear_attachments.vk_clear_rect.baseArrayLayer = 0; + clear_attachments.vk_clear_rect.layerCount = 1; + + build_clear_attachments_color(clear_color, true, clear_attachments); + if (clear_attachments.attachment_count) { + clear(clear_attachments); + } } void VKFrameBuffer::clear_attachment(GPUAttachmentType /*type*/, @@ -661,4 +676,62 @@ int VKFrameBuffer::color_attachments_resource_size() const /** \} */ +void VKFrameBuffer::rendering_reset() +{ + is_rendering_ = false; +} + +void VKFrameBuffer::rendering_ensure(VKContext &context) +{ + if (is_rendering_) { + return; + } + is_rendering_ = true; + + render_graph::VKResourceAccessInfo access_info; + render_graph::VKBeginRenderingNode::CreateInfo begin_rendering(access_info); + begin_rendering.node_data.vk_rendering_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; + begin_rendering.node_data.vk_rendering_info.layerCount = 1; + begin_rendering.node_data.vk_rendering_info.renderArea = vk_render_areas_get()[0]; + + for (int color_slot : IndexRange(GPU_FB_MAX_COLOR_ATTACHMENT)) { + VKTexture *color_texture = unwrap(unwrap(color_tex(color_slot))); + if (color_texture != nullptr) { + VkRenderingAttachmentInfo &attachment_info = + begin_rendering.node_data.color_attachments[begin_rendering.node_data.vk_rendering_info + .colorAttachmentCount++]; + attachment_info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + /* TODO attachment mip/layer */ + attachment_info.imageView = color_texture->image_view_get().vk_handle(); + attachment_info.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + /* TODO add load store ops. */ + attachment_info.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachment_info.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + access_info.images.append( + {color_texture->vk_image_handle(), + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_ASPECT_COLOR_BIT}); + + begin_rendering.node_data.vk_rendering_info.pColorAttachments = + begin_rendering.node_data.color_attachments; + } + } + + context.render_graph.add_node(begin_rendering); +} + +void VKFrameBuffer::rendering_end(VKContext &context) +{ + if (!is_rendering_ && use_explicit_load_store_) { + rendering_ensure(context); + } + + if (is_rendering_) { + render_graph::VKEndRenderingNode::CreateInfo end_rendering = {}; + context.render_graph.add_node(end_rendering); + is_rendering_ = false; + } +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_framebuffer.hh b/source/blender/gpu/vulkan/vk_framebuffer.hh index 401ff1e2a6e..35d8df2aab2 100644 --- a/source/blender/gpu/vulkan/vk_framebuffer.hh +++ b/source/blender/gpu/vulkan/vk_framebuffer.hh @@ -15,6 +15,7 @@ #include "gpu_framebuffer_private.hh" +#include "render_graph/vk_render_graph.hh" #include "vk_common.hh" #include "vk_image_view.hh" @@ -37,6 +38,7 @@ class VKFrameBuffer : public FrameBuffer { /** Is the first attachment an SRGB texture. */ bool srgb_; bool enabled_srgb_; + bool is_rendering_ = false; public: /** @@ -59,6 +61,9 @@ class VKFrameBuffer : public FrameBuffer { void attachment_set_loadstore_op(GPUAttachmentType type, GPULoadStore /*ls*/) override; + void begin_rendering(VKContext &context); + void end_rendering(VKContext &context); + protected: void subpass_transition_impl(const GPUAttachmentState depth_attachment_state, Span color_attachment_states) override; @@ -117,6 +122,27 @@ class VKFrameBuffer : public FrameBuffer { void update_srgb(); + /** + * Mark this framebuffer to be not being rendered on. + * + * Between binding a framebuffer and actually using it the state and clear operations can change. + * The rendering state is used to find out if the framebuffer begin rendering command should be + * recorded + */ + void rendering_reset(); + + /** + * Ensure that the framebuffer is ready to be rendered on and that its state is up to date with + * the latest changes that can happen between drawing commands inside `VKStateManager`. + */ + void rendering_ensure(VKContext &context); + + /** + * End the rendering on this framebuffer. + * Is being triggered when framebuffer is deactivated or when + */ + void rendering_end(VKContext &context); + /** * Return the number of color attachments of this frame buffer, including unused color * attachments. @@ -132,14 +158,16 @@ class VKFrameBuffer : public FrameBuffer { void render_pass_create(); /* Clearing attachments */ - void build_clear_attachments_depth_stencil(eGPUFrameBufferBits buffers, - float clear_depth, - uint32_t clear_stencil, - Vector &r_attachments) const; - void build_clear_attachments_color(const float (*clear_colors)[4], - const bool multi_clear_colors, - Vector &r_attachments) const; - void clear(Span attachments) const; + void build_clear_attachments_depth_stencil( + eGPUFrameBufferBits buffers, + float clear_depth, + uint32_t clear_stencil, + render_graph::VKClearAttachmentsNode::CreateInfo &clear_attachments) const; + void build_clear_attachments_color( + const float (*clear_colors)[4], + const bool multi_clear_colors, + render_graph::VKClearAttachmentsNode::CreateInfo &clear_attachments) const; + void clear(render_graph::VKClearAttachmentsNode::CreateInfo &clear_attachments); }; static inline VKFrameBuffer *unwrap(FrameBuffer *framebuffer) diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index e60be318d5b..b81e3f2562c 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -11,6 +11,7 @@ #include "vk_buffer.hh" #include "vk_context.hh" #include "vk_data_conversion.hh" +#include "vk_framebuffer.hh" #include "vk_memory.hh" #include "vk_shader.hh" #include "vk_shader_interface.hh" @@ -285,6 +286,7 @@ void VKTexture::read_sub( VKContext &context = *VKContext::get(); if (use_render_graph) { + context.rendering_end(); context.render_graph.add_node(copy_image_to_buffer); context.render_graph.submit_buffer_for_read(staging_buffer.vk_handle()); } diff --git a/source/blender/gpu/vulkan/vk_to_string.cc b/source/blender/gpu/vulkan/vk_to_string.cc index 6dc4fe0bde6..0fdf8b9d631 100644 --- a/source/blender/gpu/vulkan/vk_to_string.cc +++ b/source/blender/gpu/vulkan/vk_to_string.cc @@ -30,6 +30,11 @@ std::string to_string(VkImage vk_handle) return to_string_handle(uint64_t(vk_handle)); } +std::string to_string(VkImageView vk_handle) +{ + return to_string_handle(uint64_t(vk_handle)); +} + std::string to_string(VkRenderPass vk_handle) { return to_string_handle(uint64_t(vk_handle)); @@ -835,10 +840,10 @@ std::string to_string(const VkRenderingAttachmentInfo &vk_rendering_attachment_i { UNUSED_VARS(indentation_level); std::stringstream ss; - ss << "image_view=" << vk_rendering_attachment_info.imageView; + ss << "image_view=" << to_string(vk_rendering_attachment_info.imageView); ss << ", image_layout=" << to_string(vk_rendering_attachment_info.imageLayout); ss << ", resolve_mode=" << to_string(vk_rendering_attachment_info.resolveMode); - ss << ", resolve_image_view=" << vk_rendering_attachment_info.resolveImageView; + ss << ", resolve_image_view=" << to_string(vk_rendering_attachment_info.resolveImageView); ss << ", resolve_image_layout=" << to_string(vk_rendering_attachment_info.resolveImageLayout); ss << ", load_op=" << to_string(vk_rendering_attachment_info.loadOp); ss << ", store_op=" << to_string(vk_rendering_attachment_info.storeOp); diff --git a/source/blender/gpu/vulkan/vk_to_string.hh b/source/blender/gpu/vulkan/vk_to_string.hh index 8c7c1ea62fb..44e7212d123 100644 --- a/source/blender/gpu/vulkan/vk_to_string.hh +++ b/source/blender/gpu/vulkan/vk_to_string.hh @@ -12,6 +12,7 @@ namespace blender::gpu { std::string to_string(VkImage vk_handle); +std::string to_string(VkImageView vk_handle); std::string to_string(VkBuffer vk_handle); std::string to_string(VkDescriptorSet vk_handle); std::string to_string(VkPipeline vk_handle);