From 05c56603a92b87cea8749fec6dc88200f06d5c7b Mon Sep 17 00:00:00 2001
From: Jason Fielder <jason-fielder@noreply.localhost>
Date: Tue, 7 Nov 2023 15:35:42 +0100
Subject: [PATCH] Fix #114192: Resolve animation player greying out on resize
 in Metal

Standalone animation player has inconsistent GPU context activation
paradigm compared with standard rendering paths. The Metal backend
utilises the context activation step to refresh target window swapchains
from within the GHOST module.

This PR adds activation and deactivation calls, and also aims to clean up
GPU_render_begin/end setup to ensure all paths are covered.

Also resolves a bug upon shutdown wherein GPU resources which may
be tied to a GPU context are released during IMB_exit(), which is called
after GPU context destruction.

Authored by Apple: Michael Parkin-White

Pull Request: https://projects.blender.org/blender/blender/pulls/114573
---
 .../windowmanager/intern/wm_playanim.cc       | 40 +++++++++++++------
 1 file changed, 28 insertions(+), 12 deletions(-)

diff --git a/source/blender/windowmanager/intern/wm_playanim.cc b/source/blender/windowmanager/intern/wm_playanim.cc
index b4e2adb692e..0b2f43e8d4d 100644
--- a/source/blender/windowmanager/intern/wm_playanim.cc
+++ b/source/blender/windowmanager/intern/wm_playanim.cc
@@ -624,7 +624,7 @@ static void draw_display_buffer(const PlayDisplayContext *display_ctx,
  * \param draw_flip: X/Y flipping (ignored when null).
  * \param indicator_factor: Display a vertical indicator (ignored when -1).
  */
-static void playanim_toscreen_ex(GHOST_WindowHandle ghost_window,
+static void playanim_toscreen_ex(GhostData *data,
                                  const PlayDisplayContext *display_ctx,
                                  const PlayAnimPict *picture,
                                  ImBuf *ibuf,
@@ -635,9 +635,11 @@ static void playanim_toscreen_ex(GHOST_WindowHandle ghost_window,
                                  const bool draw_flip[2],
                                  const float indicator_factor)
 {
-  GHOST_ActivateWindowDrawingContext(ghost_window);
+  GHOST_ActivateWindowDrawingContext(data->window);
   GPU_render_begin();
-  GPU_render_step();
+
+  GPUContext *restore_context = GPU_context_active_get();
+  GPU_context_active_set(data->gpu_context);
 
   GPU_clear_color(0.1f, 0.1f, 0.1f, 0.0f);
 
@@ -689,7 +691,7 @@ static void playanim_toscreen_ex(GHOST_WindowHandle ghost_window,
       SNPRINTF(label, "%s | <failed to load buffer>", picture->filepath);
     }
 
-    playanim_window_get_size(ghost_window, &sizex, &sizey);
+    playanim_window_get_size(data->window, &sizex, &sizey);
     fsizex_inv = 1.0f / sizex;
     fsizey_inv = 1.0f / sizey;
 
@@ -737,11 +739,17 @@ static void playanim_toscreen_ex(GHOST_WindowHandle ghost_window,
     GPU_matrix_pop_projection();
   }
 
-  GHOST_SwapWindowBuffers(ghost_window);
+  GPU_render_step();
+  if (GPU_backend_get_type() == GPU_BACKEND_METAL) {
+    GPU_flush();
+  }
+
+  GHOST_SwapWindowBuffers(data->window);
+  GPU_context_active_set(restore_context);
   GPU_render_end();
 }
 
-static void playanim_toscreen_on_load(GHOST_WindowHandle ghost_window,
+static void playanim_toscreen_on_load(GhostData *ghost_data,
                                       const PlayDisplayContext *display_ctx,
                                       const PlayAnimPict *picture,
                                       ImBuf *ibuf)
@@ -753,7 +761,7 @@ static void playanim_toscreen_on_load(GHOST_WindowHandle ghost_window,
   const bool *draw_flip = nullptr;
 
   playanim_toscreen_ex(
-      ghost_window, display_ctx, picture, ibuf, font_id, fstep, zoom, draw_flip, indicator_factor);
+      ghost_data, display_ctx, picture, ibuf, font_id, fstep, zoom, draw_flip, indicator_factor);
 }
 
 static void playanim_toscreen(PlayState *ps, const PlayAnimPict *picture, ImBuf *ibuf)
@@ -779,7 +787,7 @@ static void playanim_toscreen(PlayState *ps, const PlayAnimPict *picture, ImBuf
   }
 
   BLI_assert(ps->loading == false);
-  playanim_toscreen_ex(ps->ghost_data.window,
+  playanim_toscreen_ex(&ps->ghost_data,
                        &ps->display_ctx,
                        picture,
                        ibuf,
@@ -804,7 +812,7 @@ static void build_pict_list_from_anim(GhostData *ghost_data,
 
   ImBuf *ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
   if (ibuf) {
-    playanim_toscreen_on_load(ghost_data->window, display_ctx, nullptr, ibuf);
+    playanim_toscreen_on_load(ghost_data, display_ctx, nullptr, ibuf);
     IMB_freeImBuf(ibuf);
   }
 
@@ -888,7 +896,7 @@ static void build_pict_list_from_image_sequence(GhostData *ghost_data,
 
       if (ibuf) {
         if (display_imbuf) {
-          playanim_toscreen_on_load(ghost_data->window, display_ctx, picture, ibuf);
+          playanim_toscreen_on_load(ghost_data, display_ctx, picture, ibuf);
         }
 #ifdef USE_FRAME_CACHE_LIMIT
         if (fill_cache) {
@@ -1951,9 +1959,15 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
 
       ps.next_frame = ps.direction;
 
+      GPU_render_begin();
+      GPUContext *restore_context = GPU_context_active_get();
+      GPU_context_active_set(ps.ghost_data.gpu_context);
       while ((has_event = GHOST_ProcessEvents(ps.ghost_data.system, false))) {
         GHOST_DispatchEvents(ps.ghost_data.system);
       }
+      GPU_render_end();
+      GPU_context_active_set(restore_context);
+
       if (ps.go == false) {
         break;
       }
@@ -2055,6 +2069,10 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
 
   BLF_exit();
 
+  /* NOTE: Must happen before GPU Context destruction as GPU resources are released via
+   * Colour Management module. */
+  IMB_exit();
+
   if (ps.ghost_data.gpu_context) {
     GPU_context_active_set(ps.ghost_data.gpu_context);
     GPU_exit();
@@ -2074,8 +2092,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
 
   GHOST_DisposeSystem(ps.ghost_data.system);
 
-  IMB_exit();
-
   totblock = MEM_get_memory_blocks_in_use();
   if (totblock != 0) {
 /* prints many bAKey, bArgument's which are tricky to fix */
-- 
GitLab