Vulkan: Render graph dispatch indirect #120993

Merged
Jeroen Bakker merged 4 commits from Jeroen-Bakker/blender:vulkan/render-graph-dispatch-indirect into main 2024-04-24 21:28:57 +02:00
13 changed files with 391 additions and 107 deletions

View File

@ -219,6 +219,7 @@ set(VULKAN_SRC
vulkan/vk_pixel_buffer.cc
vulkan/vk_push_constants.cc
vulkan/vk_query.cc
vulkan/render_graph/nodes/vk_pipeline_data.cc
vulkan/render_graph/vk_command_buffer_wrapper.cc
vulkan/render_graph/vk_command_builder.cc
vulkan/render_graph/vk_resource_access_info.cc

View File

@ -0,0 +1,87 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#pragma once
#include "render_graph/vk_render_graph_links.hh"
#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 VKDispatchIndirectData {
VKPipelineData pipeline_data;
VkBuffer buffer;
VkDeviceSize offset;
};
/**
* Information needed to add a node to the render graph.
*/
struct VKDispatchIndirectCreateInfo : NonCopyable {
VKDispatchIndirectData dispatch_indirect_node = {};
const VKResourceAccessInfo &resources;
VKDispatchIndirectCreateInfo(const VKResourceAccessInfo &resources) : resources(resources) {}
};
class VKDispatchIndirectNode : public VKNodeInfo<VKNodeType::DISPATCH_INDIRECT,
VKDispatchIndirectCreateInfo,
VKDispatchIndirectData,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VKResourceType::IMAGE | VKResourceType::BUFFER> {
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.dispatch_indirect = create_info.dispatch_indirect_node;
vk_pipeline_data_copy(node.dispatch_indirect.pipeline_data,
create_info.dispatch_indirect_node.pipeline_data);
}
/**
* Free the pipeline data stored in the render graph node data.
*/
void free_data(VKDispatchIndirectData &data)
{
vk_pipeline_data_free(data.pipeline_data);
}
/**
* 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);
ResourceWithStamp buffer_resource = resources.get_buffer(
create_info.dispatch_indirect_node.buffer);
node_links.inputs.append({buffer_resource, VK_ACCESS_INDIRECT_COMMAND_READ_BIT});
}
/**
* Build the commands and add them to the command_buffer.
*/
void build_commands(VKCommandBufferInterface &command_buffer,
const Data &data,
VKBoundPipelines &r_bound_pipelines) override
{
vk_pipeline_data_build_commands(
command_buffer, data.pipeline_data, r_bound_pipelines, VK_PIPELINE_BIND_POINT_COMPUTE);
command_buffer.dispatch_indirect(data.buffer, data.offset);
}
};
} // namespace blender::gpu::render_graph

View File

@ -27,8 +27,9 @@ struct VKDispatchData {
* Information needed to add a node to the render graph.
*/
struct VKDispatchCreateInfo : NonCopyable {
VKDispatchData dispatch_node;
VKResourceAccessInfo resources;
VKDispatchData dispatch_node = {};
const VKResourceAccessInfo &resources;
VKDispatchCreateInfo(const VKResourceAccessInfo &resources) : resources(resources) {}
};
class VKDispatchNode : public VKNodeInfo<VKNodeType::DISPATCH,
@ -75,33 +76,8 @@ class VKDispatchNode : public VKNodeInfo<VKNodeType::DISPATCH,
const Data &data,
VKBoundPipelines &r_bound_pipelines) override
{
/* TODO: introduce helper function in pipeline types. */
const VKPipelineData &pipeline_data = data.pipeline_data;
if (assign_if_different(r_bound_pipelines.compute.vk_pipeline, pipeline_data.vk_pipeline)) {
command_buffer.bind_pipeline(VK_PIPELINE_BIND_POINT_COMPUTE,
r_bound_pipelines.compute.vk_pipeline);
}
if (assign_if_different(r_bound_pipelines.compute.vk_descriptor_set,
pipeline_data.vk_descriptor_set))
{
command_buffer.bind_descriptor_sets(VK_PIPELINE_BIND_POINT_COMPUTE,
pipeline_data.vk_pipeline_layout,
0,
1,
&r_bound_pipelines.compute.vk_descriptor_set,
0,
nullptr);
}
if (pipeline_data.push_constants_size) {
command_buffer.push_constants(pipeline_data.vk_pipeline_layout,
VK_SHADER_STAGE_COMPUTE_BIT,
0,
pipeline_data.push_constants_size,
pipeline_data.push_constants_data);
}
vk_pipeline_data_build_commands(
command_buffer, data.pipeline_data, r_bound_pipelines, VK_PIPELINE_BIND_POINT_COMPUTE);
command_buffer.dispatch(data.group_count_x, data.group_count_y, data.group_count_z);
}
};

View File

@ -30,6 +30,7 @@ enum class VKNodeType {
COPY_BUFFER_TO_IMAGE,
BLIT_IMAGE,
DISPATCH,
DISPATCH_INDIRECT,
SYNCHRONIZATION,
};

View File

@ -0,0 +1,60 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#include "render_graph/nodes/vk_pipeline_data.hh"
#include "render_graph/vk_command_buffer_wrapper.hh"
namespace blender::gpu::render_graph {
void vk_pipeline_data_copy(VKPipelineData &dst, const VKPipelineData &src)
{
dst.push_constants_data = nullptr;
dst.push_constants_size = src.push_constants_size;
if (src.push_constants_size) {
BLI_assert(src.push_constants_data);
void *data = MEM_mallocN(src.push_constants_size, __func__);
memcpy(data, src.push_constants_data, src.push_constants_size);
dst.push_constants_data = data;
}
}
void vk_pipeline_data_build_commands(VKCommandBufferInterface &command_buffer,
const VKPipelineData &pipeline_data,
VKBoundPipelines &r_bound_pipelines,
VkPipelineBindPoint vk_pipeline_bind_point)
{
if (assign_if_different(r_bound_pipelines.compute.vk_pipeline, pipeline_data.vk_pipeline)) {
command_buffer.bind_pipeline(vk_pipeline_bind_point, r_bound_pipelines.compute.vk_pipeline);
}
if (assign_if_different(r_bound_pipelines.compute.vk_descriptor_set,
pipeline_data.vk_descriptor_set))
{
command_buffer.bind_descriptor_sets(vk_pipeline_bind_point,
pipeline_data.vk_pipeline_layout,
0,
1,
&r_bound_pipelines.compute.vk_descriptor_set,
0,
nullptr);
}
if (pipeline_data.push_constants_size) {
command_buffer.push_constants(pipeline_data.vk_pipeline_layout,
vk_pipeline_bind_point,
0,
pipeline_data.push_constants_size,
pipeline_data.push_constants_data);
}
}
void vk_pipeline_data_free(VKPipelineData &data)
{
MEM_SAFE_FREE(data.push_constants_data);
}
} // namespace blender::gpu::render_graph

View File

@ -11,6 +11,8 @@
#include "vk_common.hh"
namespace blender::gpu::render_graph {
class VKCommandBufferInterface;
/**
* Container for storing shader descriptor set and push constants.
*
@ -24,6 +26,23 @@ struct VKPipelineData {
const void *push_constants_data;
};
/** Resources bound for a compute/graphics pipeline. */
struct VKBoundPipeline {
VkPipeline vk_pipeline;
VkDescriptorSet vk_descriptor_set;
};
/**
* Vulkan keeps track of bound resources for graphics separate from compute.
* This struct store last bound resources for both bind points.
*/
struct VKBoundPipelines {
/** Last bound resources for compute pipeline. */
VKBoundPipeline compute;
/** Last bound resources for graphics pipeline. */
VKBoundPipeline graphics;
};
/**
* Copy src pipeline data into dst. The push_constant_data will be duplicated and needs to be freed
* using `vk_pipeline_data_free`.
@ -31,33 +50,26 @@ struct VKPipelineData {
* Memory duplication isn't used as push_constant_data in the src doesn't need to be allocated via
* guardedalloc.
*/
BLI_INLINE void vk_pipeline_data_copy(VKPipelineData &dst, const VKPipelineData &src)
{
dst.push_constants_data = nullptr;
dst.push_constants_size = src.push_constants_size;
if (src.push_constants_size) {
BLI_assert(src.push_constants_data);
void *data = MEM_mallocN(src.push_constants_size, __func__);
memcpy(data, src.push_constants_data, src.push_constants_size);
dst.push_constants_data = data;
}
}
void vk_pipeline_data_copy(VKPipelineData &dst, const VKPipelineData &src);
/**
* Record the commands to the given command buffer to bind the descriptor set, pipeline and push
* constants.
*
* Descriptor set and pipeline are only bound, when they are different than the last bound. The
* r_bound_pipelines are checked to identify if they are the last bound. Descriptor set and
* pipeline are bound at the given pipeline bind point.
*
* Any available push constants in the pipeline data are always bound.
*/
void vk_pipeline_data_build_commands(VKCommandBufferInterface &command_buffer,
const VKPipelineData &pipeline_data,
VKBoundPipelines &r_bound_pipelines,
VkPipelineBindPoint vk_pipeline_bind_point);
/**
* Free localized data created by `vk_pipeline_data_copy`.
*/
BLI_INLINE void vk_pipeline_data_free(VKPipelineData &data)
{
MEM_SAFE_FREE(data.push_constants_data);
}
struct VKBoundPipeline {
VkPipeline vk_pipeline;
VkDescriptorSet vk_descriptor_set;
};
struct VKBoundPipelines {
VKBoundPipeline compute;
VKBoundPipeline graphics;
};
void vk_pipeline_data_free(VKPipelineData &data);
} // namespace blender::gpu::render_graph

View File

@ -20,15 +20,15 @@ TEST(vk_render_graph, dispatch_read_back)
VKResourceStateTracker resources;
VKRenderGraph render_graph(std::make_unique<CommandBufferLog>(log), resources);
resources.add_buffer(buffer);
VKDispatchNode::CreateInfo dispatch_info = {};
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchNode::CreateInfo dispatch_info(access_info);
dispatch_info.dispatch_node.pipeline_data.vk_pipeline = pipeline;
dispatch_info.dispatch_node.pipeline_data.vk_pipeline_layout = pipeline_layout;
dispatch_info.dispatch_node.pipeline_data.vk_descriptor_set = descriptor_set;
dispatch_info.dispatch_node.group_count_x = 1;
dispatch_info.dispatch_node.group_count_y = 1;
dispatch_info.dispatch_node.group_count_z = 1;
dispatch_info.resources.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
render_graph.add_node(dispatch_info);
render_graph.submit_buffer_for_read(buffer);
EXPECT_EQ(3, log.size());
@ -58,25 +58,27 @@ TEST(vk_render_graph, dispatch_dispatch_read_back)
resources.add_buffer(buffer);
{
VKDispatchNode::CreateInfo dispatch_info = {};
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchNode::CreateInfo dispatch_info(access_info);
dispatch_info.dispatch_node.pipeline_data.vk_pipeline = pipeline;
dispatch_info.dispatch_node.pipeline_data.vk_pipeline_layout = pipeline_layout;
dispatch_info.dispatch_node.pipeline_data.vk_descriptor_set = descriptor_set;
dispatch_info.dispatch_node.group_count_x = 1;
dispatch_info.dispatch_node.group_count_y = 1;
dispatch_info.dispatch_node.group_count_z = 1;
dispatch_info.resources.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
render_graph.add_node(dispatch_info);
}
{
VKDispatchNode::CreateInfo dispatch_info = {};
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchNode::CreateInfo dispatch_info(access_info);
dispatch_info.dispatch_node.pipeline_data.vk_pipeline = pipeline;
dispatch_info.dispatch_node.pipeline_data.vk_pipeline_layout = pipeline_layout;
dispatch_info.dispatch_node.pipeline_data.vk_descriptor_set = descriptor_set;
dispatch_info.dispatch_node.group_count_x = 2;
dispatch_info.dispatch_node.group_count_y = 2;
dispatch_info.dispatch_node.group_count_z = 2;
dispatch_info.resources.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
render_graph.add_node(dispatch_info);
}
render_graph.submit_buffer_for_read(buffer);
@ -119,25 +121,27 @@ TEST(vk_render_graph, dispatch_dispatch_read_back_with_changing_descriptor_sets)
resources.add_buffer(buffer);
{
VKDispatchNode::CreateInfo dispatch_info = {};
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchNode::CreateInfo dispatch_info(access_info);
dispatch_info.dispatch_node.pipeline_data.vk_pipeline = pipeline;
dispatch_info.dispatch_node.pipeline_data.vk_pipeline_layout = pipeline_layout;
dispatch_info.dispatch_node.pipeline_data.vk_descriptor_set = descriptor_set_a;
dispatch_info.dispatch_node.group_count_x = 1;
dispatch_info.dispatch_node.group_count_y = 1;
dispatch_info.dispatch_node.group_count_z = 1;
dispatch_info.resources.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
render_graph.add_node(dispatch_info);
}
{
VKDispatchNode::CreateInfo dispatch_info = {};
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchNode::CreateInfo dispatch_info(access_info);
dispatch_info.dispatch_node.pipeline_data.vk_pipeline = pipeline;
dispatch_info.dispatch_node.pipeline_data.vk_pipeline_layout = pipeline_layout;
dispatch_info.dispatch_node.pipeline_data.vk_descriptor_set = descriptor_set_b;
dispatch_info.dispatch_node.group_count_x = 2;
dispatch_info.dispatch_node.group_count_y = 2;
dispatch_info.dispatch_node.group_count_z = 2;
dispatch_info.resources.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
render_graph.add_node(dispatch_info);
}
render_graph.submit_buffer_for_read(buffer);
@ -183,25 +187,27 @@ TEST(vk_render_graph, dispatch_dispatch_read_back_with_changing_pipelines)
resources.add_buffer(buffer);
{
VKDispatchNode::CreateInfo dispatch_info = {};
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchNode::CreateInfo dispatch_info(access_info);
dispatch_info.dispatch_node.pipeline_data.vk_pipeline = pipeline_a;
dispatch_info.dispatch_node.pipeline_data.vk_pipeline_layout = pipeline_layout;
dispatch_info.dispatch_node.pipeline_data.vk_descriptor_set = descriptor_set;
dispatch_info.dispatch_node.group_count_x = 1;
dispatch_info.dispatch_node.group_count_y = 1;
dispatch_info.dispatch_node.group_count_z = 1;
dispatch_info.resources.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
render_graph.add_node(dispatch_info);
}
{
VKDispatchNode::CreateInfo dispatch_info = {};
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchNode::CreateInfo dispatch_info(access_info);
dispatch_info.dispatch_node.pipeline_data.vk_pipeline = pipeline_b;
dispatch_info.dispatch_node.pipeline_data.vk_pipeline_layout = pipeline_layout;
dispatch_info.dispatch_node.pipeline_data.vk_descriptor_set = descriptor_set;
dispatch_info.dispatch_node.group_count_x = 2;
dispatch_info.dispatch_node.group_count_y = 2;
dispatch_info.dispatch_node.group_count_z = 2;
dispatch_info.resources.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
render_graph.add_node(dispatch_info);
}
render_graph.submit_buffer_for_read(buffer);
@ -247,25 +253,27 @@ TEST(vk_render_graph, dispatch_dispatch_read_back_with_changing_pipelines_descri
resources.add_buffer(buffer);
{
VKDispatchNode::CreateInfo dispatch_info = {};
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchNode::CreateInfo dispatch_info(access_info);
dispatch_info.dispatch_node.pipeline_data.vk_pipeline = pipeline_a;
dispatch_info.dispatch_node.pipeline_data.vk_pipeline_layout = pipeline_layout;
dispatch_info.dispatch_node.pipeline_data.vk_descriptor_set = descriptor_set_a;
dispatch_info.dispatch_node.group_count_x = 1;
dispatch_info.dispatch_node.group_count_y = 1;
dispatch_info.dispatch_node.group_count_z = 1;
dispatch_info.resources.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
render_graph.add_node(dispatch_info);
}
{
VKDispatchNode::CreateInfo dispatch_info = {};
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchNode::CreateInfo dispatch_info(access_info);
dispatch_info.dispatch_node.pipeline_data.vk_pipeline = pipeline_b;
dispatch_info.dispatch_node.pipeline_data.vk_pipeline_layout = pipeline_layout;
dispatch_info.dispatch_node.pipeline_data.vk_descriptor_set = descriptor_set_b;
dispatch_info.dispatch_node.group_count_x = 2;
dispatch_info.dispatch_node.group_count_y = 2;
dispatch_info.dispatch_node.group_count_z = 2;
dispatch_info.resources.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
render_graph.add_node(dispatch_info);
}
render_graph.submit_buffer_for_read(buffer);
@ -295,4 +303,120 @@ TEST(vk_render_graph, dispatch_dispatch_read_back_with_changing_pipelines_descri
EXPECT_EQ("dispatch(group_count_x=2, group_count_y=2, group_count_z=2)", log[6]);
}
/**
* Test dispatch indirect
*/
TEST(vk_render_graph, dispatch_indirect_read_back)
{
VkHandle<VkBuffer> buffer(1u);
VkHandle<VkBuffer> command_buffer(2u);
VkHandle<VkPipeline> pipeline(3u);
VkHandle<VkPipelineLayout> pipeline_layout(4u);
VkHandle<VkDescriptorSet> descriptor_set(5u);
Vector<std::string> log;
VKCommandBufferWrapper wrapper;
VKResourceStateTracker resources;
VKRenderGraph render_graph(std::make_unique<CommandBufferLog>(log), resources);
resources.add_buffer(buffer);
resources.add_buffer(command_buffer);
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchIndirectNode::CreateInfo dispatch_indirect_info(access_info);
dispatch_indirect_info.dispatch_indirect_node.pipeline_data.vk_pipeline = pipeline;
dispatch_indirect_info.dispatch_indirect_node.pipeline_data.vk_pipeline_layout = pipeline_layout;
dispatch_indirect_info.dispatch_indirect_node.pipeline_data.vk_descriptor_set = descriptor_set;
dispatch_indirect_info.dispatch_indirect_node.buffer = command_buffer;
dispatch_indirect_info.dispatch_indirect_node.offset = 0;
render_graph.add_node(dispatch_indirect_info);
render_graph.submit_buffer_for_read(buffer);
EXPECT_EQ(4, log.size());
EXPECT_EQ(
"pipeline_barrier(src_stage_mask=VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "
"dst_stage_mask=VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT" +
endl() +
" - buffer_barrier(src_access_mask=, "
"dst_access_mask=VK_ACCESS_INDIRECT_COMMAND_READ_BIT, buffer=0x2, offset=0, "
"size=18446744073709551615)" +
endl() + ")",
log[0]);
EXPECT_EQ("bind_pipeline(pipeline_bind_point=VK_PIPELINE_BIND_POINT_COMPUTE, pipeline=0x3)",
log[1]);
EXPECT_EQ(
"bind_descriptor_sets(pipeline_bind_point=VK_PIPELINE_BIND_POINT_COMPUTE, layout=0x4, "
"p_descriptor_sets=0x5)",
log[2]);
EXPECT_EQ("dispatch_indirect(buffer=0x2, offset=0)", log[3]);
}
TEST(vk_render_graph, dispatch_indirect_dispatch_indirect_read_back)
{
VkHandle<VkBuffer> buffer(1u);
VkHandle<VkBuffer> command_buffer(2u);
VkHandle<VkPipeline> pipeline(3u);
VkHandle<VkPipelineLayout> pipeline_layout(4u);
VkHandle<VkDescriptorSet> descriptor_set(5u);
Vector<std::string> log;
VKCommandBufferWrapper wrapper;
VKResourceStateTracker resources;
VKRenderGraph render_graph(std::make_unique<CommandBufferLog>(log), resources);
resources.add_buffer(buffer);
resources.add_buffer(command_buffer);
{
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchIndirectNode::CreateInfo dispatch_indirect_info(access_info);
dispatch_indirect_info.dispatch_indirect_node.pipeline_data.vk_pipeline = pipeline;
dispatch_indirect_info.dispatch_indirect_node.pipeline_data.vk_pipeline_layout =
pipeline_layout;
dispatch_indirect_info.dispatch_indirect_node.pipeline_data.vk_descriptor_set = descriptor_set;
dispatch_indirect_info.dispatch_indirect_node.buffer = command_buffer;
dispatch_indirect_info.dispatch_indirect_node.offset = 0;
render_graph.add_node(dispatch_indirect_info);
}
{
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer, VK_ACCESS_SHADER_WRITE_BIT});
VKDispatchIndirectNode::CreateInfo dispatch_indirect_info(access_info);
dispatch_indirect_info.dispatch_indirect_node.pipeline_data.vk_pipeline = pipeline;
dispatch_indirect_info.dispatch_indirect_node.pipeline_data.vk_pipeline_layout =
pipeline_layout;
dispatch_indirect_info.dispatch_indirect_node.pipeline_data.vk_descriptor_set = descriptor_set;
dispatch_indirect_info.dispatch_indirect_node.buffer = command_buffer;
dispatch_indirect_info.dispatch_indirect_node.offset = 12;
render_graph.add_node(dispatch_indirect_info);
}
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_COMPUTE_SHADER_BIT" +
endl() +
" - buffer_barrier(src_access_mask=, "
"dst_access_mask=VK_ACCESS_INDIRECT_COMMAND_READ_BIT, buffer=0x2, offset=0, "
"size=18446744073709551615)" +
endl() + ")",
log[0]);
EXPECT_EQ("bind_pipeline(pipeline_bind_point=VK_PIPELINE_BIND_POINT_COMPUTE, pipeline=0x3)",
log[1]);
EXPECT_EQ(
"bind_descriptor_sets(pipeline_bind_point=VK_PIPELINE_BIND_POINT_COMPUTE, layout=0x4, "
"p_descriptor_sets=0x5)",
log[2]);
EXPECT_EQ("dispatch_indirect(buffer=0x2, offset=0)", log[3]);
EXPECT_EQ(
"pipeline_barrier(src_stage_mask=VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, "
"dst_stage_mask=VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT" +
endl() +
" - buffer_barrier(src_access_mask=VK_ACCESS_SHADER_WRITE_BIT, "
"dst_access_mask=VK_ACCESS_SHADER_WRITE_BIT, buffer=0x1, offset=0, "
"size=18446744073709551615)" +
endl() + ")",
log[4]);
EXPECT_EQ("dispatch_indirect(buffer=0x2, offset=12)", log[5]);
}
} // namespace blender::gpu::render_graph

View File

@ -186,10 +186,14 @@ class CommandBufferLog : public VKCommandBufferInterface {
void dispatch_indirect(VkBuffer buffer, VkDeviceSize offset) override
{
UNUSED_VARS(buffer, offset);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
std::stringstream ss;
ss << "dispatch_indirect(";
ss << "buffer=" << to_string(buffer);
ss << ", offset=" << offset;
ss << ")";
log_.append(ss.str());
}
void copy_buffer(VkBuffer src_buffer,

View File

@ -164,6 +164,10 @@ class VKRenderGraph : public NonCopyable {
{
add_node<VKDispatchNode>(dispatch);
}
void add_node(const VKDispatchIndirectNode::CreateInfo &dispatch)
{
add_node<VKDispatchIndirectNode>(dispatch);
}
/**
* Submit partial graph to be able to read the expected result of the rendering commands

View File

@ -15,6 +15,7 @@
#include "nodes/vk_copy_buffer_to_image_node.hh"
#include "nodes/vk_copy_image_node.hh"
#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_fill_buffer_node.hh"
#include "nodes/vk_synchronization_node.hh"
@ -44,6 +45,7 @@ struct VKRenderGraphNode {
VKCopyImageNode::Data copy_image;
VKCopyImageToBufferNode::Data copy_image_to_buffer;
VKDispatchNode::Data dispatch;
VKDispatchIndirectNode::Data dispatch_indirect;
VKFillBufferNode::Data fill_buffer;
VKSynchronizationNode::Data synchronization;
};
@ -110,6 +112,8 @@ struct VKRenderGraphNode {
return VKBlitImageNode::pipeline_stage;
case VKNodeType::DISPATCH:
return VKDispatchNode::pipeline_stage;
case VKNodeType::DISPATCH_INDIRECT:
return VKDispatchIndirectNode::pipeline_stage;
case VKNodeType::SYNCHRONIZATION:
return VKSynchronizationNode::pipeline_stage;
}
@ -190,6 +194,12 @@ struct VKRenderGraphNode {
node_info.build_commands(command_buffer, dispatch, r_bound_pipelines);
break;
}
case VKNodeType::DISPATCH_INDIRECT: {
VKDispatchIndirectNode node_info;
node_info.build_commands(command_buffer, dispatch_indirect, r_bound_pipelines);
break;
}
}
}
@ -205,6 +215,12 @@ struct VKRenderGraphNode {
break;
}
case VKNodeType::DISPATCH_INDIRECT: {
VKDispatchIndirectNode node_info;
node_info.free_data(dispatch_indirect);
break;
}
case VKNodeType::UNUSED:
case VKNodeType::CLEAR_COLOR_IMAGE:
case VKNodeType::CLEAR_DEPTH_STENCIL_IMAGE:

View File

@ -141,7 +141,9 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_
{
VKContext &context = *VKContext::get();
if (use_render_graph) {
render_graph::VKDispatchCreateInfo &dispatch_info = context.update_and_get_dispatch_info();
render_graph::VKResourceAccessInfo &resources = context.update_and_get_access_info();
render_graph::VKDispatchNode::CreateInfo dispatch_info(resources);
context.update_pipeline_data(dispatch_info.dispatch_node.pipeline_data);
dispatch_info.dispatch_node.group_count_x = groups_x_len;
dispatch_info.dispatch_node.group_count_y = groups_y_len;
dispatch_info.dispatch_node.group_count_z = groups_z_len;
@ -160,12 +162,22 @@ void VKBackend::compute_dispatch_indirect(StorageBuf *indirect_buf)
{
BLI_assert(indirect_buf);
VKContext &context = *VKContext::get();
render_graph::VKResourceAccessInfo resource_access_info = {};
context.state_manager_get().apply_bindings(context, resource_access_info);
context.bind_compute_pipeline();
VKStorageBuffer &indirect_buffer = *unwrap(indirect_buf);
VKCommandBuffers &command_buffers = context.command_buffers_get();
command_buffers.dispatch(indirect_buffer);
if (use_render_graph) {
render_graph::VKResourceAccessInfo &resources = context.update_and_get_access_info();
render_graph::VKDispatchIndirectNode::CreateInfo dispatch_indirect_info(resources);
context.update_pipeline_data(dispatch_indirect_info.dispatch_indirect_node.pipeline_data);
dispatch_indirect_info.dispatch_indirect_node.buffer = indirect_buffer.vk_handle();
dispatch_indirect_info.dispatch_indirect_node.offset = 0;
context.render_graph.add_node(dispatch_indirect_info);
}
else {
render_graph::VKResourceAccessInfo resource_access_info = {};
context.state_manager_get().apply_bindings(context, resource_access_info);
context.bind_compute_pipeline();
VKCommandBuffers &command_buffers = context.command_buffers_get();
command_buffers.dispatch(indirect_buffer);
}
}
Context *VKBackend::context_alloc(void *ghost_window, void *ghost_context)

View File

@ -217,6 +217,7 @@ void VKContext::update_pipeline_data(render_graph::VKPipelineData &pipeline_data
{
VKShader &vk_shader = unwrap(*shader);
pipeline_data.vk_pipeline_layout = vk_shader.vk_pipeline_layout_get();
pipeline_data.vk_pipeline = vk_shader.ensure_and_get_compute_pipeline();
/* Update descriptor set. */
pipeline_data.vk_descriptor_set = VK_NULL_HANDLE;
@ -231,29 +232,17 @@ void VKContext::update_pipeline_data(render_graph::VKPipelineData &pipeline_data
const VKPushConstants::Layout &push_constants_layout =
vk_shader.interface_get().push_constants_layout_get();
if (push_constants_layout.storage_type_get() == VKPushConstants::StorageType::PUSH_CONSTANTS) {
vk_shader.push_constants.update(*this);
pipeline_data.push_constants_size = push_constants_layout.size_in_bytes();
pipeline_data.push_constants_data = vk_shader.push_constants.data();
}
}
void VKContext::update_dispatch_info()
render_graph::VKResourceAccessInfo &VKContext::update_and_get_access_info()
{
dispatch_info_.dispatch_node = {};
dispatch_info_.resources.reset();
state_manager_get().apply_bindings(*this, dispatch_info_.resources);
update_pipeline_data(dispatch_info_.dispatch_node.pipeline_data);
VKShader &vk_shader = unwrap(*shader);
VkPipeline vk_pipeline = vk_shader.ensure_and_get_compute_pipeline();
dispatch_info_.dispatch_node.pipeline_data.vk_pipeline = vk_pipeline;
}
render_graph::VKDispatchNode::CreateInfo &VKContext::update_and_get_dispatch_info()
{
VKShader *shader = unwrap(this->shader);
shader->push_constants.update(*this);
update_dispatch_info();
return dispatch_info_;
access_info_.reset();
state_manager_get().apply_bindings(*this, access_info_);
return access_info_;
}
/** \} */

View File

@ -35,7 +35,8 @@ class VKContext : public Context, NonCopyable {
GPUTexture *surface_texture_ = nullptr;
void *ghost_context_;
render_graph::VKDispatchNode::CreateInfo dispatch_info_ = {};
/* Reusable data. Stored inside context to limit reallocations. */
render_graph::VKResourceAccessInfo access_info_ = {};
public:
render_graph::VKRenderGraph render_graph;
@ -72,8 +73,12 @@ class VKContext : public Context, NonCopyable {
VKFrameBuffer *active_framebuffer_get() const;
void bind_compute_pipeline();
void update_dispatch_info();
render_graph::VKDispatchNode::CreateInfo &update_and_get_dispatch_info();
render_graph::VKResourceAccessInfo &update_and_get_access_info();
/**
* Update the give shader data with the current state of the context.
*/
void update_pipeline_data(render_graph::VKPipelineData &pipeline_data);
void bind_graphics_pipeline(const GPUPrimType prim_type,
const VKVertexAttributeObject &vertex_attribute_object);
@ -107,13 +112,6 @@ class VKContext : public Context, NonCopyable {
private:
void swap_buffers_pre_handler(const GHOST_VulkanSwapChainData &data);
void swap_buffers_post_handler();
/**
* Update the give shader data with the current state of the context.
*
* NOTE: Shader data structure is reused between render graph nodes.
*/
void update_pipeline_data(render_graph::VKPipelineData &pipeline_data);
};
BLI_INLINE bool operator==(const VKContext &a, const VKContext &b)