diff mbox series

[07/26] hw/display/apple-gfx: Makes set_mode thread & memory safe

Message ID 20240715210705.32365-8-phil@philjordan.eu (mailing list archive)
State New, archived
Headers show
Series [01/26] hw/vmapple/apple-gfx: Introduce ParavirtualizedGraphics.Framework support | expand

Commit Message

Phil Dennis-Jordan July 15, 2024, 9:06 p.m. UTC
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 <phil@philjordan.eu>
---
 hw/display/apple-gfx.m | 54 +++++++++++++++++++++++++++++++-----------
 1 file changed, 40 insertions(+), 14 deletions(-)
diff mbox series

Patch

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)