Vulkan: Render graph clear attachments
Adds support for clear attachments to the render graph. Clearing attachments require that the command buffer is being set for rendering (vkCmdBeginRendering). **What works** - Clear attachments are working with dynamic rendering and the render graph - `GPUVulkanTest.framebuffer_clear_color_single_attachment` - `GPUVulkanTest.framebuffer_clear_color_multiple_attachments` - `GPUVulkanTest.framebuffer_clear_multiple_color_multiple_attachments` - `GPUVulkanTest.framebuffer_scissor_test` - `GPUVulkanTest.framebuffer_clear_depth` **What still needs to be addressed** When a command buffer is rendering it cannot do any pipeline barriers. For clearing attachments this isn't needed, but when we address drawing we might need to register drawing resource dependencies to the dependency list of the begin rendering node. This will be solved when drawing will be implemented. [#121648] The begin rendering node is large as it has to store data for framebuffers with 8 color attachments as well. This might become an overhead and we could solve this by splicing the data of larger nodes into 2 lists. This will be addressed after we are able to draw a screen so we can collect data on this topic. [#121649] Pull Request: https://projects.blender.org/blender/blender/pulls/121073
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user