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
This commit is contained in:
Brecht Van Lommel 2022-07-15 12:44:35 +02:00
parent 5e1229f253
commit 1cf465bbc3
Notes: blender-bot 2023-02-14 01:52:41 +01:00
Referenced by commit c505f19efe, Fix compiler error in debug builds after 1cf465bbc3
9 changed files with 58 additions and 29 deletions

View File

@ -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);

View File

@ -30,6 +30,7 @@ class VertBuf;
class GPUBackend {
public:
virtual ~GPUBackend() = default;
virtual void delete_resources() = 0;
static GPUBackend *get();

View File

@ -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;
}

View File

@ -55,6 +55,8 @@ void GPU_exit(void)
gpu_shader_dependency_exit();
gpu_shader_create_info_exit();
gpu_backend_delete_resources();
initialized = false;
}

View File

@ -10,6 +10,10 @@
extern "C" {
#endif
/* gpu_backend.cc */
void gpu_backend_delete_resources(void);
/* gpu_pbvh.c */
void gpu_pbvh_init(void);

View File

@ -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()
{

View File

@ -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<GLBackend *>(GPUBackend::get());

View File

@ -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();
}

View File

@ -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);