[Bf-blender-cvs] [b5660f71fe7] master: Fix missing GPU image free in background mode

Brecht Van Lommel noreply at git.blender.org
Wed Jul 1 16:06:39 CEST 2020


Commit: b5660f71fe77969a75d6b41d87a310ec252b3a4c
Author: Brecht Van Lommel
Date:   Wed Jul 1 14:55:43 2020 +0200
Branches: master
https://developer.blender.org/rBb5660f71fe77969a75d6b41d87a310ec252b3a4c

Fix missing GPU image free in background mode

This is legacy code from before Eevee and Workbench rendering in background
mode was supported. Avoid memory leak by only queueing GPU textures to be
freed when we know they have been allocated.

Differential Revision: https://developer.blender.org/D8172

===================================================================

M	source/blender/blenkernel/intern/image.c
M	source/blender/gpu/GPU_draw.h
M	source/blender/gpu/intern/gpu_draw.c
M	source/blender/windowmanager/intern/wm_draw.c
M	source/blender/windowmanager/intern/wm_init_exit.c

===================================================================

diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 24d175511c7..bb793b58a1d 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -360,13 +360,7 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
     ima->rr = NULL;
   }
 
-  if (!G.background) {
-    /* Background mode doesn't use OpenGL,
-     * so we can avoid freeing GPU images and save some
-     * time by skipping mutex lock.
-     */
-    GPU_free_image(ima);
-  }
+  GPU_free_image(ima);
 
   LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
     tile->ok = IMA_OK;
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index ab507d852e8..1cd5c4d519e 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -86,7 +86,7 @@ void GPU_create_smoke_coba_field(struct FluidModifierData *mmd);
 void GPU_create_smoke_velocity(struct FluidModifierData *mmd);
 
 /* Delayed free of OpenGL buffers by main thread */
-void GPU_free_unused_buffers(struct Main *bmain);
+void GPU_free_unused_buffers(void);
 
 #ifdef __cplusplus
 }
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index d768ce373b6..f07e3ed70d7 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -60,7 +60,8 @@
 
 #include "PIL_time.h"
 
-static void gpu_free_image_immediate(Image *ima);
+static void gpu_free_image(Image *ima, const bool immediate);
+static void gpu_free_unused_buffers(void);
 
 //* Checking powers of two for images since OpenGL ES requires it */
 #ifdef WITH_DDS
@@ -859,9 +860,13 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf,
     return NULL;
   }
 
+  /* 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();
+
   /* currently, gpu refresh tagging is used by ima sequences */
   if (ima->gpuflag & IMA_GPU_REFRESH) {
-    gpu_free_image_immediate(ima);
+    gpu_free_image(ima, true);
     ima->gpuflag &= ~IMA_GPU_REFRESH;
   }
 
@@ -1338,47 +1343,47 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
 #endif
 }
 
-static LinkNode *image_free_queue = NULL;
-static ThreadMutex img_queue_mutex = BLI_MUTEX_INITIALIZER;
+/* Delayed GPU texture free. Image datablocks can be deleted by any thread,
+ * but there may not be any active OpenGL context. In that case we push them
+ * into a queue and free the buffers later. */
+static LinkNode *gpu_texture_free_queue = NULL;
+static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER;
 
-static void gpu_queue_image_for_free(Image *ima)
+static void gpu_free_unused_buffers()
 {
-  BLI_mutex_lock(&img_queue_mutex);
-  BLI_linklist_prepend(&image_free_queue, ima);
-  BLI_mutex_unlock(&img_queue_mutex);
-}
-
-void GPU_free_unused_buffers(Main *bmain)
-{
-  if (!BLI_thread_is_main()) {
+  if (gpu_texture_free_queue == NULL) {
     return;
   }
 
-  BLI_mutex_lock(&img_queue_mutex);
-
-  /* images */
-  for (LinkNode *node = image_free_queue; node; node = node->next) {
-    Image *ima = node->link;
+  BLI_mutex_lock(&gpu_texture_queue_mutex);
 
-    /* check in case it was freed in the meantime */
-    if (bmain && BLI_findindex(&bmain->images, ima) != -1) {
-      GPU_free_image(ima);
+  if (gpu_texture_free_queue != NULL) {
+    for (LinkNode *node = gpu_texture_free_queue; node; node = node->next) {
+      GPUTexture *tex = node->link;
+      GPU_texture_free(tex);
     }
-  }
 
-  BLI_linklist_free(image_free_queue, NULL);
-  image_free_queue = NULL;
+    BLI_linklist_free(gpu_texture_free_queue, NULL);
+    gpu_texture_free_queue = NULL;
+  }
 
-  BLI_mutex_unlock(&img_queue_mutex);
+  BLI_mutex_unlock(&gpu_texture_queue_mutex);
 }
 
-static void gpu_free_image_immediate(Image *ima)
+static void gpu_free_image(Image *ima, const bool immediate)
 {
   for (int eye = 0; eye < 2; eye++) {
     for (int i = 0; i < TEXTARGET_COUNT; i++) {
-      /* free glsl image binding */
       if (ima->gputexture[i][eye] != NULL) {
-        GPU_texture_free(ima->gputexture[i][eye]);
+        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] = NULL;
       }
     }
@@ -1387,14 +1392,16 @@ static void gpu_free_image_immediate(Image *ima)
   ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
 }
 
-void GPU_free_image(Image *ima)
+void GPU_free_unused_buffers()
 {
-  if (!BLI_thread_is_main()) {
-    gpu_queue_image_for_free(ima);
-    return;
+  if (BLI_thread_is_main()) {
+    gpu_free_unused_buffers();
   }
+}
 
-  gpu_free_image_immediate(ima);
+void GPU_free_image(Image *ima)
+{
+  gpu_free_image(ima, BLI_thread_is_main());
 }
 
 void GPU_free_images(Main *bmain)
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 6a19ce62f50..3c2bc14837d 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -1012,7 +1012,7 @@ void wm_draw_update(bContext *C)
   wmWindowManager *wm = CTX_wm_manager(C);
   wmWindow *win;
 
-  GPU_free_unused_buffers(bmain);
+  GPU_free_unused_buffers();
 
   for (win = wm->windows.first; win; win = win->next) {
 #ifdef WIN32
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index e0d2127ba51..cb5a039765a 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -578,7 +578,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
   BKE_subdiv_exit();
 
   if (opengl_is_init) {
-    GPU_free_unused_buffers(G_MAIN);
+    GPU_free_unused_buffers();
   }
 
   BKE_blender_free(); /* blender.c, does entire library and spacetypes */



More information about the Bf-blender-cvs mailing list