From 718b76b87cc527ec94e65d3d992066412d8471f5 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 5 Apr 2020 08:54:07 -0700 Subject: [PATCH] Fixed bug 4788 - macOS 10.14 (Mojave) opengl issues (SDL-1.2) Murphy I don't build SDL apps on macOS myself, but two recent pieces of code I've written have run into this (or a related Mojave/SDL1.2 blank screen bug) for other users. I thought I'd share what I'd gleaned in case it's helpful. First, I notice the issue specifies OpenGL. Maybe that's a backend thing I'm not aware of or maybe there are multiple blank screen bugs related to Mojave, but this also occurs with applications that aren't (explicitly, anyway) doing anything with OpenGL. Second, the solution of building with an old SDK (e.g., the macOS 10.13 SDK from Xcode 10.1) resolves it (though it's a pain). Third, it looks like this came up in DOSBox-X and Jon Campbell patched the vendored SDL1.2 to fix it (I haven't tested this on my own applications). I'm not sure if there was an attempt to upstream this, but here's the commit and a related issue tracker entry where it's discussed: https://github.com/joncampbell123/dosbox-x/commit/fdf6061c05dcb35a1ea111ad5b75ade350059df3 https://github.com/joncampbell123/dosbox-x/issues/896 Fourth, lending credence to the idea that there may be multiple bugs at play here, some of the Mojave bug reports refer to a *black* screen, but others are less specific about "no video" or "blank screen" or the like. In the case of my applications, the result isn't black. It's light gray or something (possibly a default window background color?). [Fixed with patch by Alex Sirota] --- src/video/quartz/SDL_QuartzVideo.m | 55 +++++++++++++++++++++++++---- src/video/quartz/SDL_QuartzWindow.h | 1 + src/video/quartz/SDL_QuartzWindow.m | 7 ++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/video/quartz/SDL_QuartzVideo.m b/src/video/quartz/SDL_QuartzVideo.m index 5e40bdbec..dd88ae015 100644 --- a/src/video/quartz/SDL_QuartzVideo.m +++ b/src/video/quartz/SDL_QuartzVideo.m @@ -940,6 +940,10 @@ other blitting while waiting on the VBL (and hence results in higher framerates) /* Set app state, hide cursor if necessary, ... */ QZ_DoActivate(this); + [ window_view setNeedsDisplay:YES ]; + [ [ qz_window contentView ] setNeedsDisplay:YES ]; + [ qz_window displayIfNeeded ]; + return current; /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */ @@ -1115,7 +1119,11 @@ other blitting while waiting on the VBL (and hence results in higher framerates) /* Save flags to ensure correct teardown */ mode_flags = current->flags; - + + [ window_view setNeedsDisplay:YES ]; + [ [ qz_window contentView ] setNeedsDisplay:YES ]; + [ qz_window displayIfNeeded ]; + /* Fade in again (asynchronously) if we came from a fullscreen mode and faded to black */ if (fade_token != kCGDisplayFadeReservationInvalidToken) { CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE); @@ -1155,7 +1163,13 @@ other blitting while waiting on the VBL (and hence results in higher framerates) if (qz_window != nil) { nsgfx_context = [NSGraphicsContext graphicsContextWithWindow:qz_window]; - [NSGraphicsContext setCurrentContext:nsgfx_context]; + if (nsgfx_context != NULL) { + [NSGraphicsContext setCurrentContext:nsgfx_context]; + } + else { + /* Whoops, looks like Mojave doesn't support this anymore */ + fprintf(stderr,"Unable to obtain graphics context for NSWindow (Mojave behavior)\n"); + } } /* Setup the new pixel format */ @@ -1500,10 +1514,17 @@ static void QZ_DrawResizeIcon (_THIS) } } -static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) -{ +static SDL_VideoDevice *last_this = NULL; + +void QZ_UpdateRectsOnDrawRect(/*TODO: NSRect from drawRect*/) { + // HACK + SDL_VideoDevice *this = last_this; + + if (this == NULL) return; + if (SDL_VideoSurface == NULL) return; + if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) { - QZ_GL_SwapBuffers (this); +// TODO } else if ( [ qz_window isMiniaturized ] ) { @@ -1512,8 +1533,9 @@ static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) else { NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; - if (ctx != nsgfx_context) { /* uhoh, you might be rendering from another thread... */ - [NSGraphicsContext setCurrentContext:nsgfx_context]; + /* NTS: nsgfx_context == NULL will occur on Mojave, may be non-NULL on older versions of OS X */ + if (nsgfx_context != NULL && ctx != nsgfx_context) { /* uhoh, you might be rendering from another thread... */ + [NSGraphicsContext setCurrentContext:nsgfx_context]; ctx = nsgfx_context; } CGContextRef cgc = (CGContextRef) [ctx graphicsPort]; @@ -1528,6 +1550,25 @@ static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) } } +static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) +{ + // HACK + last_this = this; + + if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) { + QZ_GL_SwapBuffers (this); + // TODO? + } + else if ( [ qz_window isMiniaturized ] ) { + /* Do nothing if miniaturized */ + } + else { + [ window_view setNeedsDisplay:YES ]; + [ [ qz_window contentView ] setNeedsDisplay:YES ]; + [ qz_window displayIfNeeded ]; + } +} + static void QZ_VideoQuit (_THIS) { CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken; diff --git a/src/video/quartz/SDL_QuartzWindow.h b/src/video/quartz/SDL_QuartzWindow.h index d19375b74..5798aa170 100644 --- a/src/video/quartz/SDL_QuartzWindow.h +++ b/src/video/quartz/SDL_QuartzWindow.h @@ -47,5 +47,6 @@ typedef unsigned int NSUInteger; /* Subclass of NSView to set cursor rectangle */ @interface SDL_QuartzView : NSView +- (void)drawRect:(NSRect)dirtyRect; - (void)resetCursorRects; @end diff --git a/src/video/quartz/SDL_QuartzWindow.m b/src/video/quartz/SDL_QuartzWindow.m index 375833fb7..425f266ea 100644 --- a/src/video/quartz/SDL_QuartzWindow.m +++ b/src/video/quartz/SDL_QuartzWindow.m @@ -220,6 +220,13 @@ - (void)windowDidResignKey:(NSNotification *)aNotification @implementation SDL_QuartzView +void QZ_UpdateRectsOnDrawRect(/*TODO: NSRect from drawRect*/); + +- (void)drawRect:(NSRect)dirtyRect +{ + QZ_UpdateRectsOnDrawRect(); +} + - (void)resetCursorRects { SDL_Cursor *sdlc = SDL_GetCursor();