From f8bdefe1b56afecbec45da1dfa8d3b5e4f2bd512 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 13 Oct 2019 15:18:28 -0300 Subject: [PATCH] macOS: Fix asserts in SDL_Render's metal scissor code when the window is resized. --- src/video/cocoa/SDL_cocoametalview.h | 6 +++- src/video/cocoa/SDL_cocoametalview.m | 44 +++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/video/cocoa/SDL_cocoametalview.h b/src/video/cocoa/SDL_cocoametalview.h index 77e7256bed646..76e2cf82f800b 100644 --- a/src/video/cocoa/SDL_cocoametalview.h +++ b/src/video/cocoa/SDL_cocoametalview.h @@ -42,12 +42,16 @@ @interface SDL_cocoametalview : NSView - (instancetype)initWithFrame:(NSRect)frame - highDPI:(BOOL)highDPI; + highDPI:(BOOL)highDPI + windowID:(Uint32)windowID; + +- (void)updateDrawableSize; /* Override superclass tag so this class can set it. */ @property (assign, readonly) NSInteger tag; @property (nonatomic) BOOL highDPI; +@property (nonatomic) Uint32 sdlWindowID; @end diff --git a/src/video/cocoa/SDL_cocoametalview.m b/src/video/cocoa/SDL_cocoametalview.m index 4eea8d1bc0003..d4911db297c1c 100644 --- a/src/video/cocoa/SDL_cocoametalview.m +++ b/src/video/cocoa/SDL_cocoametalview.m @@ -30,6 +30,28 @@ #if SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) #include "SDL_assert.h" +#include "SDL_events.h" + +static int SDLCALL +SDL_MetalViewEventWatch(void *userdata, SDL_Event *event) +{ + /* Update the drawable size when SDL receives a size changed event for + * the window that contains the metal view. It would be nice to use + * - (void)resizeWithOldSuperviewSize:(NSSize)oldSize and + * - (void)viewDidChangeBackingProperties instead, but SDL's size change + * events don't always happen in the same frame (for example when a + * resizable window exits a fullscreen Space via the user pressing the OS + * exit-space button). */ + if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + @autoreleasepool { + SDL_cocoametalview *view = (__bridge SDL_cocoametalview *)userdata; + if (view.sdlWindowID == event->window.windowID) { + [view updateDrawableSize]; + } + } + } + return 0; +} @implementation SDL_cocoametalview @@ -55,20 +77,30 @@ - (CALayer*)makeBackingLayer - (instancetype)initWithFrame:(NSRect)frame highDPI:(BOOL)highDPI + windowID:(Uint32)windowID; { if ((self = [super initWithFrame:frame])) { self.highDPI = highDPI; + self.sdlWindowID = windowID; self.wantsLayer = YES; /* Allow resize. */ self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + SDL_AddEventWatch(SDL_MetalViewEventWatch, self); + [self updateDrawableSize]; } return self; } +- (void)dealloc +{ + SDL_DelEventWatch(SDL_MetalViewEventWatch, self); + [super dealloc]; +} + - (NSInteger)tag { return METALVIEW_TAG; @@ -91,13 +123,6 @@ - (void)updateDrawableSize metalLayer.drawableSize = NSSizeToCGSize(backingSize); } -/* Set the size of the metal drawables when the view is resized. */ -- (void)resizeWithOldSuperviewSize:(NSSize)oldSize -{ - [super resizeWithOldSuperviewSize:oldSize]; - [self updateDrawableSize]; -} - @end SDL_MetalView @@ -106,10 +131,13 @@ - (void)resizeWithOldSuperviewSize:(NSSize)oldSize SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata; NSView *view = data->nswindow.contentView; BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; + Uint32 windowID = SDL_GetWindowID(window); SDL_cocoametalview *newview; SDL_MetalView metalview; - newview = [[SDL_cocoametalview alloc] initWithFrame:view.frame highDPI:highDPI]; + newview = [[SDL_cocoametalview alloc] initWithFrame:view.frame + highDPI:highDPI + windowID:windowID]; if (newview == nil) { return NULL; }