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 <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-06-12 19:27:48 +02:00
parent 9b5e9ae607
commit 0e592f8bc6
13 changed files with 60 additions and 24 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ import (
// ViewEvent carries the platform specific window handles for // ViewEvent carries the platform specific window handles for
// a Window. // a Window.
// //
// ViewEvent is implemented on Android and macOS. // ViewEvent is implemented for Android, macOS, Windows.
type ViewEvent = wm.ViewEvent type ViewEvent = wm.ViewEvent
// extraArgs contains extra arguments to append to // extraArgs contains extra arguments to append to
+4
View File
@@ -71,6 +71,10 @@ func (c *d3d11Context) Present() error {
return err return err
} }
func (c *d3d11Context) Refresh() error {
return nil
}
func (c *d3d11Context) MakeCurrent() error { func (c *d3d11Context) MakeCurrent() error {
var width, height int var width, height int
c.win.w.Run(func() { c.win.w.Run(func() {
+4
View File
@@ -34,6 +34,10 @@ func (c *context) Release() {
} }
} }
func (c *context) Refresh() error {
return nil
}
func (c *context) MakeCurrent() error { func (c *context) MakeCurrent() error {
c.Context.ReleaseSurface() c.Context.ReleaseSurface()
var ( var (
+4
View File
@@ -48,6 +48,10 @@ func (c *context) Release() {
} }
} }
func (c *context) Refresh() error {
return nil
}
func (c *context) MakeCurrent() error { func (c *context) MakeCurrent() error {
c.Context.ReleaseSurface() c.Context.ReleaseSurface()
if c.eglWin != nil { if c.eglWin != nil {
+4
View File
@@ -34,6 +34,10 @@ func (c *glContext) Release() {
} }
} }
func (c *glContext) Refresh() error {
return nil
}
func (c *glContext) MakeCurrent() error { func (c *glContext) MakeCurrent() error {
c.Context.ReleaseSurface() c.Context.ReleaseSurface()
var ( var (
+4
View File
@@ -31,6 +31,10 @@ func (c *x11Context) Release() {
} }
} }
func (c *x11Context) Refresh() error {
return nil
}
func (c *x11Context) MakeCurrent() error { func (c *x11Context) MakeCurrent() error {
c.Context.ReleaseSurface() c.Context.ReleaseSurface()
win, width, height := c.win.window() win, width, height := c.win.window()
+4
View File
@@ -100,6 +100,10 @@ func (c *context) Lock() {}
func (c *context) Unlock() {} func (c *context) Unlock() {}
func (c *context) Refresh() error {
return nil
}
func (c *context) MakeCurrent() error { func (c *context) MakeCurrent() error {
if C.gio_makeCurrent(c.ctx) == 0 { if C.gio_makeCurrent(c.ctx) == 0 {
return errors.New("[EAGLContext setCurrentContext] failed") return errors.New("[EAGLContext setCurrentContext] failed")
+4
View File
@@ -54,6 +54,10 @@ func (c *context) Lock() {}
func (c *context) Unlock() {} func (c *context) Unlock() {}
func (c *context) Refresh() error {
return nil
}
func (c *context) MakeCurrent() error { func (c *context) MakeCurrent() error {
return nil return nil
} }
+8
View File
@@ -19,6 +19,7 @@ import (
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createGLContext(void); __attribute__ ((visibility ("hidden"))) CFTypeRef gio_createGLContext(void);
__attribute__ ((visibility ("hidden"))) void gio_setContextView(CFTypeRef ctx, CFTypeRef view); __attribute__ ((visibility ("hidden"))) void gio_setContextView(CFTypeRef ctx, CFTypeRef view);
__attribute__ ((visibility ("hidden"))) void gio_makeCurrentContext(CFTypeRef ctx); __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_flushContextBuffer(CFTypeRef ctx);
__attribute__ ((visibility ("hidden"))) void gio_clearCurrentContext(void); __attribute__ ((visibility ("hidden"))) void gio_clearCurrentContext(void);
__attribute__ ((visibility ("hidden"))) void gio_lockContext(CFTypeRef ctxRef); __attribute__ ((visibility ("hidden"))) void gio_lockContext(CFTypeRef ctxRef);
@@ -74,6 +75,13 @@ func (c *context) Unlock() {
C.gio_unlockContext(c.ctx) 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 { func (c *context) MakeCurrent() error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
+9 -20
View File
@@ -8,20 +8,6 @@
#include <OpenGL/OpenGL.h> #include <OpenGL/OpenGL.h>
#include "_cgo_export.h" #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) { CFTypeRef gio_createGLContext(void) {
@autoreleasepool { @autoreleasepool {
NSOpenGLPixelFormatAttribute attr[] = { NSOpenGLPixelFormatAttribute attr[] = {
@@ -36,20 +22,16 @@ CFTypeRef gio_createGLContext(void) {
}; };
NSOpenGLPixelFormat *pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; 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); return CFBridgingRetain(ctx);
} }
} }
void gio_setContextView(CFTypeRef ctxRef, CFTypeRef viewRef) { void gio_setContextView(CFTypeRef ctxRef, CFTypeRef viewRef) {
GioGLContext *ctx = (__bridge GioGLContext *)ctxRef; NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
NSView *view = (__bridge NSView *)viewRef; NSView *view = (__bridge NSView *)viewRef;
[view setWantsBestResolutionOpenGLSurface:YES]; [view setWantsBestResolutionOpenGLSurface:YES];
[ctx setView:view]; [ctx setView:view];
[[NSNotificationCenter defaultCenter] addObserver:ctx
selector:@selector(notifyUpdate:)
name:NSViewGlobalFrameDidChangeNotification
object:view];
} }
void gio_clearCurrentContext(void) { 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) { void gio_makeCurrentContext(CFTypeRef ctxRef) {
@autoreleasepool { @autoreleasepool {
NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef; NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
+3 -1
View File
@@ -6,9 +6,10 @@ package wm
import ( import (
"errors" "errors"
"gioui.org/io/key"
"image/color" "image/color"
"gioui.org/io/key"
"gioui.org/gpu" "gioui.org/gpu"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/io/pointer" "gioui.org/io/pointer"
@@ -69,6 +70,7 @@ type Context interface {
API() gpu.API API() gpu.API
Present() error Present() error
MakeCurrent() error MakeCurrent() error
Refresh() error
Release() Release()
Lock() Lock()
Unlock() Unlock()
+3
View File
@@ -17,6 +17,7 @@ type renderLoop struct {
drawing bool drawing bool
err error err error
ctx wm.Context
frames chan frame frames chan frame
results chan frameResult results chan frameResult
refresh chan struct{} refresh chan struct{}
@@ -38,6 +39,7 @@ type frameResult struct {
func newLoop(ctx wm.Context) (*renderLoop, error) { func newLoop(ctx wm.Context) (*renderLoop, error) {
l := &renderLoop{ l := &renderLoop{
ctx: ctx,
frames: make(chan frame), frames: make(chan frame),
results: make(chan frameResult), results: make(chan frameResult),
refresh: make(chan struct{}), refresh: make(chan struct{}),
@@ -132,6 +134,7 @@ func (l *renderLoop) Summary() string {
} }
func (l *renderLoop) Refresh() { func (l *renderLoop) Refresh() {
l.ctx.Refresh()
if l.err != nil { if l.err != nil {
return return
} }
+8 -2
View File
@@ -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() { func (w *Window) destroyGPU() {
if w.loop != nil { if w.loop != nil {
w.loop.Release() w.loop.Release()
@@ -473,7 +479,7 @@ func (w *Window) run(opts *wm.Options) {
if e2.Stage < system.StageRunning { if e2.Stage < system.StageRunning {
w.destroyGPU() w.destroyGPU()
} else { } else {
w.loop.Refresh() w.refresh()
} }
} }
w.stage = e2.Stage w.stage = e2.Stage
@@ -495,7 +501,7 @@ func (w *Window) run(opts *wm.Options) {
w.out <- e2.FrameEvent w.out <- e2.FrameEvent
if w.loop != nil { if w.loop != nil {
if e2.Sync { if e2.Sync {
w.loop.Refresh() w.refresh()
} }
} }
frame, gotFrame := w.waitFrame() frame, gotFrame := w.waitFrame()