From 1cf465bbc3312ae8eac3e1ae573b716e0fad92cf Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 15 Jul 2022 12:44:35 +0200 Subject: Fix GPU backend deleting resources without an active context This causes an assert with libepoxy, but was wrong already regardless. Refactor logic to work as follows: * GPU_exit() deletes backend resources * Destroy UI GPU resources with the context active * Call GPU_backend_exit() after deleting the context Ref D15291 Differential Revision: https://developer.blender.org/D15465 --- source/blender/gpu/GPU_context.h | 5 +++- source/blender/gpu/intern/gpu_backend.hh | 1 + source/blender/gpu/intern/gpu_context.cc | 33 +++++++++++++--------- source/blender/gpu/intern/gpu_init_exit.c | 2 ++ source/blender/gpu/intern/gpu_private.h | 4 +++ source/blender/gpu/metal/mtl_backend.hh | 5 ++++ source/blender/gpu/opengl/gl_backend.hh | 8 ++++-- source/blender/gpu/tests/gpu_testing.cc | 3 +- source/blender/windowmanager/intern/wm_init_exit.c | 26 +++++++++-------- 9 files changed, 58 insertions(+), 29 deletions(-) (limited to 'source') diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h index b04a4422baa..c81296093a1 100644 --- a/source/blender/gpu/GPU_context.h +++ b/source/blender/gpu/GPU_context.h @@ -17,8 +17,11 @@ extern "C" { #endif +/* GPU backends abstract the differences between different APIs. These must be + * initialized before creating contexts, and deleted after the last context is + * discarded. GPU_context_create automatically initializes a backend if none + * exists yet. */ bool GPU_backend_init_once(void); -void GPU_backend_init(eGPUBackendType backend); void GPU_backend_exit(void); bool GPU_backend_supported(eGPUBackendType type); diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh index 6e07e6c3229..d2890efee72 100644 --- a/source/blender/gpu/intern/gpu_backend.hh +++ b/source/blender/gpu/intern/gpu_backend.hh @@ -30,6 +30,7 @@ class VertBuf; class GPUBackend { public: virtual ~GPUBackend() = default; + 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 d3b208dc6f6..9b0670da8cb 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -27,6 +27,7 @@ #include "gpu_batch_private.hh" #include "gpu_context_private.hh" #include "gpu_matrix_private.h" +#include "gpu_private.h" #ifdef WITH_OPENGL_BACKEND # include "gl_backend.hh" @@ -213,20 +214,17 @@ bool GPU_backend_supported(eGPUBackendType type) bool GPU_backend_init_once() { - if (GPUBackend::get() == nullptr) { - if (!GPU_backend_supported(GPU_BACKEND_OPENGL)) { - return false; - } - /* TODO: move where it make sense. */ - GPU_backend_init(GPU_BACKEND_OPENGL); + if (GPUBackend::get() != nullptr) { + return true; } - return true; -} -void GPU_backend_init(eGPUBackendType backend_type) -{ - BLI_assert(g_backend == nullptr); - BLI_assert(GPU_backend_supported(backend_type)); + const eGPUBackendType backend_type = GPU_BACKEND_OPENGL; + if (!GPU_backend_supported(backend_type)) { + return false; + } + + static std::mutex backend_init_mutex; + std::scoped_lock lock(backend_init_mutex); switch (backend_type) { #ifdef WITH_OPENGL_BACKEND @@ -243,12 +241,19 @@ void GPU_backend_init(eGPUBackendType backend_type) BLI_assert(0); break; } + + return true; +} + +void gpu_backend_delete_resources() +{ + BLI_assert(backend); + g_backend->delete_resources(); } void GPU_backend_exit() { - /* TODO: assert no resource left. Currently UI textures are still not freed in their context - * correctly. */ + /* TODO: assert no resource left. */ delete g_backend; g_backend = nullptr; } diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 062614fb5cb..34b355eefaf 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -55,6 +55,8 @@ void GPU_exit(void) gpu_shader_dependency_exit(); gpu_shader_create_info_exit(); + gpu_backend_delete_resources(); + initialized = false; } diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h index a8ee5187d98..0e293302086 100644 --- a/source/blender/gpu/intern/gpu_private.h +++ b/source/blender/gpu/intern/gpu_private.h @@ -10,6 +10,10 @@ extern "C" { #endif +/* gpu_backend.cc */ + +void gpu_backend_delete_resources(void); + /* gpu_pbvh.c */ void gpu_pbvh_init(void); diff --git a/source/blender/gpu/metal/mtl_backend.hh b/source/blender/gpu/metal/mtl_backend.hh index 7228a5f7596..3e09408e43e 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 delete_resources() + { + /* Delete any resources with context active. */ + } + static bool metal_is_supported(); static MTLBackend *get() { diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh index 29249111294..e425b87afe8 100644 --- a/source/blender/gpu/opengl/gl_backend.hh +++ b/source/blender/gpu/opengl/gl_backend.hh @@ -42,11 +42,15 @@ class GLBackend : public GPUBackend { } ~GLBackend() { - GLTexture::samplers_free(); - GLBackend::platform_exit(); } + void delete_resources() override + { + /* Delete any resources with context active. */ + GLTexture::samplers_free(); + } + static GLBackend *get() { return static_cast(GPUBackend::get()); diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc index 4e93e062b50..5a2ad893360 100644 --- a/source/blender/gpu/tests/gpu_testing.cc +++ b/source/blender/gpu/tests/gpu_testing.cc @@ -17,6 +17,7 @@ void GPUTest::SetUp() GHOST_GLSettings glSettings = {0}; CLG_init(); ghost_system = GHOST_CreateSystem(); + GPU_backend_init_once(); ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings); GHOST_ActivateOpenGLContext(ghost_context); context = GPU_context_create(nullptr); @@ -26,9 +27,9 @@ void GPUTest::SetUp() void GPUTest::TearDown() { GPU_exit(); - GPU_backend_exit(); GPU_context_discard(context); GHOST_DisposeOpenGLContext(ghost_system, ghost_context); + GPU_backend_exit(); GHOST_DisposeSystem(ghost_system); CLG_exit(); } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index b9bb1d88819..7324abfd096 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -576,14 +576,6 @@ void WM_exit_ex(bContext *C, const bool do_python) BLF_exit(); - if (opengl_is_init) { - DRW_opengl_context_enable_ex(false); - GPU_pass_cache_free(); - GPU_exit(); - DRW_opengl_context_disable_ex(false); - DRW_opengl_context_destroy(); - } - BLT_lang_free(); ANIM_keyingset_infos_exit(); @@ -608,13 +600,25 @@ void WM_exit_ex(bContext *C, const bool do_python) ED_file_exit(); /* for fsmenu */ - UI_exit(); + /* Delete GPU resources and context. The UI also uses GPU resources and so + * is also deleted with the context active. */ + if (opengl_is_init) { + DRW_opengl_context_enable_ex(false); + UI_exit(); + GPU_pass_cache_free(); + GPU_exit(); + DRW_opengl_context_disable_ex(false); + DRW_opengl_context_destroy(); + } + else { + UI_exit(); + } + GPU_backend_exit(); + BKE_blender_userdef_data_free(&U, false); RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */ - GPU_backend_exit(); - wm_ghost_exit(); CTX_free(C); -- cgit v1.2.3