diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 737b4a542c8..2427301782c 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -173,6 +173,11 @@ void GPU_invalid_tex_free(void); void GPU_texture_free(GPUTexture *tex); +void GPU_texture_init_orphans(void); +void GPU_texture_exit_orphans(void); +/* This has to be called from a thread with an ogl context bound. */ +void GPU_texture_delete_orphans(void); + void GPU_texture_ref(GPUTexture *tex); void GPU_texture_bind(GPUTexture *tex, int number); void GPU_texture_unbind(GPUTexture *tex); diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index c2f14687ff5..7b596e6d76b 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -34,6 +34,7 @@ #include "GPU_init_exit.h" /* interface */ #include "GPU_immediate.h" #include "GPU_batch.h" +#include "GPU_texture.h" #include "BKE_global.h" #include "intern/gpu_codegen.h" @@ -56,6 +57,7 @@ void GPU_init(void) gpu_extensions_init(); /* must come first */ + GPU_texture_init_orphans(); gpu_codegen_init(); if (G.debug & G_DEBUG_GPU) @@ -80,6 +82,8 @@ void GPU_exit(void) gpu_batch_exit(); + GPU_texture_exit_orphans(); + if (G.debug & G_DEBUG_GPU) gpu_debug_exit(); diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 14d0b27bc28..d916b75417f 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -32,6 +32,8 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_base.h" +#include "BLI_listbase.h" +#include "BLI_threads.h" #include "BKE_global.h" @@ -49,6 +51,9 @@ static struct GPUTextureGlobal { GPUTexture *invalid_tex_3D; } GG = {NULL, NULL, NULL}; +static ListBase g_orphaned_tex = {NULL, NULL}; +static ThreadMutex g_orphan_lock; + /* Maximum number of FBOs a texture can be attached to. */ #define GPU_TEX_MAX_FBO_ATTACHED 8 @@ -1083,6 +1088,16 @@ void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat) glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat); } +static void gpu_texture_delete(GPUTexture *tex) +{ + if (tex->bindcode && !tex->fromblender) + glDeleteTextures(1, &tex->bindcode); + + gpu_texture_memory_footprint_remove(tex); + + MEM_freeN(tex); +} + void GPU_texture_free(GPUTexture *tex) { tex->refcount--; @@ -1097,15 +1112,39 @@ void GPU_texture_free(GPUTexture *tex) } } - if (tex->bindcode && !tex->fromblender) - glDeleteTextures(1, &tex->bindcode); - - gpu_texture_memory_footprint_remove(tex); - - MEM_freeN(tex); + /* TODO(fclem): Check if the thread has an ogl context. */ + if (BLI_thread_is_main()) { + gpu_texture_delete(tex); + } + else{ + BLI_mutex_lock(&g_orphan_lock); + BLI_addtail(&g_orphaned_tex, BLI_genericNodeN(tex)); + BLI_mutex_unlock(&g_orphan_lock); + } } } +void GPU_texture_init_orphans(void) +{ + BLI_mutex_init(&g_orphan_lock); +} + +void GPU_texture_delete_orphans(void) +{ + BLI_mutex_lock(&g_orphan_lock); + LinkData *link; + while((link = BLI_pophead(&g_orphaned_tex))) { + gpu_texture_delete((GPUTexture *)link->data); + } + BLI_mutex_unlock(&g_orphan_lock); +} + +void GPU_texture_exit_orphans(void) +{ + GPU_texture_delete_orphans(); + BLI_mutex_end(&g_orphan_lock); +} + void GPU_texture_ref(GPUTexture *tex) { tex->refcount++; diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 28fb4f2e011..ca5f95909f8 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -85,6 +85,7 @@ #include "GPU_framebuffer.h" #include "GPU_init_exit.h" #include "GPU_immediate.h" +#include "GPU_texture.h" #include "BLF_api.h" #include "UI_resources.h" @@ -2023,6 +2024,7 @@ void wm_window_raise(wmWindow *win) void wm_window_swap_buffers(wmWindow *win) { + GPU_texture_delete_orphans(); /* XXX should be done elsewhere. */ GHOST_SwapWindowBuffers(win->ghostwin); }