Vulkan: Render graph dispatch indirect #120993
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -30,6 +30,7 @@ enum class VKNodeType {
|
|||
COPY_BUFFER_TO_IMAGE,
|
||||
BLIT_IMAGE,
|
||||
DISPATCH,
|
||||
DISPATCH_INDIRECT,
|
||||
SYNCHRONIZATION,
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue