Vulkan: Render graph clear attachments #121073

Merged
Jeroen Bakker merged 19 commits from Jeroen-Bakker/blender:vulkan/render-graph-clear-attachments into main 2024-05-10 15:40:13 +02:00
16 changed files with 618 additions and 43 deletions

View File

@ -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()

View File

@ -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<VKNodeType::BEGIN_RENDERING,
VKBeginRenderingCreateInfo,
VKBeginRenderingData,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
VKResourceType::IMAGE> {
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<typename Node> 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

View File

@ -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<VKNodeType::CLEAR_ATTACHMENTS,
VKClearAttachmentsData,
VKClearAttachmentsData,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VKResourceType::IMAGE> {
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<typename Node> 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

View File

@ -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<VKNodeType::END_RENDERING,
VKEndRenderingData,
VKEndRenderingData,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
VKResourceType::NONE> {
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<typename Node> 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

View File

@ -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<VKNodeType NodeType,
typename NodeCreateInfo,
typename NodeData,
VkPipelineStageFlagBits PipelineStage,
VkPipelineStageFlags PipelineStage,
VKResourceType ResourceUsages>
class VKNodeInfo : public NonCopyable {

View File

@ -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<VkImage> image(1u);
VkHandle<VkImageView> image_view(2u);
VkHandle<VkBuffer> buffer(3u);
Vector<std::string> log;
VKCommandBufferWrapper wrapper;
VKResourceStateTracker resources;
VKRenderGraph render_graph(std::make_unique<CommandBufferLog>(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

View File

@ -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<VkClearAttachment>(p_attachments, attachment_count))
{
ss << " - attachment(" << to_string(attachment, 1) << ")" << std::endl;
}
for (const VkClearRect &rect : Span<VkClearRect>(p_rects, rect_count)) {
ss << " - rect(" << to_string(rect, 1) << ")" << std::endl;
}
ss << ")";
log_.append(ss.str());
}
void pipeline_barrier(VkPipelineStageFlags src_stage_mask,

View File

@ -128,6 +128,18 @@ class VKRenderGraph : public NonCopyable {
}
public:
void add_node(const VKBeginRenderingNode::CreateInfo &begin_rendering)
{
add_node<VKBeginRenderingNode>(begin_rendering);
}
void add_node(const VKEndRenderingNode::CreateInfo &end_rendering)
{
add_node<VKEndRenderingNode>(end_rendering);
}
void add_node(const VKClearAttachmentsNode::CreateInfo &clear_attachments)
{
add_node<VKClearAttachmentsNode>(clear_attachments);
}
void add_node(const VKClearColorImageNode::CreateInfo &clear_color_image)
{
add_node<VKClearColorImageNode>(clear_color_image);

View File

@ -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:

View File

@ -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);
}
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -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();

View File

@ -99,19 +99,23 @@ void VKFrameBuffer::build_clear_attachments_depth_stencil(
const eGPUFrameBufferBits buffers,
float clear_depth,
uint32_t clear_stencil,
Vector<VkClearAttachment> &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<VkClearAttachment> &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<VkClearAttachment> 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<VkClearRect>(&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<VkClearAttachment>(clear_attachments.attachments, clear_attachments.attachment_count),
Span<VkClearRect>(&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<VkClearAttachment> 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<VkClearAttachment> 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

View File

@ -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<GPUAttachmentState> 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<VkClearAttachment> &r_attachments) const;
void build_clear_attachments_color(const float (*clear_colors)[4],
const bool multi_clear_colors,
Vector<VkClearAttachment> &r_attachments) const;
void clear(Span<VkClearAttachment> 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)

View File

@ -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());
}

View File

@ -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);

View File

@ -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);