mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-04 00:45:35 +00:00
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:
+1
-1
@@ -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
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user