From a1c0693eeb163f015cf2e50e03e2b4f0c85c68f3 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 24 May 2019 14:01:26 +0200 Subject: [PATCH] ui/app: add Lock/Unlock to Context for macOS Without locking, asynchronous OpenGL rendering crashes on macOS. Signed-off-by: Elias Naur --- ui/app/egl.go | 4 ++++ ui/app/gl_ios.go | 4 ++++ ui/app/gl_js.go | 4 ++++ ui/app/gl_macos.go | 13 +++++++++++++ ui/app/gl_macos.h | 2 ++ ui/app/gl_macos.m | 10 ++++++++++ ui/app/internal/gl/gl.go | 2 ++ ui/app/internal/gpu/gpu.go | 2 ++ 8 files changed, 41 insertions(+) diff --git a/ui/app/egl.go b/ui/app/egl.go index 5c8b0dae..cc944b03 100644 --- a/ui/app/egl.go +++ b/ui/app/egl.go @@ -114,6 +114,10 @@ func (c *context) Functions() *gl.Functions { return c.c } +func (c *context) Lock() {} + +func (c *context) Unlock() {} + func (c *context) MakeCurrent() error { w, width, height := c.driver.nativeWindow(int(c.eglCtx.visualID)) win := _EGLNativeWindowType(w) diff --git a/ui/app/gl_ios.go b/ui/app/gl_ios.go index dcf872fd..dc367321 100644 --- a/ui/app/gl_ios.go +++ b/ui/app/gl_ios.go @@ -83,6 +83,10 @@ func (c *context) Present() error { return nil } +func (c *context) Lock() {} + +func (c *context) Unlock() {} + func (c *context) MakeCurrent() error { if C.gio_makeCurrent(c.ctx) == 0 { C.CFRelease(c.ctx) diff --git a/ui/app/gl_js.go b/ui/app/gl_js.go index a2ffa11d..b4b25265 100644 --- a/ui/app/gl_js.go +++ b/ui/app/gl_js.go @@ -62,6 +62,10 @@ func (c *context) Present() error { return nil } +func (c *context) Lock() {} + +func (c *context) Unlock() {} + func (c *context) MakeCurrent() error { if c.srgbFBO == nil { var err error diff --git a/ui/app/gl_macos.go b/ui/app/gl_macos.go index c7348c18..da6a9f41 100644 --- a/ui/app/gl_macos.go +++ b/ui/app/gl_macos.go @@ -44,17 +44,30 @@ func (c *context) Functions() *gl.Functions { } func (c *context) Release() { + c.Lock() + defer c.Unlock() C.gio_clearCurrentContext() C.CFRelease(c.ctx) c.ctx = 0 } func (c *context) Present() error { + // Assume the caller already locked the context. C.glFlush() return nil } +func (c *context) Lock() { + C.gio_lockContext(c.ctx) +} + +func (c *context) Unlock() { + C.gio_unlockContext(c.ctx) +} + func (c *context) MakeCurrent() error { + c.Lock() + defer c.Unlock() C.gio_makeCurrentContext(c.ctx) return nil } diff --git a/ui/app/gl_macos.h b/ui/app/gl_macos.h index 2e516c31..e1dc76d8 100644 --- a/ui/app/gl_macos.h +++ b/ui/app/gl_macos.h @@ -5,3 +5,5 @@ __attribute__ ((visibility ("hidden"))) CFTypeRef gio_contextForView(CFTypeRef v __attribute__ ((visibility ("hidden"))) void gio_makeCurrentContext(CFTypeRef ctx); __attribute__ ((visibility ("hidden"))) void gio_flushContextBuffer(CFTypeRef ctx); __attribute__ ((visibility ("hidden"))) void gio_clearCurrentContext(); +__attribute__ ((visibility ("hidden"))) void gio_lockContext(CFTypeRef ctxRef); +__attribute__ ((visibility ("hidden"))) void gio_unlockContext(CFTypeRef ctxRef); diff --git a/ui/app/gl_macos.m b/ui/app/gl_macos.m index 5eb8d219..e0473bcf 100644 --- a/ui/app/gl_macos.m +++ b/ui/app/gl_macos.m @@ -151,3 +151,13 @@ void gio_makeCurrentContext(CFTypeRef ctxRef) { NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef; return [ctx makeCurrentContext]; } + +void gio_lockContext(CFTypeRef ctxRef) { + NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef; + CGLLockContext([ctx CGLContextObj]); +} + +void gio_unlockContext(CFTypeRef ctxRef) { + NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef; + CGLUnlockContext([ctx CGLContextObj]); +} diff --git a/ui/app/internal/gl/gl.go b/ui/app/internal/gl/gl.go index e86a520e..0a114526 100644 --- a/ui/app/internal/gl/gl.go +++ b/ui/app/internal/gl/gl.go @@ -12,6 +12,8 @@ type Context interface { Present() error MakeCurrent() error Release() + Lock() + Unlock() } const ( diff --git a/ui/app/internal/gpu/gpu.go b/ui/app/internal/gpu/gpu.go index 63d754e7..5266ac1a 100644 --- a/ui/app/internal/gpu/gpu.go +++ b/ui/app/internal/gpu/gpu.go @@ -202,6 +202,7 @@ func (g *GPU) renderLoop(glctx gl.Context) error { case <-g.refresh: g.refreshErr <- glctx.MakeCurrent() case frame := <-g.frames: + glctx.Lock() if frame.collectStats && timers == nil && ctx.caps.EXT_disjoint_timer_query { timers = newTimers(ctx) zopsTimer = timers.newTimer() @@ -253,6 +254,7 @@ func (g *GPU) renderLoop(glctx gl.Context) error { res.summary = fmt.Sprintf("f:%7s zt:%7s st:%7s cov:%7s", ft, zt, st, covt) } res.err = err + glctx.Unlock() g.results <- res case <-g.stop: break loop