From c00e8866f6bf3512aa699a46d9d8eb155ca51876 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 31 May 2022 08:49:30 +0200 Subject: Remove textures that cannot be accessed from any image in bmain. --- source/blender/blenkernel/BKE_image.h | 2 +- source/blender/blenkernel/intern/image_gpu.cc | 98 ++++++++++------------ source/blender/windowmanager/intern/wm_draw.c | 2 +- source/blender/windowmanager/intern/wm_init_exit.c | 5 +- 4 files changed, 52 insertions(+), 55 deletions(-) diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index f8a8b30abcf..30b899812e3 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -525,7 +525,7 @@ void BKE_image_paint_set_mipmap(bool mipmap); /** * Delayed free of OpenGL buffers by main thread. */ -void BKE_image_free_unused_gpu_textures(void); +void BKE_image_free_unused_gpu_textures(const struct Main *bmain); struct RenderSlot *BKE_image_add_renderslot(struct Image *ima, const char *name); bool BKE_image_remove_renderslot(struct Image *ima, struct ImageUser *iuser, int slot); diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc index 476c0b23fe5..b63a9ae8130 100644 --- a/source/blender/blenkernel/intern/image_gpu.cc +++ b/source/blender/blenkernel/intern/image_gpu.cc @@ -7,6 +7,8 @@ #include "MEM_guardedalloc.h" +#include "atomic_ops.h" + #include "BLI_bitmap.h" #include "BLI_boxpack_2d.h" #include "BLI_linklist.h" @@ -52,7 +54,8 @@ struct ImageGPUTextureStore { public: GPUTexture *gputextures[TEXTARGET_COUNT][2]; struct { - bool in_use : 1; + bool in_use_gc : 1; + bool in_use_bmain : 1; } flags; Entry() @@ -62,6 +65,8 @@ struct ImageGPUTextureStore { gputextures[target][eye] = nullptr; } } + flags.in_use_gc = false; + flags.in_use_bmain = false; } Entry(Entry &&other) @@ -72,7 +77,7 @@ struct ImageGPUTextureStore { other.gputextures[target][eye] = nullptr; } } - flags.in_use = other.flags.in_use; + flags = other.flags; }; virtual ~Entry() @@ -94,7 +99,7 @@ struct ImageGPUTextureStore { void tag_used() { - flags.in_use = true; + flags.in_use_gc = true; } void clear() @@ -114,19 +119,40 @@ struct ImageGPUTextureStore { void reset_usage() { for (Entry &entry : entries.values()) { - entry.flags.in_use = false; + entry.flags.in_use_gc = false; } } void remove_unused() { - int entries_removed = 0; for (auto it : entries.items()) { - if (it.value.flags.in_use) { + if (it.value.flags.in_use_gc) { + continue; + } + entries.remove(it.key); + } + } + + void remove_unused(const Main *bmain) + { + for (Entry &entry : entries.values()) { + entry.flags.in_use_bmain = false; + } + + LISTBASE_FOREACH (Image *, image, &bmain->images) { + std::string key = create_key(*image); + Entry *entry = entries.lookup_ptr(key); + if (entry == nullptr) { + continue; + } + entry->flags.in_use_bmain = true; + } + + for (auto it : entries.items()) { + if (it.value.flags.in_use_bmain) { continue; } entries.remove(it.key); - entries_removed++; } } @@ -210,8 +236,6 @@ extern "C" { using namespace blender::bke::image::gpu; /* Prototypes. */ -static void gpu_free_unused_buffers(); -static void image_free_gpu(Image *ima, const bool immediate); static void image_update_gputexture_ex(Image *ima, ImageGPUTextureStore::Entry &entry, ImageTile *tile, @@ -520,10 +544,6 @@ static GPUTexture *image_get_gpu_texture(Image *ima, return nullptr; } - /* Free any unused GPU textures, since we know we are in a thread with OpenGL - * context and might as well ensure we have as much space free as possible. */ - gpu_free_unused_buffers(); - /* Free GPU textures when requesting a different render pass/layer. * When `iuser` isn't set (texture painting single image mode) we assume that * the current `pass` and `layer` should be 0. */ @@ -646,29 +666,28 @@ GPUTexture *BKE_image_get_gpu_tilemap(Image *image, ImageUser *iuser, ImBuf *ibu * In that case we push them into a queue and free the buffers later. * \{ */ -static LinkNode *gpu_texture_free_queue = nullptr; -static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER; +static int32_t free_unused_gpu_textures = false; -static void gpu_free_unused_buffers() +static void gpu_free_unused_buffers(const Main *bmain) { - if (gpu_texture_free_queue == nullptr) { + BLI_assert(BLI_thread_is_main()); + + if (G.is_rendering) { return; } - BLI_mutex_lock(&gpu_texture_queue_mutex); - - while (gpu_texture_free_queue != nullptr) { - GPUTexture *tex = static_cast(BLI_linklist_pop(&gpu_texture_free_queue)); - GPU_texture_free(tex); + int32_t do_free = atomic_cas_int32(&free_unused_gpu_textures, true, false); + if (!do_free) { + return; } - BLI_mutex_unlock(&gpu_texture_queue_mutex); + g_texture_store.remove_unused(bmain); } -void BKE_image_free_unused_gpu_textures() +void BKE_image_free_unused_gpu_textures(const Main *bmain) { if (BLI_thread_is_main()) { - gpu_free_unused_buffers(); + gpu_free_unused_buffers(bmain); } } @@ -678,34 +697,9 @@ void BKE_image_free_unused_gpu_textures() /** \name Deletion * \{ */ -static void image_free_gpu(Image *UNUSED(ima), const bool UNUSED(immediate)) -{ -// TODO(jbakker)... -#if 0 - for (int eye = 0; eye < 2; eye++) { - for (int i = 0; i < TEXTARGET_COUNT; i++) { - if (ima->gputexture[i][eye] != nullptr) { - if (immediate) { - GPU_texture_free(ima->gputexture[i][eye]); - } - else { - BLI_mutex_lock(&gpu_texture_queue_mutex); - BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]); - BLI_mutex_unlock(&gpu_texture_queue_mutex); - } - - ima->gputexture[i][eye] = nullptr; - } - } - } - - ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE; -#endif -} - -void BKE_image_free_gputextures(Image *ima) +void BKE_image_free_gputextures(Image *UNUSED(ima)) { - image_free_gpu(ima, BLI_thread_is_main()); + atomic_store_int32(&free_unused_gpu_textures, true); } void BKE_image_free_all_gputextures(Main *UNUSED(bmain)) diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index d2ade7b0376..8fb86642495 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -1062,7 +1062,7 @@ void wm_draw_update(bContext *C) GPU_render_begin(); GPU_render_step(); - BKE_image_free_unused_gpu_textures(); + BKE_image_free_unused_gpu_textures(bmain); LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { #ifdef WIN32 diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 8d6741dcfb6..f735c4fafed 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -541,7 +541,10 @@ void WM_exit_ex(bContext *C, const bool do_python) BKE_subdiv_exit(); if (opengl_is_init) { - BKE_image_free_unused_gpu_textures(); + if (C) { + Main *bmain = CTX_data_main(C); + BKE_image_free_unused_gpu_textures(bmain); + } } BKE_blender_free(); /* blender.c, does entire library and spacetypes */ -- cgit v1.2.3