**Design Task**: blender/blender#118330 This PR adds the core of the render graph. The render graph isn't used. Current implementation of the Vulkan Backend is slow by design. We focused on stability, before performance. With the new introduced render graph the focus will shift to performance and keep the stability at where it is. Some highlights: - Every context will get its own render graph. (`VKRenderGraph`). - Resources (and resource state tracking) is device specific (`VKResourceStateTracker`). - No node reordering / sub graph execution has been implemented. Currently All nodes in the graph is executed in the order they were added. (`VKScheduler`). - The links inside the graph describe the resources the nodes read from (input links) or writes to (output links) - When resources are written to a resource stamp is incremented allowing keeping track of which nodes needs which stamp of a resource. - At each link the access information (how does the node accesses the resource) and image layout (for image resources) are stored. This allows the render graph to find out how a resource was used in the past and will be used in the future. That is important to construct pipeline barriers that don't stall the whole GPU. # Defined nodes This implementation has nodes for: - Blit image - Clear color image - Copy buffers to buffers - Copy buffers to images - Copy images to images - Copy images to buffers - Dispatch compute shader - Fill buffers - Synchronization Each node has a node info, create info and data struct. The create info contains all data to construct the node, including the links of the graph. The data struct only contains the data stored inside the node. The node info contains the node specific implementation. > NOTE: Other nodes will be added after this PR lands to main. # Resources Before a render graph can be used, the resources should be registered to `VKResourceStateTracker`. In the final implementation this will be owned by the `VKDevice`. Registration of resources can be done by calling `VKResources.add_buffer` or `VKResources.add_image`. # Render graph Nodes can be added to the render graph. When adding a node its read/ write dependencies are extracted and converted into links (`VKNodeInfo. build_links`). When the caller wants to have a resource up to date the functions `VKRenderGraph.submit_for_read` or `VKRenderGraph.submit_for_present` can be called. These functions will select and order the nodes that are needed and convert them to `vkCmd*` commands. These commands include pipeline barrier and image layout transitions. The `vkCmd` are recorded into a command buffer which is sent to the device queue. ## Walking the graph Walking the render graph isn't implemented yet. The idea is to have a `Map<ResourceWithStamp, Vector<NodeHandle>> consumers` and `Map<ResourceWithStamp, NodeHandle> producers`. These attributes can be stored in the render graph and created when building the links, or can be created inside the VKScheduler as a variable. The exact detail which one would be better is unclear as there aren't any users yet. At the moment the scheduler would need them we need to figure out the best way to store and retrieve the consumers/producers. # Unit tests The render graph can be tested by enabling `WITH_GTEST` and use `vk_render_graph` as a filter. ``` bin/tests/blender_test --gtest_filter="vk_render_graph*" ``` Pull Request: https://projects.blender.org/blender/blender/pulls/120427
85 lines
3.4 KiB
C++
85 lines
3.4 KiB
C++
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup gpu
|
|
*
|
|
* The scheduler is responsible to find and reorder the nodes in the render graph to update an
|
|
* image or buffer to its latest content and state.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "BLI_vector.hh"
|
|
|
|
#include "vk_common.hh"
|
|
#include "vk_render_graph_node.hh"
|
|
|
|
namespace blender::gpu::render_graph {
|
|
class VKRenderGraph;
|
|
|
|
/**
|
|
* VKScheduler is responsible for selecting and reordering of nodes in the render graph. This
|
|
* selection and order is used to convert the nodes to commands and submitting it to the GPU.
|
|
*
|
|
* This scheduler selects all nodes in the order they were added to the render graph.
|
|
*
|
|
* This is an initial implementation and should be enhanced for:
|
|
* - Moving data transfer and compute before drawing, when they are scheduled between drawing nodes
|
|
* that use the same pipeline.
|
|
* - Only select the nodes that are only needed for the given vk_image/vk_buffer. When performing
|
|
* read-backs of buffers should be done with as least as possible nodes as they can block
|
|
* drawing. It is better to do handle most nodes just before presenting the image. This would
|
|
* lead to less CPU locks.
|
|
* - Pruning branches that are not linked to anything. EEVEE can add debug commands that would
|
|
* eventually not been displayed on screen. These branches should be pruned. The challenge is
|
|
* that we need to know for certain that it isn't used in a not submitted part of the graph.
|
|
*
|
|
* TODO: Walking the render graph isn't implemented yet. The idea is to have a
|
|
* `Map<ResourceWithStamp, Vector<NodeHandle>> consumers` and `Map<ResourceWithStamp, NodeHandle>
|
|
* producers`. These attributes can be stored in the render graph and created when building the
|
|
* links, or can be created inside the VKScheduler as a variable. The exact detail which one would
|
|
* be better is unclear as there aren't any users yet. At the moment the scheduler would need them
|
|
* we need to figure out the best way to store and retrieve the consumers/producers.
|
|
*/
|
|
class VKScheduler {
|
|
private:
|
|
/**
|
|
* Results of `select_nodes_for_image`, `select_nodes_for_buffer` are cached in this instance to
|
|
* reduce memory operations.
|
|
*/
|
|
Vector<NodeHandle> result_;
|
|
|
|
public:
|
|
/**
|
|
* Determine which nodes of the render graph should be selected and in what order they should
|
|
* be executed to update the given vk_image to its latest content and state.
|
|
*
|
|
* NOTE: Currently will select all nodes.
|
|
* NOTE: Result becomes invalid by the next call to VKScheduler.
|
|
*/
|
|
[[nodiscard]] Span<NodeHandle> select_nodes_for_image(const VKRenderGraph &render_graph,
|
|
VkImage vk_image);
|
|
|
|
/**
|
|
* Determine which nodes of the render graph should be selected and in what order they should
|
|
* be executed to update the given vk_buffer to its latest content and state.
|
|
*
|
|
* NOTE: Currently will select all nodes.
|
|
* NOTE: Result becomes invalid by the next call to VKScheduler.
|
|
*/
|
|
[[nodiscard]] Span<NodeHandle> select_nodes_for_buffer(const VKRenderGraph &render_graph,
|
|
VkBuffer vk_buffer);
|
|
|
|
private:
|
|
/**
|
|
* Select all nodes.
|
|
*
|
|
* Result is stored in `result_`.
|
|
*/
|
|
void select_all_nodes(const VKRenderGraph &render_graph);
|
|
};
|
|
|
|
} // namespace blender::gpu::render_graph
|