This PR implements a new the threading model for building render graphs based on tests performed last month. For out workload multithreaded command building will block in the driver or device. So better to use a single thread for command building. Details of the internal working is documented at https://developer.blender.org/docs/features/gpu/vulkan/render_graph/ - When a context is activated on a thread the context asks for a render graph it can use by calling `VKDevice::render_graph_new`. - Parts of the GPU backend that requires GPU commands will add a specific render graph node to the render graph. The nodes also contains a reference to all resources it needs including the access it needs and the image layout. - When the context is flushed the render graph is submitted to the device by calling `VKDevice::render_graph_submit`. - The device puts the render graph in `VKDevice::submission_pool`. - There is a single background thread that gets the next render graph to send to the GPU (`VKDevice::submission_runner`). - Reorder the commands of the render graph to comply with Vulkan specific command order rules and reducing possible bottlenecks. (`VKScheduler`) - Generate the required barriers `VKCommandBuilder::groups_extract_barriers`. This is a separate step to reduce resource locking giving other threads access to the resource states when they are building the render graph nodes. - GPU commands and pipeline barriers are recorded to a VkCommandBuffer. (`VKCommandBuilder::record_commands`) - When completed the command buffer can be submitted to the device queue. `vkQueueSubmit` - Render graphs that have been submitted can be reused by a next thread. This is done by pushing the render graph to the `VKDevice::unused_render_graphs` queue. Pull Request: https://projects.blender.org/blender/blender/pulls/132681
143 lines
4.0 KiB
C++
143 lines
4.0 KiB
C++
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup gpu
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "gpu_context_private.hh"
|
|
|
|
#include "GHOST_Types.h"
|
|
|
|
#include "render_graph/vk_render_graph.hh"
|
|
#include "vk_common.hh"
|
|
#include "vk_debug.hh"
|
|
#include "vk_descriptor_pools.hh"
|
|
#include "vk_resource_pool.hh"
|
|
|
|
namespace blender::gpu {
|
|
class VKFrameBuffer;
|
|
class VKVertexAttributeObject;
|
|
class VKBatch;
|
|
class VKStateManager;
|
|
class VKShader;
|
|
class VKThreadData;
|
|
|
|
enum RenderGraphFlushFlags {
|
|
NONE = 0,
|
|
RENEW_RENDER_GRAPH = 1 << 0,
|
|
SUBMIT = 1 << 1,
|
|
WAIT_FOR_COMPLETION = 1 << 2,
|
|
};
|
|
ENUM_OPERATORS(RenderGraphFlushFlags, RenderGraphFlushFlags::WAIT_FOR_COMPLETION);
|
|
|
|
class VKContext : public Context, NonCopyable {
|
|
private:
|
|
VkExtent2D vk_extent_ = {};
|
|
VkSurfaceFormatKHR swap_chain_format_ = {};
|
|
GPUTexture *surface_texture_ = nullptr;
|
|
void *ghost_context_;
|
|
|
|
/* Reusable data. Stored inside context to limit reallocations. */
|
|
render_graph::VKResourceAccessInfo access_info_ = {};
|
|
|
|
std::optional<std::reference_wrapper<VKThreadData>> thread_data_;
|
|
std::optional<std::reference_wrapper<render_graph::VKRenderGraph>> render_graph_;
|
|
|
|
public:
|
|
VKDiscardPool discard_pool;
|
|
|
|
const render_graph::VKRenderGraph &render_graph() const
|
|
{
|
|
return render_graph_.value().get();
|
|
}
|
|
render_graph::VKRenderGraph &render_graph()
|
|
{
|
|
return render_graph_.value().get();
|
|
}
|
|
|
|
VKContext(void *ghost_window, void *ghost_context);
|
|
virtual ~VKContext();
|
|
|
|
void activate() override;
|
|
void deactivate() override;
|
|
void begin_frame() override;
|
|
void end_frame() override;
|
|
|
|
void flush() override;
|
|
|
|
TimelineValue flush_render_graph(RenderGraphFlushFlags flags);
|
|
void finish() override;
|
|
|
|
void memory_statistics_get(int *r_total_mem_kb, int *r_free_mem_kb) override;
|
|
|
|
void debug_group_begin(const char *, int) override;
|
|
void debug_group_end() override;
|
|
bool debug_capture_begin(const char *title) override;
|
|
void debug_capture_end() override;
|
|
void *debug_capture_scope_create(const char *name) override;
|
|
bool debug_capture_scope_begin(void *scope) override;
|
|
void debug_capture_scope_end(void *scope) override;
|
|
|
|
void debug_unbind_all_ubo() override;
|
|
void debug_unbind_all_ssbo() override;
|
|
|
|
bool has_active_framebuffer() const;
|
|
void activate_framebuffer(VKFrameBuffer &framebuffer);
|
|
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();
|
|
|
|
render_graph::VKResourceAccessInfo &reset_and_get_access_info();
|
|
|
|
/**
|
|
* Update the give shader data with the current state of the context.
|
|
*/
|
|
void update_pipeline_data(render_graph::VKPipelineData &r_pipeline_data);
|
|
void update_pipeline_data(GPUPrimType primitive,
|
|
VKVertexAttributeObject &vao,
|
|
render_graph::VKPipelineData &r_pipeline_data);
|
|
|
|
void sync_backbuffer(bool cycle_resource_pool);
|
|
|
|
static VKContext *get()
|
|
{
|
|
return static_cast<VKContext *>(Context::get());
|
|
}
|
|
|
|
VKDescriptorPools &descriptor_pools_get();
|
|
VKDescriptorSetTracker &descriptor_set_get();
|
|
VKStateManager &state_manager_get() const;
|
|
|
|
static void swap_buffers_pre_callback(const GHOST_VulkanSwapChainData *data);
|
|
static void swap_buffers_post_callback();
|
|
|
|
private:
|
|
void swap_buffers_pre_handler(const GHOST_VulkanSwapChainData &data);
|
|
void swap_buffers_post_handler();
|
|
|
|
void update_pipeline_data(VKShader &shader,
|
|
VkPipeline vk_pipeline,
|
|
render_graph::VKPipelineData &r_pipeline_data);
|
|
};
|
|
|
|
BLI_INLINE bool operator==(const VKContext &a, const VKContext &b)
|
|
{
|
|
return static_cast<const void *>(&a) == static_cast<const void *>(&b);
|
|
}
|
|
|
|
} // namespace blender::gpu
|