When the set_mode callback was invoked outside of the BQL, there
could be a race condition swapping out the resized render target
texture and VRAM. set_mode may be called inside or out of the
BQL depending on context (reentrant from a MMIO write or not)
so we need to check locking state first.

Signed-off-by: Phil Dennis-Jordan <p...@philjordan.eu>
---
 hw/display/apple-gfx.m | 54 +++++++++++++++++++++++++++++++-----------
 1 file changed, 40 insertions(+), 14 deletions(-)

diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
index b10c060d9a..39aba8d143 100644
--- a/hw/display/apple-gfx.m
+++ b/hw/display/apple-gfx.m
@@ -290,34 +290,60 @@ static void update_cursor(AppleGFXState *s)
 
 static void set_mode(AppleGFXState *s, uint32_t width, uint32_t height)
 {
-    void *vram = g_malloc0(width * height * 4);
+    void *vram = NULL;
     void *old_vram = s->vram;
     DisplaySurface *surface;
     MTLTextureDescriptor *textureDescriptor;
-    id<MTLTexture> old_texture = s->texture;
+    id<MTLTexture> old_texture = nil;
+    id<MTLTexture> texture = nil;
+    bool locking_required = false;
 
+    locking_required = !bql_locked();
+    if (locking_required) {
+        bql_lock();
+    }
     if (s->surface &&
         width == surface_width(s->surface) &&
         height == surface_height(s->surface)) {
+        if (locking_required) {
+            bql_unlock();
+        }
         return;
     }
+    if (locking_required) {
+        bql_unlock();
+    }
+
+    vram = g_malloc0(width * height * 4);
     surface = qemu_create_displaysurface_from(width, height, 
PIXMAN_LE_a8r8g8b8,
                                               width * 4, vram);
-    s->surface = surface;
-    dpy_gfx_replace_surface(s->con, surface);
-    s->vram = vram;
-    g_free(old_vram);
 
-    textureDescriptor = [MTLTextureDescriptor 
texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
-                                              width:width
-                                              height:height
-                                              mipmapped:NO];
-    textureDescriptor.usage = s->pgdisp.minimumTextureUsage;
-    s->texture = [s->mtl newTextureWithDescriptor:textureDescriptor];
+    @autoreleasepool {
+        textureDescriptor =
+            [MTLTextureDescriptor
+                texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
+                                             width:width
+                                            height:height
+                                         mipmapped:NO];
+        textureDescriptor.usage = s->pgdisp.minimumTextureUsage;
+        texture = [s->mtl newTextureWithDescriptor:textureDescriptor];
+    }
 
-    if (old_texture) {
-        [old_texture release];
+    if (locking_required) {
+        bql_lock();
+    }
+    old_vram = s->vram;
+    s->vram = vram;
+    s->surface = surface;
+    dpy_gfx_replace_surface(s->con, surface);
+    old_texture = s->texture;
+    s->texture = texture;
+    if (locking_required) {
+        bql_unlock();
     }
+
+    g_free(old_vram);
+    [old_texture release];
 }
 
 static void create_fb(AppleGFXState *s)
-- 
2.39.3 (Apple Git-146)


Reply via email to