SDL: cocoa: Update CVDisplayLink timing when screen changes.

From 7c760f7f79f65cc628fc43db9d507f051475a43f Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Wed, 16 Nov 2022 11:32:08 -0500
Subject: [PATCH] cocoa: Update CVDisplayLink timing when screen changes.

This handles both the window moving to a new display and
changing the current display's refresh rate in System
Preferences

Reference Issue #4918.
---
 src/video/cocoa/SDL_cocoaopengl.h |  1 +
 src/video/cocoa/SDL_cocoaopengl.m |  9 +++++++++
 src/video/cocoa/SDL_cocoawindow.h |  1 +
 src/video/cocoa/SDL_cocoawindow.m | 12 ++++++++++++
 4 files changed, 23 insertions(+)

diff --git a/src/video/cocoa/SDL_cocoaopengl.h b/src/video/cocoa/SDL_cocoaopengl.h
index a483ac08a002..7b900dee63b0 100644
--- a/src/video/cocoa/SDL_cocoaopengl.h
+++ b/src/video/cocoa/SDL_cocoaopengl.h
@@ -53,6 +53,7 @@ struct SDL_GLDriverData
         shareContext:(NSOpenGLContext *)share;
 - (void)scheduleUpdate;
 - (void)updateIfNeeded;
+- (void)movedToNewScreen;
 - (void)setWindow:(SDL_Window *)window;
 - (SDL_Window*)window;
 - (void)explicitUpdate;
diff --git a/src/video/cocoa/SDL_cocoaopengl.m b/src/video/cocoa/SDL_cocoaopengl.m
index af17ae228fa9..607f30716164 100644
--- a/src/video/cocoa/SDL_cocoaopengl.m
+++ b/src/video/cocoa/SDL_cocoaopengl.m
@@ -97,6 +97,13 @@ - (id)initWithFormat:(NSOpenGLPixelFormat *)format
     return self;
 }
 
+- (void)movedToNewScreen
+{
+    if (self->displayLink) {
+        CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(self->displayLink, [self CGLContextObj], [[self pixelFormat] CGLPixelFormatObj]);
+    }
+}
+
 - (void)scheduleUpdate
 {
     SDL_AtomicAdd(&self->dirty, 1);
@@ -483,6 +490,8 @@ - (void)dealloc
         SDL_UnlockMutex(nscontext->swapIntervalMutex);
     }
 
+    /*{ static Uint64 prev = 0; const Uint64 now = SDL_GetTicks64(); const unsigned int diff = (unsigned int) (now - prev); prev = now; printf("GLSWAPBUFFERS TICKS %u\n", diff); }*/
+
     /* on 10.14 ("Mojave") and later, this deadlocks if two contexts in two
        threads try to swap at the same time, so put a mutex around it. */
     SDL_LockMutex(videodata.swaplock);
diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h
index cd76b0cd9dec..18f7d8587d9a 100644
--- a/src/video/cocoa/SDL_cocoawindow.h
+++ b/src/video/cocoa/SDL_cocoawindow.h
@@ -85,6 +85,7 @@ typedef enum
 -(void) windowDidResignKey:(NSNotification *) aNotification;
 -(void) windowDidChangeBackingProperties:(NSNotification *) aNotification;
 -(void) windowDidChangeScreenProfile:(NSNotification *) aNotification;
+-(void) windowDidChangeScreen:(NSNotification *) aNotification;
 -(void) windowWillEnterFullScreen:(NSNotification *) aNotification;
 -(void) windowDidEnterFullScreen:(NSNotification *) aNotification;
 -(void) windowWillExitFullScreen:(NSNotification *) aNotification;
diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m
index eea7f981a662..05cdcbcbd41e 100644
--- a/src/video/cocoa/SDL_cocoawindow.m
+++ b/src/video/cocoa/SDL_cocoawindow.m
@@ -500,6 +500,7 @@ - (void)listen:(SDL_WindowData *)data
         [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
         [center addObserver:self selector:@selector(windowDidChangeBackingProperties:) name:NSWindowDidChangeBackingPropertiesNotification object:window];
         [center addObserver:self selector:@selector(windowDidChangeScreenProfile:) name:NSWindowDidChangeScreenProfileNotification object:window];
+        [center addObserver:self selector:@selector(windowDidChangeScreen:) name:NSWindowDidChangeScreenNotification object:window];
         [center addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window];
         [center addObserver:self selector:@selector(windowDidEnterFullScreen:) name:NSWindowDidEnterFullScreenNotification object:window];
         [center addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window];
@@ -632,6 +633,7 @@ - (void)close
         [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
         [center removeObserver:self name:NSWindowDidChangeBackingPropertiesNotification object:window];
         [center removeObserver:self name:NSWindowDidChangeScreenProfileNotification object:window];
+        [center removeObserver:self name:NSWindowDidChangeScreenNotification object:window];
         [center removeObserver:self name:NSWindowWillEnterFullScreenNotification object:window];
         [center removeObserver:self name:NSWindowDidEnterFullScreenNotification object:window];
         [center removeObserver:self name:NSWindowWillExitFullScreenNotification object:window];
@@ -920,6 +922,16 @@ - (void)windowDidChangeScreenProfile:(NSNotification *)aNotification
     SDL_SendWindowEvent(_data.window, SDL_WINDOWEVENT_ICCPROF_CHANGED, 0, 0);
 }
 
+- (void)windowDidChangeScreen:(NSNotification *)aNotification
+{
+    /*printf("WINDOWDIDCHANGESCREEN\n");*/
+    if (_data && _data.nscontexts) {
+        for (SDLOpenGLContext *context in _data.nscontexts) {
+            [context movedToNewScreen];
+        }
+    }
+}
+
 - (void)windowWillEnterFullScreen:(NSNotification *)aNotification
 {
     SDL_Window *window = _data.window;