diff --git a/source/blender/draw/DRW_engine.hh b/source/blender/draw/DRW_engine.hh index 0ed2ad62744..e039d75a504 100644 --- a/source/blender/draw/DRW_engine.hh +++ b/source/blender/draw/DRW_engine.hh @@ -132,13 +132,20 @@ void DRW_render_gpencil(RenderEngine *engine, Depsgraph *depsgraph); void DRW_render_context_enable(Render *render); void DRW_render_context_disable(Render *render); +void DRW_mutexes_init(); +void DRW_mutexes_exit(); + +/* Mutex to lock the drw manager and avoid concurrent context usage. + * Equivalent to the old DST lock. + * Brought back to 4.5 due to unforeseen issues causing data races and race conditions with Images + * and GPUTextures. (See #141253) */ +void DRW_lock_start(); +void DRW_lock_end(); + /* Critical section for GPUShader usage. Can be removed when we have threadsafe GPUShader class. */ void DRW_submission_start(); void DRW_submission_end(); -void DRW_submission_mutex_init(); -void DRW_submission_mutex_exit(); - void DRW_gpu_context_create(); void DRW_gpu_context_destroy(); /** diff --git a/source/blender/draw/engines/eevee/eevee_material.cc b/source/blender/draw/engines/eevee/eevee_material.cc index 22f153b9a53..025663485c3 100644 --- a/source/blender/draw/engines/eevee/eevee_material.cc +++ b/source/blender/draw/engines/eevee/eevee_material.cc @@ -209,13 +209,17 @@ void MaterialModule::end_sync() for (auto i : range) { GPUMaterialTexture *tex = texture_loading_queue_[i]; ImageUser *iuser = tex->iuser_available ? &tex->iuser : nullptr; - BKE_image_tag_time(tex->ima); BKE_image_get_tile(tex->ima, 0); ImBuf *imbuf = BKE_image_acquire_ibuf(tex->ima, iuser, nullptr); BKE_image_release_ibuf(tex->ima, imbuf, nullptr); } }); + /* Tag time is not thread-safe. */ + for (GPUMaterialTexture *tex : texture_loading_queue_) { + BKE_image_tag_time(tex->ima); + } + /* Upload to the GPU (create GPUTexture). This part still requires a valid GPU context and * is not easily parallelized. */ for (GPUMaterialTexture *tex : texture_loading_queue_) { diff --git a/source/blender/draw/intern/draw_gpu_context.cc b/source/blender/draw/intern/draw_gpu_context.cc index 6b55bfa644a..70b579b6c03 100644 --- a/source/blender/draw/intern/draw_gpu_context.cc +++ b/source/blender/draw/intern/draw_gpu_context.cc @@ -28,18 +28,33 @@ * between render engine instances, we cannot allow pass submissions in a concurrent manner. * \{ */ +static TicketMutex *draw_mutex = nullptr; static TicketMutex *submission_mutex = nullptr; -void DRW_submission_mutex_init() +void DRW_mutexes_init() { + draw_mutex = BLI_ticket_mutex_alloc(); submission_mutex = BLI_ticket_mutex_alloc(); } -void DRW_submission_mutex_exit() +void DRW_mutexes_exit() { + BLI_ticket_mutex_free(draw_mutex); BLI_ticket_mutex_free(submission_mutex); } +void DRW_lock_start() +{ + bool locked = BLI_ticket_mutex_lock_check_recursive(draw_mutex); + BLI_assert(locked); + UNUSED_VARS_NDEBUG(locked); +} + +void DRW_lock_end() +{ + BLI_ticket_mutex_unlock(draw_mutex); +} + void DRW_submission_start() { bool locked = BLI_ticket_mutex_lock_check_recursive(submission_mutex); @@ -95,6 +110,7 @@ class ContextShared { void enable() { + DRW_lock_start(); /* IMPORTANT: We don't support immediate mode in render mode! * This shall remain in effect until immediate mode supports * multiple threads. */ @@ -124,6 +140,7 @@ class ContextShared { GPU_render_end(); BLI_ticket_mutex_unlock(mutex_); + DRW_lock_end(); } }; @@ -145,7 +162,7 @@ void DRW_gpu_context_create() { BLI_assert(viewport_context == nullptr); /* Ensure it's called once */ - DRW_submission_mutex_init(); + DRW_mutexes_init(); viewport_context = MEM_new(__func__); preview_context = MEM_new(__func__); @@ -164,7 +181,7 @@ void DRW_gpu_context_destroy() if (viewport_context == nullptr) { return; } - DRW_submission_mutex_exit(); + DRW_mutexes_exit(); MEM_SAFE_DELETE(viewport_context); MEM_SAFE_DELETE(preview_context); @@ -237,12 +254,14 @@ void DRW_system_gpu_render_context_enable(void *re_system_gpu_context) /* If thread is main you should use DRW_gpu_context_enable(). */ BLI_assert(!BLI_thread_is_main()); + DRW_lock_start(); WM_system_gpu_context_activate(re_system_gpu_context); } void DRW_system_gpu_render_context_disable(void *re_system_gpu_context) { WM_system_gpu_context_release(re_system_gpu_context); + DRW_lock_end(); } void DRW_blender_gpu_render_context_enable(void *re_gpu_context) @@ -346,6 +365,7 @@ void DRW_xr_drawing_begin() { /* XXX: See comment on #DRW_system_gpu_context_get(). */ + DRW_lock_start(); BLI_ticket_mutex_lock(viewport_context->mutex_); } @@ -354,6 +374,7 @@ void DRW_xr_drawing_end() /* XXX: See comment on #DRW_system_gpu_context_get(). */ BLI_ticket_mutex_unlock(viewport_context->mutex_); + DRW_lock_end(); } #endif diff --git a/source/blender/draw/tests/draw_testing.cc b/source/blender/draw/tests/draw_testing.cc index 86f541f4191..a21fd5c5958 100644 --- a/source/blender/draw/tests/draw_testing.cc +++ b/source/blender/draw/tests/draw_testing.cc @@ -14,12 +14,12 @@ namespace blender::draw { void DrawOpenGLTest::SetUp() { GPUOpenGLTest::SetUp(); - DRW_submission_mutex_init(); + DRW_mutexes_init(); } void DrawOpenGLTest::TearDown() { - DRW_submission_mutex_exit(); + DRW_mutexes_exit(); GPUOpenGLTest::TearDown(); } #endif @@ -28,12 +28,12 @@ void DrawOpenGLTest::TearDown() void DrawMetalTest::SetUp() { GPUMetalTest::SetUp(); - DRW_submission_mutex_init(); + DRW_mutexes_init(); } void DrawMetalTest::TearDown() { - DRW_submission_mutex_exit(); + DRW_mutexes_exit(); GPUMetalTest::TearDown(); } #endif @@ -42,12 +42,12 @@ void DrawMetalTest::TearDown() void DrawVulkanTest::SetUp() { GPUVulkanTest::SetUp(); - DRW_submission_mutex_init(); + DRW_mutexes_init(); } void DrawVulkanTest::TearDown() { - DRW_submission_mutex_exit(); + DRW_mutexes_exit(); GPUVulkanTest::TearDown(); } #endif diff --git a/tests/python/compositor_render_tests.py b/tests/python/compositor_render_tests.py index 3d579f8bdac..1d180bda1cb 100644 --- a/tests/python/compositor_render_tests.py +++ b/tests/python/compositor_render_tests.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# SPDX-FileCopyrightText: 2015-2022 Blender Authors +# SPDX-FileCopyrightText: 2015-2025 Blender Authors # # SPDX-License-Identifier: Apache-2.0 @@ -20,7 +20,7 @@ def get_compositor_device_setter_script(execution_device): return f"import bpy; bpy.data.scenes[0].render.compositor_device = '{execution_device}'" -def get_arguments(filepath, output_filepath, execution_device): +def get_arguments(filepath, output_filepath, backend): arguments = [ "--background", "--factory-startup", @@ -28,6 +28,11 @@ def get_arguments(filepath, output_filepath, execution_device): "--debug-memory", "--debug-exit-on-error"] + execution_device = "CPU" + if backend != "CPU": + execution_device = "GPU" + arguments.extend(["--gpu-backend", backend]) + arguments.extend([ filepath, "-P", os.path.realpath(__file__), @@ -56,8 +61,8 @@ def main(): args = parser.parse_args() from modules import render_report - execution_device = "GPU" if args.gpu_backend else "CPU" - report_title = f"Compositor {execution_device}" + backend = args.gpu_backend if args.gpu_backend else "CPU" + report_title = f"Compositor {backend.upper()}" report = render_report.Report(report_title, args.outdir, args.oiiotool) report.set_pixelated(True) report.set_reference_dir("compositor_renders") @@ -73,7 +78,7 @@ def main(): report.set_fail_threshold(0.06) report.set_fail_percent(2) - def arguments_callback(filepath, output_filepath): return get_arguments(filepath, output_filepath, execution_device) + def arguments_callback(filepath, output_filepath): return get_arguments(filepath, output_filepath, backend) ok = report.run(args.testdir, args.blender, arguments_callback, batch=args.batch) sys.exit(not ok)