From a5ed5dc4bf215d402b68de17519b59379cf3579c Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Mon, 7 Apr 2025 15:26:25 +0200 Subject: [PATCH] GPU: Support deferred compilation in ShaderCompilerGeneric Update the `ShaderCompilerGeneric` to support deferred compilation using the batch compilation API, so we can get rid of `drw_manager_shader`. This approach also allows supporting non-blocking compilation for static shaders. This shouldn't cause any behavior changes at the moment, since batch compilation is not yet used when parallel compilation is disabled. This adds a `GPUWorker` and a `GPUSecondaryContext` as an easy to use wrapper for managing secondary GPU contexts. (Part of #133674) Pull Request: https://projects.blender.org/blender/blender/pulls/136518 --- source/blender/gpu/CMakeLists.txt | 4 +- source/blender/gpu/GPU_context.hh | 20 ++++ source/blender/gpu/GPU_worker.hh | 49 +++++++++ source/blender/gpu/dummy/dummy_backend.hh | 1 + source/blender/gpu/dummy/dummy_context.hh | 5 + source/blender/gpu/intern/gpu_backend.hh | 4 + source/blender/gpu/intern/gpu_context.cc | 103 ++++++++++++++++++ .../blender/gpu/intern/gpu_context_private.hh | 4 +- source/blender/gpu/intern/gpu_init_exit.cc | 2 + source/blender/gpu/intern/gpu_private.hh | 1 + source/blender/gpu/intern/gpu_shader.cc | 83 +++++++++++--- .../blender/gpu/intern/gpu_shader_private.hh | 19 +++- source/blender/gpu/intern/gpu_worker.cc | 52 +++++++++ source/blender/gpu/metal/mtl_backend.hh | 5 + source/blender/gpu/metal/mtl_context.hh | 7 ++ source/blender/gpu/metal/mtl_shader.mm | 3 +- source/blender/gpu/opengl/gl_backend.hh | 18 ++- .../gpu/opengl/gl_compilation_subprocess.cc | 6 + source/blender/gpu/opengl/gl_context.cc | 13 ++- source/blender/gpu/opengl/gl_context.hh | 2 + source/blender/gpu/vulkan/vk_backend.cc | 1 + source/blender/gpu/vulkan/vk_backend.hh | 1 + source/blender/gpu/vulkan/vk_context.cc | 8 +- source/blender/gpu/vulkan/vk_context.hh | 2 + 24 files changed, 378 insertions(+), 35 deletions(-) create mode 100644 source/blender/gpu/GPU_worker.hh create mode 100644 source/blender/gpu/intern/gpu_worker.cc diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 46e03f34ed4..6afff6892b8 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -98,7 +98,8 @@ set(SRC intern/gpu_vertex_format.cc intern/gpu_vertex_format_normals.cc intern/gpu_viewport.cc - + intern/gpu_worker.cc + GPU_attribute_convert.hh GPU_batch.hh GPU_batch_presets.hh @@ -132,6 +133,7 @@ set(SRC GPU_vertex_buffer.hh GPU_vertex_format.hh GPU_viewport.hh + GPU_worker.hh intern/gpu_backend.hh intern/gpu_capabilities_private.hh diff --git a/source/blender/gpu/GPU_context.hh b/source/blender/gpu/GPU_context.hh index c7b457a9615..ab7cbc3f334 100644 --- a/source/blender/gpu/GPU_context.hh +++ b/source/blender/gpu/GPU_context.hh @@ -85,3 +85,23 @@ void GPU_render_step(bool force_resource_release = false); /* For when we need access to a system context in order to create a GPU context. */ void GPU_backend_ghost_system_set(void *ghost_system_handle); void *GPU_backend_ghost_system_get(); + +namespace blender::gpu { + +/* Abstracts secondary GHOST and GPU context creation, activation and deletion. + * Must be created from the main thread and destructed from the thread they where activated in. + * (See GPUWorker for an usage example) */ +class GPUSecondaryContext { + private: + void *ghost_context_; + GPUContext *gpu_context_; + + public: + GPUSecondaryContext(); + ~GPUSecondaryContext(); + + /* Must be called from a secondary thread.*/ + void activate(); +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/GPU_worker.hh b/source/blender/gpu/GPU_worker.hh new file mode 100644 index 00000000000..83dc3cb0e8d --- /dev/null +++ b/source/blender/gpu/GPU_worker.hh @@ -0,0 +1,49 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "BLI_vector.hh" +#include "GPU_context.hh" + +#include +#include +#include +#include +#include +#include + +namespace blender::gpu { + +/* Abstracts the creation and management of secondary threads with GPU contexts. + * Must be created from the main thread. + * Threads and their context remain alive until destruction. */ +class GPUWorker { + private: + Vector> threads_; + std::condition_variable condition_var_; + std::mutex mutex_; + std::atomic_bool terminate_ = false; + + public: + /** + * \param threads_count: Number of threads to span. + * \param share_context: If true, all threads will use the same secondary GPUContext, + * otherwise each thread will have its own unique GPUContext. + * \param run_cb: The callback function that will be called by a thread on `wake_up()`. + */ + GPUWorker(uint32_t threads_count, bool share_context, std::function run_cb); + ~GPUWorker(); + + /* Wake up a single thread. */ + void wake_up() + { + condition_var_.notify_one(); + } + + private: + void run(std::shared_ptr context, std::function run_cb); +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/dummy/dummy_backend.hh b/source/blender/gpu/dummy/dummy_backend.hh index 523095b3e48..bb1ec05a649 100644 --- a/source/blender/gpu/dummy/dummy_backend.hh +++ b/source/blender/gpu/dummy/dummy_backend.hh @@ -32,6 +32,7 @@ class DummyBackend : public GPUBackend { "", GPU_ARCHITECTURE_IMR); } + void init_resources() override {} void delete_resources() override {} void samplers_update() override {} void compute_dispatch(int /*groups_x_len*/, int /*groups_y_len*/, int /*groups_z_len*/) override diff --git a/source/blender/gpu/dummy/dummy_context.hh b/source/blender/gpu/dummy/dummy_context.hh index 471d8a3b33a..0d28369b701 100644 --- a/source/blender/gpu/dummy/dummy_context.hh +++ b/source/blender/gpu/dummy/dummy_context.hh @@ -32,6 +32,11 @@ class DummyContext : public Context { void flush() override {} void finish() override {} + ShaderCompiler *get_compiler() override + { + return nullptr; + } + void memory_statistics_get(int * /*r_total_mem*/, int * /*r_free_mem*/) override {} void debug_group_begin(const char * /*unused*/, int /*unused*/) override {} diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh index 8d63503ff56..5b48f07538d 100644 --- a/source/blender/gpu/intern/gpu_backend.hh +++ b/source/blender/gpu/intern/gpu_backend.hh @@ -33,6 +33,10 @@ class VertBuf; class GPUBackend { public: virtual ~GPUBackend() = default; + + /* Called after the main context creation and activation. */ + virtual void init_resources() = 0; + /* Called before the main context deletion and deactivation. */ virtual void delete_resources() = 0; static GPUBackend *get(); diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index c256c1b5edd..3b25be58d05 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -16,8 +16,12 @@ #include "BKE_global.hh" #include "BLI_assert.h" +#include "BLI_threads.h" #include "BLI_vector_set.hh" +#include "DNA_userdef_types.h" + +#include "GHOST_C-api.h" #include "GHOST_Types.h" #include "GPU_context.hh" @@ -450,6 +454,12 @@ static void gpu_backend_create() } } +void gpu_backend_init_resources() +{ + BLI_assert(g_backend); + g_backend->init_resources(); +} + void gpu_backend_delete_resources() { BLI_assert(g_backend); @@ -493,3 +503,96 @@ GPUBackend *GPUBackend::get() } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name GPUSecondaryContext + * \{ */ + +static GHOST_TDrawingContextType ghost_context_type() +{ + switch (GPU_backend_type_selection_get()) { +#ifdef WITH_OPENGL_BACKEND + case GPU_BACKEND_OPENGL: + return GHOST_kDrawingContextTypeOpenGL; +#endif +#ifdef WITH_VULKAN_BACKEND + case GPU_BACKEND_VULKAN: + return GHOST_kDrawingContextTypeVulkan; +#endif +#ifdef WITH_METAL_BACKEND + case GPU_BACKEND_METAL: + return GHOST_kDrawingContextTypeMetal; +#endif + default: + BLI_assert_unreachable(); + return GHOST_kDrawingContextTypeNone; + } +} + +GPUSecondaryContext::GPUSecondaryContext() +{ + /* Contexts can only be created on the main thread. */ + BLI_assert(BLI_thread_is_main()); + + GHOST_ContextHandle main_thread_ghost_context = GHOST_GetActiveGPUContext(); + GPUContext *main_thread_gpu_context = GPU_context_active_get(); + + /* GPU settings for context creation. */ + GHOST_GPUSettings gpu_settings = {0}; + gpu_settings.context_type = ghost_context_type(); + if (G.debug & G_DEBUG_GPU) { + gpu_settings.flags |= GHOST_gpuDebugContext; + } + gpu_settings.preferred_device.index = U.gpu_preferred_index; + gpu_settings.preferred_device.vendor_id = U.gpu_preferred_vendor_id; + gpu_settings.preferred_device.device_id = U.gpu_preferred_device_id; + + /* Grab the system handle. */ + GHOST_SystemHandle ghost_system = reinterpret_cast( + GPU_backend_ghost_system_get()); + BLI_assert(ghost_system); + + /* Create a Ghost GPU Context using the system handle. */ + ghost_context_ = GHOST_CreateGPUContext(ghost_system, gpu_settings); + BLI_assert(ghost_context_); + + /* Create a GPU context for the secondary thread to use. */ + gpu_context_ = GPU_context_create(nullptr, ghost_context_); + BLI_assert(gpu_context_); + + /* Release the Ghost GPU Context from this thread. */ + GHOST_TSuccess success = GHOST_ReleaseGPUContext( + reinterpret_cast(ghost_context_)); + BLI_assert(success); + + /* Restore the main thread contexts. + * (required as the above context creation also makes it active). */ + GHOST_ActivateGPUContext(main_thread_ghost_context); + GPU_context_active_set(main_thread_gpu_context); +} + +GPUSecondaryContext::~GPUSecondaryContext() +{ + /* Contexts should be destructed on the thread they were activated. */ + BLI_assert(!BLI_thread_is_main()); + + GPU_context_discard(gpu_context_); + + GHOST_ReleaseGPUContext(reinterpret_cast(ghost_context_)); + + GHOST_SystemHandle ghost_system = reinterpret_cast( + GPU_backend_ghost_system_get()); + BLI_assert(ghost_system); + GHOST_DisposeGPUContext(ghost_system, reinterpret_cast(ghost_context_)); +} + +void GPUSecondaryContext::activate() +{ + /* Contexts need to be activated in the thread they're going to be used. */ + BLI_assert(!BLI_thread_is_main()); + + GHOST_ActivateGPUContext(reinterpret_cast(ghost_context_)); + GPU_context_active_set(gpu_context_); +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh index b785b92acb9..b8138c55ffd 100644 --- a/source/blender/gpu/intern/gpu_context_private.hh +++ b/source/blender/gpu/intern/gpu_context_private.hh @@ -37,8 +37,6 @@ class Context { StateManager *state_manager = nullptr; Immediate *imm = nullptr; - ShaderCompiler *compiler = nullptr; - /** * All 4 window frame-buffers. * None of them are valid in an off-screen context. @@ -99,6 +97,8 @@ class Context { /* Will wait until the GPU has finished executing all command. */ virtual void finish() = 0; + virtual ShaderCompiler *get_compiler() = 0; + virtual void memory_statistics_get(int *r_total_mem, int *r_free_mem) = 0; virtual void debug_group_begin(const char * /*name*/, int /*index*/){}; diff --git a/source/blender/gpu/intern/gpu_init_exit.cc b/source/blender/gpu/intern/gpu_init_exit.cc index 8f195bf003b..59f82db54e4 100644 --- a/source/blender/gpu/intern/gpu_init_exit.cc +++ b/source/blender/gpu/intern/gpu_init_exit.cc @@ -29,6 +29,8 @@ void GPU_init() initialized = true; + gpu_backend_init_resources(); + gpu_shader_dependency_init(); gpu_shader_create_info_init(); diff --git a/source/blender/gpu/intern/gpu_private.hh b/source/blender/gpu/intern/gpu_private.hh index 040c3286c71..293fee93223 100644 --- a/source/blender/gpu/intern/gpu_private.hh +++ b/source/blender/gpu/intern/gpu_private.hh @@ -10,4 +10,5 @@ /* gpu_backend.cc */ +void gpu_backend_init_resources(); void gpu_backend_delete_resources(); diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 2dce5c0f783..ded6840e8d2 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -8,6 +8,7 @@ #include "BLI_math_matrix.h" #include "BLI_string.h" +#include "BLI_time.h" #include "GPU_capabilities.hh" #include "GPU_debug.hh" @@ -265,7 +266,7 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) { using namespace blender::gpu::shader; const ShaderCreateInfo &info = *reinterpret_cast(_info); - return wrap(Context::get()->compiler->compile(info, false)); + return wrap(Context::get()->get_compiler()->compile(info, false)); } static std::string preprocess_source(StringRefNull original) @@ -293,7 +294,7 @@ GPUShader *GPU_shader_create_from_info_python(const GPUShaderCreateInfo *_info) info.geometry_source_generated = preprocess_source(info.geometry_source_generated); info.compute_source_generated = preprocess_source(info.compute_source_generated); - GPUShader *result = wrap(Context::get()->compiler->compile(info, false)); + GPUShader *result = wrap(Context::get()->get_compiler()->compile(info, false)); info.vertex_source_generated = vertex_source_original; info.fragment_source_generated = fragment_source_original; @@ -365,17 +366,17 @@ BatchHandle GPU_shader_batch_create_from_infos(Span using namespace blender::gpu::shader; Span &infos_ = reinterpret_cast &>( infos); - return Context::get()->compiler->batch_compile(infos_); + return Context::get()->get_compiler()->batch_compile(infos_); } bool GPU_shader_batch_is_ready(BatchHandle handle) { - return Context::get()->compiler->batch_is_ready(handle); + return Context::get()->get_compiler()->batch_is_ready(handle); } Vector GPU_shader_batch_finalize(BatchHandle &handle) { - Vector result = Context::get()->compiler->batch_finalize(handle); + Vector result = Context::get()->get_compiler()->batch_finalize(handle); return reinterpret_cast &>(result); } @@ -543,12 +544,12 @@ void GPU_shader_constant_bool(GPUShader *sh, const char *name, bool value) SpecializationBatchHandle GPU_shader_batch_specializations( blender::Span specializations) { - return Context::get()->compiler->precompile_specializations(specializations); + return Context::get()->get_compiler()->precompile_specializations(specializations); } bool GPU_shader_batch_specializations_is_ready(SpecializationBatchHandle &handle) { - return Context::get()->compiler->specialization_batch_is_ready(handle); + return Context::get()->get_compiler()->specialization_batch_is_ready(handle); } /** \} */ @@ -953,23 +954,43 @@ Shader *ShaderCompiler::compile(const shader::ShaderCreateInfo &info, bool is_ba /** \name ShaderCompilerGeneric * \{ */ +ShaderCompilerGeneric::ShaderCompilerGeneric() +{ + if (!GPU_use_main_context_workaround()) { + compilation_thread_ = std::make_unique(1, true, [this]() { this->run_thread(); }); + } +} + ShaderCompilerGeneric::~ShaderCompilerGeneric() { + compilation_thread_.reset(); + /* Ensure all the requested batches have been retrieved. */ - BLI_assert(batches.is_empty()); + BLI_assert(batches_.is_empty()); } BatchHandle ShaderCompilerGeneric::batch_compile(Span &infos) { - std::lock_guard lock(mutex_); + std::unique_lock lock(mutex_); - BatchHandle handle = next_batch_handle++; - batches.add(handle, {{}, infos, true}); - Batch &batch = batches.lookup(handle); - batch.shaders.reserve(infos.size()); - for (const shader::ShaderCreateInfo *info : infos) { - batch.shaders.append(compile(*info, true)); + BatchHandle handle = next_batch_handle_++; + batches_.add(handle, std::make_unique()); + Batch *batch = batches_.lookup(handle).get(); + batch->infos = infos; + batch->shaders.reserve(infos.size()); + + if (compilation_thread_) { + compilation_queue_.push_back(batch); + lock.unlock(); + compilation_thread_->wake_up(); } + else { + for (const shader::ShaderCreateInfo *info : infos) { + batch->shaders.append(compile(*info, false)); + } + batch->is_ready = true; + } + return handle; } @@ -977,19 +998,47 @@ bool ShaderCompilerGeneric::batch_is_ready(BatchHandle handle) { std::lock_guard lock(mutex_); - bool is_ready = batches.lookup(handle).is_ready; + bool is_ready = batches_.lookup(handle)->is_ready; return is_ready; } Vector ShaderCompilerGeneric::batch_finalize(BatchHandle &handle) { + while (!batch_is_ready(handle)) { + BLI_time_sleep_ms(1); + } + std::lock_guard lock(mutex_); - Vector shaders = batches.pop(handle).shaders; + Vector shaders = batches_.lookup(handle)->shaders; + batches_.pop(handle); handle = 0; return shaders; } +void ShaderCompilerGeneric::run_thread() +{ + while (true) { + Batch *batch = nullptr; + { + std::unique_lock lock(mutex_); + + if (compilation_queue_.empty()) { + return; + } + + batch = compilation_queue_.front(); + compilation_queue_.pop_front(); + } + + /* Compile */ + for (const shader::ShaderCreateInfo *info : batch->infos) { + batch->shaders.append(compile(*info, false)); + } + batch->is_ready = true; + } +} + /** \} */ } // namespace blender::gpu diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh index c8bac348f56..00bed6f0b14 100644 --- a/source/blender/gpu/intern/gpu_shader_private.hh +++ b/source/blender/gpu/intern/gpu_shader_private.hh @@ -8,15 +8,16 @@ #pragma once +#include "BLI_map.hh" #include "BLI_span.hh" #include "BLI_string_ref.hh" #include "GPU_shader.hh" +#include "GPU_worker.hh" #include "gpu_shader_create_info.hh" #include "gpu_shader_interface.hh" -#include "BLI_map.hh" - +#include #include namespace blender::gpu { @@ -188,19 +189,25 @@ class ShaderCompiler { }; }; -/* Generic (fully synchronous) implementation used as fallback. */ +/* Generic implementation used as fallback. */ class ShaderCompilerGeneric : public ShaderCompiler { private: struct Batch { Vector shaders; Vector infos; - bool is_ready = false; + std::atomic_bool is_ready = false; }; - BatchHandle next_batch_handle = 1; - Map batches; + BatchHandle next_batch_handle_ = 1; + Map> batches_; std::mutex mutex_; + std::deque compilation_queue_; + std::unique_ptr compilation_thread_; + + void run_thread(); + public: + ShaderCompilerGeneric(); ~ShaderCompilerGeneric() override; BatchHandle batch_compile(Span &infos) override; diff --git a/source/blender/gpu/intern/gpu_worker.cc b/source/blender/gpu/intern/gpu_worker.cc new file mode 100644 index 00000000000..738f14dedd3 --- /dev/null +++ b/source/blender/gpu/intern/gpu_worker.cc @@ -0,0 +1,52 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "GPU_worker.hh" + +namespace blender::gpu { + +GPUWorker::GPUWorker(uint32_t threads_count, bool share_context, std::function run_cb) +{ + std::shared_ptr shared_context = nullptr; + if (share_context) { + shared_context = std::make_shared(); + } + + for (int i : IndexRange(threads_count)) { + UNUSED_VARS(i); + std::shared_ptr thread_context = + share_context ? shared_context : std::make_shared(); + threads_.append(std::make_unique([=]() { this->run(thread_context, run_cb); })); + } +} + +GPUWorker::~GPUWorker() +{ + terminate_ = true; + condition_var_.notify_all(); + for (std::unique_ptr &thread : threads_) { + thread->join(); + } +} + +void GPUWorker::run(std::shared_ptr context, std::function run_cb) +{ + context->activate(); + + /* Loop until we get the terminate signal. */ + while (!terminate_) { + { + /* Wait until wake_up() */ + std::unique_lock lock(mutex_); + condition_var_.wait(lock); + } + if (terminate_) { + continue; + } + + run_cb(); + } +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/metal/mtl_backend.hh b/source/blender/gpu/metal/mtl_backend.hh index d11998ea415..05be19958a0 100644 --- a/source/blender/gpu/metal/mtl_backend.hh +++ b/source/blender/gpu/metal/mtl_backend.hh @@ -40,6 +40,11 @@ class MTLBackend : public GPUBackend { MTLBackend::platform_exit(); } + void init_resources() override + { + /* Create any resources with context active. */ + } + void delete_resources() override { /* Delete any resources with context active. */ diff --git a/source/blender/gpu/metal/mtl_context.hh b/source/blender/gpu/metal/mtl_context.hh index df5e1c99867..01a74281ac1 100644 --- a/source/blender/gpu/metal/mtl_context.hh +++ b/source/blender/gpu/metal/mtl_context.hh @@ -776,6 +776,8 @@ class MTLContext : public Context { GPUVertFormat dummy_vertformat_[GPU_SAMPLER_TYPE_MAX]; VertBuf *dummy_verts_[GPU_SAMPLER_TYPE_MAX] = {nullptr}; + ShaderCompiler *compiler; + public: /* GPUContext interface. */ MTLContext(void *ghost_window, void *ghost_context); @@ -791,6 +793,11 @@ class MTLContext : public Context { void flush() override; void finish() override; + ShaderCompiler *get_compiler() override + { + return compiler; + } + void memory_statistics_get(int *r_total_mem, int *r_free_mem) override; static MTLContext *get() diff --git a/source/blender/gpu/metal/mtl_shader.mm b/source/blender/gpu/metal/mtl_shader.mm index 5f1501c9537..bee9d2740a6 100644 --- a/source/blender/gpu/metal/mtl_shader.mm +++ b/source/blender/gpu/metal/mtl_shader.mm @@ -1695,7 +1695,8 @@ void MTLParallelShaderCompiler::parallel_compilation_thread_func( GPU_context_active_set(blender_gpu_context); MTLContext *metal_context = static_cast(unwrap(blender_gpu_context)); - MTLShaderCompiler *shader_compiler = static_cast(metal_context->compiler); + MTLShaderCompiler *shader_compiler = static_cast( + metal_context->get_compiler()); /* This context is only for compilation, it does not need it's own instance of the compiler */ shader_compiler->release_parallel_shader_compiler(); diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh index 00a8352a467..23d29bf9756 100644 --- a/source/blender/gpu/opengl/gl_backend.hh +++ b/source/blender/gpu/opengl/gl_backend.hh @@ -8,6 +8,7 @@ #pragma once +#include "GPU_capabilities.hh" #include "gpu_backend.hh" #include "BLI_vector.hh" @@ -39,7 +40,7 @@ class GLBackend : public GPUBackend { renderdoc::api::Renderdoc renderdoc_; #endif - GLShaderCompiler compiler_; + ShaderCompiler *compiler_; public: GLBackend() @@ -55,10 +56,21 @@ class GLBackend : public GPUBackend { GLBackend::platform_exit(); } + void init_resources() override + { + if (GPU_use_parallel_compilation()) { + compiler_ = new GLShaderCompiler(); + } + else { + compiler_ = new ShaderCompilerGeneric(); + } + }; + void delete_resources() override { /* Delete any resources with context active. */ GLTexture::samplers_free(); + delete compiler_; } static GLBackend *get() @@ -66,9 +78,9 @@ class GLBackend : public GPUBackend { return static_cast(GPUBackend::get()); } - GLShaderCompiler *get_compiler() + ShaderCompiler *get_compiler() { - return &compiler_; + return compiler_; } void samplers_update() override diff --git a/source/blender/gpu/opengl/gl_compilation_subprocess.cc b/source/blender/gpu/opengl/gl_compilation_subprocess.cc index 1ba34891394..676eb97b375 100644 --- a/source/blender/gpu/opengl/gl_compilation_subprocess.cc +++ b/source/blender/gpu/opengl/gl_compilation_subprocess.cc @@ -10,10 +10,12 @@ # include "BLI_fileops.hh" # include "BLI_hash.hh" # include "BLI_path_utils.hh" +# include "BLI_threads.h" # include "CLG_log.h" # include "GHOST_C-api.h" # include "GPU_context.hh" # include "GPU_init_exit.hh" +# include "gpu_capabilities_private.hh" # include # include @@ -153,6 +155,10 @@ void GPU_compilation_subprocess_run(const char *subprocess_name) # endif CLG_init(); + BLI_threadapi_init(); + + /* Prevent the ShaderCompiler from spawning extra threads/contexts, we don't need them. */ + GCaps.use_main_context_workaround = true; std::string name = subprocess_name; SharedMemory shared_mem(name, compilation_subprocess_shared_memory_size, false); diff --git a/source/blender/gpu/opengl/gl_context.cc b/source/blender/gpu/opengl/gl_context.cc index 3ee710b0be4..323481b5bdd 100644 --- a/source/blender/gpu/opengl/gl_context.cc +++ b/source/blender/gpu/opengl/gl_context.cc @@ -84,8 +84,6 @@ GLContext::GLContext(void *ghost_window, GLSharedOrphanLists &shared_orphan_list active_fb = back_left; static_cast(state_manager)->active_fb = static_cast( active_fb); - - compiler = GLBackend::get()->get_compiler(); } GLContext::~GLContext() @@ -183,6 +181,17 @@ void GLContext::finish() /** \} */ +/* -------------------------------------------------------------------- */ +/** \name ShaderCompiler + * \{ */ + +ShaderCompiler *GLContext::get_compiler() +{ + return GLBackend::get()->get_compiler(); +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Safe object deletion * diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index b8c4b541be5..a8bb1b06a33 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -123,6 +123,8 @@ class GLContext : public Context { void flush() override; void finish() override; + ShaderCompiler *get_compiler() override; + void memory_statistics_get(int *r_total_mem, int *r_free_mem) override; static GLContext *get() diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index fa065e2c54f..1f748ad4620 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -447,6 +447,7 @@ void VKBackend::platform_exit() } } +void VKBackend::init_resources() {} void VKBackend::delete_resources() {} void VKBackend::samplers_update() diff --git a/source/blender/gpu/vulkan/vk_backend.hh b/source/blender/gpu/vulkan/vk_backend.hh index 7d27b328878..9f1830fb1ba 100644 --- a/source/blender/gpu/vulkan/vk_backend.hh +++ b/source/blender/gpu/vulkan/vk_backend.hh @@ -54,6 +54,7 @@ class VKBackend : public GPUBackend { */ static bool is_supported(); + void init_resources() override; void delete_resources() override; void samplers_update() override; diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index 28c4c2e6416..fe4e0c841db 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -32,8 +32,6 @@ VKContext::VKContext(void *ghost_window, void *ghost_context) back_left = new VKFrameBuffer("back_left"); front_left = new VKFrameBuffer("front_left"); active_fb = back_left; - - compiler = &VKBackend::get().shader_compiler; } VKContext::~VKContext() @@ -48,7 +46,6 @@ VKContext::~VKContext() VKBackend::get().device.context_unregister(*this); imm = nullptr; - compiler = nullptr; } void VKContext::sync_backbuffer(bool cycle_resource_pool) @@ -184,6 +181,11 @@ TimelineValue VKContext::flush_render_graph(RenderGraphFlushFlags flags, void VKContext::finish() {} +ShaderCompiler *VKContext::get_compiler() +{ + return &VKBackend::get().shader_compiler; +} + void VKContext::memory_statistics_get(int *r_total_mem_kb, int *r_free_mem_kb) { const VKDevice &device = VKBackend::get().device; diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh index 7bd15cee8ec..2cdf733a3cc 100644 --- a/source/blender/gpu/vulkan/vk_context.hh +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -79,6 +79,8 @@ class VKContext : public Context, NonCopyable { VkFence signal_fence = VK_NULL_HANDLE); void finish() override; + ShaderCompiler *get_compiler() override; + void memory_statistics_get(int *r_total_mem_kb, int *r_free_mem_kb) override; void debug_group_begin(const char *, int) override;