From 0e592f8bc6b359fcfe7ffbc89df401b601e768f8 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sat, 12 Jun 2021 19:27:48 +0200 Subject: [PATCH] app,app/internal/wm: [macOS] refresh context on display change The NSViewGlobalFrameDidChangeNotification notification is documented to be fired every time [NSOpenGLContext update] needs to be called. However, the notification fails to fire on my setup when a window is moved to a display with a different pixel scale, which leads to incorrectly sized output. This change gets rid of the notification and updates the context before every frame. Signed-off-by: Elias Naur --- app/app.go | 2 +- app/internal/wm/d3d11_windows.go | 4 ++++ app/internal/wm/egl_android.go | 4 ++++ app/internal/wm/egl_wayland.go | 4 ++++ app/internal/wm/egl_windows.go | 4 ++++ app/internal/wm/egl_x11.go | 4 ++++ app/internal/wm/gl_ios.go | 4 ++++ app/internal/wm/gl_js.go | 4 ++++ app/internal/wm/gl_macos.go | 8 ++++++++ app/internal/wm/gl_macos.m | 29 +++++++++-------------------- app/internal/wm/window.go | 4 +++- app/loop.go | 3 +++ app/window.go | 10 ++++++++-- 13 files changed, 60 insertions(+), 24 deletions(-) diff --git a/app/app.go b/app/app.go index 0c840cf7..240b9452 100644 --- a/app/app.go +++ b/app/app.go @@ -12,7 +12,7 @@ import ( // ViewEvent carries the platform specific window handles for // a Window. // -// ViewEvent is implemented on Android and macOS. +// ViewEvent is implemented for Android, macOS, Windows. type ViewEvent = wm.ViewEvent // extraArgs contains extra arguments to append to diff --git a/app/internal/wm/d3d11_windows.go b/app/internal/wm/d3d11_windows.go index 41f5cc5b..2a0003c5 100644 --- a/app/internal/wm/d3d11_windows.go +++ b/app/internal/wm/d3d11_windows.go @@ -71,6 +71,10 @@ func (c *d3d11Context) Present() error { return err } +func (c *d3d11Context) Refresh() error { + return nil +} + func (c *d3d11Context) MakeCurrent() error { var width, height int c.win.w.Run(func() { diff --git a/app/internal/wm/egl_android.go b/app/internal/wm/egl_android.go index 06b97211..69e75a1b 100644 --- a/app/internal/wm/egl_android.go +++ b/app/internal/wm/egl_android.go @@ -34,6 +34,10 @@ func (c *context) Release() { } } +func (c *context) Refresh() error { + return nil +} + func (c *context) MakeCurrent() error { c.Context.ReleaseSurface() var ( diff --git a/app/internal/wm/egl_wayland.go b/app/internal/wm/egl_wayland.go index d309c2a5..f0012865 100644 --- a/app/internal/wm/egl_wayland.go +++ b/app/internal/wm/egl_wayland.go @@ -48,6 +48,10 @@ func (c *context) Release() { } } +func (c *context) Refresh() error { + return nil +} + func (c *context) MakeCurrent() error { c.Context.ReleaseSurface() if c.eglWin != nil { diff --git a/app/internal/wm/egl_windows.go b/app/internal/wm/egl_windows.go index 261934b9..dc2d93b3 100644 --- a/app/internal/wm/egl_windows.go +++ b/app/internal/wm/egl_windows.go @@ -34,6 +34,10 @@ func (c *glContext) Release() { } } +func (c *glContext) Refresh() error { + return nil +} + func (c *glContext) MakeCurrent() error { c.Context.ReleaseSurface() var ( diff --git a/app/internal/wm/egl_x11.go b/app/internal/wm/egl_x11.go index 2757b74b..dc15f149 100644 --- a/app/internal/wm/egl_x11.go +++ b/app/internal/wm/egl_x11.go @@ -31,6 +31,10 @@ func (c *x11Context) Release() { } } +func (c *x11Context) Refresh() error { + return nil +} + func (c *x11Context) MakeCurrent() error { c.Context.ReleaseSurface() win, width, height := c.win.window() diff --git a/app/internal/wm/gl_ios.go b/app/internal/wm/gl_ios.go index 186c7072..65501716 100644 --- a/app/internal/wm/gl_ios.go +++ b/app/internal/wm/gl_ios.go @@ -100,6 +100,10 @@ func (c *context) Lock() {} func (c *context) Unlock() {} +func (c *context) Refresh() error { + return nil +} + func (c *context) MakeCurrent() error { if C.gio_makeCurrent(c.ctx) == 0 { return errors.New("[EAGLContext setCurrentContext] failed") diff --git a/app/internal/wm/gl_js.go b/app/internal/wm/gl_js.go index 1f5a998c..74c21cce 100644 --- a/app/internal/wm/gl_js.go +++ b/app/internal/wm/gl_js.go @@ -54,6 +54,10 @@ func (c *context) Lock() {} func (c *context) Unlock() {} +func (c *context) Refresh() error { + return nil +} + func (c *context) MakeCurrent() error { return nil } diff --git a/app/internal/wm/gl_macos.go b/app/internal/wm/gl_macos.go index e652dd58..7fd49a0a 100644 --- a/app/internal/wm/gl_macos.go +++ b/app/internal/wm/gl_macos.go @@ -19,6 +19,7 @@ import ( __attribute__ ((visibility ("hidden"))) CFTypeRef gio_createGLContext(void); __attribute__ ((visibility ("hidden"))) void gio_setContextView(CFTypeRef ctx, CFTypeRef view); __attribute__ ((visibility ("hidden"))) void gio_makeCurrentContext(CFTypeRef ctx); +__attribute__ ((visibility ("hidden"))) void gio_updateContext(CFTypeRef ctx); __attribute__ ((visibility ("hidden"))) void gio_flushContextBuffer(CFTypeRef ctx); __attribute__ ((visibility ("hidden"))) void gio_clearCurrentContext(void); __attribute__ ((visibility ("hidden"))) void gio_lockContext(CFTypeRef ctxRef); @@ -74,6 +75,13 @@ func (c *context) Unlock() { C.gio_unlockContext(c.ctx) } +func (c *context) Refresh() error { + c.Lock() + defer c.Unlock() + C.gio_updateContext(c.ctx) + return nil +} + func (c *context) MakeCurrent() error { c.Lock() defer c.Unlock() diff --git a/app/internal/wm/gl_macos.m b/app/internal/wm/gl_macos.m index 965f64e6..d59117c9 100644 --- a/app/internal/wm/gl_macos.m +++ b/app/internal/wm/gl_macos.m @@ -8,20 +8,6 @@ #include #include "_cgo_export.h" -@interface GioGLContext : NSOpenGLContext -@end - -@implementation GioGLContext -- (void) notifyUpdate:(NSNotification*)notification { - CGLLockContext([self CGLContextObj]); - [self update]; - CGLUnlockContext([self CGLContextObj]); -} -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} -@end - CFTypeRef gio_createGLContext(void) { @autoreleasepool { NSOpenGLPixelFormatAttribute attr[] = { @@ -36,20 +22,16 @@ CFTypeRef gio_createGLContext(void) { }; NSOpenGLPixelFormat *pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; - GioGLContext *ctx = [[GioGLContext alloc] initWithFormat:pixFormat shareContext: nil]; + NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:pixFormat shareContext: nil]; return CFBridgingRetain(ctx); } } void gio_setContextView(CFTypeRef ctxRef, CFTypeRef viewRef) { - GioGLContext *ctx = (__bridge GioGLContext *)ctxRef; + NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef; NSView *view = (__bridge NSView *)viewRef; [view setWantsBestResolutionOpenGLSurface:YES]; [ctx setView:view]; - [[NSNotificationCenter defaultCenter] addObserver:ctx - selector:@selector(notifyUpdate:) - name:NSViewGlobalFrameDidChangeNotification - object:view]; } void gio_clearCurrentContext(void) { @@ -58,6 +40,13 @@ void gio_clearCurrentContext(void) { } } +void gio_updateContext(CFTypeRef ctxRef) { + @autoreleasepool { + NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef; + [ctx update]; + } +} + void gio_makeCurrentContext(CFTypeRef ctxRef) { @autoreleasepool { NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef; diff --git a/app/internal/wm/window.go b/app/internal/wm/window.go index 7e5b250d..393168b6 100644 --- a/app/internal/wm/window.go +++ b/app/internal/wm/window.go @@ -6,9 +6,10 @@ package wm import ( "errors" - "gioui.org/io/key" "image/color" + "gioui.org/io/key" + "gioui.org/gpu" "gioui.org/io/event" "gioui.org/io/pointer" @@ -69,6 +70,7 @@ type Context interface { API() gpu.API Present() error MakeCurrent() error + Refresh() error Release() Lock() Unlock() diff --git a/app/loop.go b/app/loop.go index b8c31eee..16e2762e 100644 --- a/app/loop.go +++ b/app/loop.go @@ -17,6 +17,7 @@ type renderLoop struct { drawing bool err error + ctx wm.Context frames chan frame results chan frameResult refresh chan struct{} @@ -38,6 +39,7 @@ type frameResult struct { func newLoop(ctx wm.Context) (*renderLoop, error) { l := &renderLoop{ + ctx: ctx, frames: make(chan frame), results: make(chan frameResult), refresh: make(chan struct{}), @@ -132,6 +134,7 @@ func (l *renderLoop) Summary() string { } func (l *renderLoop) Refresh() { + l.ctx.Refresh() if l.err != nil { return } diff --git a/app/window.go b/app/window.go index 51dc5ef8..2804396f 100644 --- a/app/window.go +++ b/app/window.go @@ -414,6 +414,12 @@ func (w *Window) destroy(err error) { } } +func (w *Window) refresh() { + w.driverRun(func(_ wm.Driver) { + w.loop.Refresh() + }) +} + func (w *Window) destroyGPU() { if w.loop != nil { w.loop.Release() @@ -473,7 +479,7 @@ func (w *Window) run(opts *wm.Options) { if e2.Stage < system.StageRunning { w.destroyGPU() } else { - w.loop.Refresh() + w.refresh() } } w.stage = e2.Stage @@ -495,7 +501,7 @@ func (w *Window) run(opts *wm.Options) { w.out <- e2.FrameEvent if w.loop != nil { if e2.Sync { - w.loop.Refresh() + w.refresh() } } frame, gotFrame := w.waitFrame()