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)