Files
gio/app/gl_macos.go
T
Elias Naur f896a72ea1 app,gpu/internal/opengl: move glFlush to macOS context present
A previous change[0] moved all OpenGL function calls to the internal
opengl package, so that Gio can use desktop OpenGL and OpenGL ES (ANGLE)
in the same program without confusing the function pointers.

However the change also moved the glFlush that constitutes a buffer
swap, or present, on macOS. Other platforms don't need the flush, so
this change moves it back to macOS-specific code, in glContext.Present
where it belongs. It also uses dlopen and dlsym to avoid symbol
confusion between Apple's OpenGL framework and ANGLE's libGLESv2.dylib.

The motivation is that we're getting rid of the desktop OpenGL backend
on macOS in favor of Metal, and so should reduce the number of global
special-cases catering to that platform.

[0] https://gioui.org/commit/476d2269a

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-09-15 21:12:29 +02:00

118 lines
2.6 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
//go:build darwin && !ios && nometal
// +build darwin,!ios,nometal
package app
import (
"errors"
"gioui.org/gpu"
"gioui.org/internal/gl"
)
/*
#include <CoreFoundation/CoreFoundation.h>
#include <CoreGraphics/CoreGraphics.h>
#include <AppKit/AppKit.h>
#include <dlfcn.h>
__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);
__attribute__ ((visibility ("hidden"))) void gio_unlockContext(CFTypeRef ctxRef);
typedef void (*PFN_glFlush)(void);
static void glFlush(PFN_glFlush f) {
f();
}
*/
import "C"
import "unsafe"
type glContext struct {
c *gl.Functions
ctx C.CFTypeRef
view C.CFTypeRef
glFlush C.PFN_glFlush
}
func newContext(w *window) (*glContext, error) {
clib := C.CString("/System/Library/Frameworks/OpenGL.framework/OpenGL")
defer C.free(unsafe.Pointer(clib))
lib, err := C.dlopen(clib, C.RTLD_NOW|C.RTLD_LOCAL)
if err != nil {
return nil, err
}
csym := C.CString("glFlush")
defer C.free(unsafe.Pointer(csym))
glFlush := C.PFN_glFlush(C.dlsym(lib, csym))
if glFlush == nil {
return nil, errors.New("gl: missing symbol glFlush in the OpenGL framework")
}
view := w.contextView()
ctx := C.gio_createGLContext()
if ctx == 0 {
return nil, errors.New("gl: failed to create NSOpenGLContext")
}
C.gio_setContextView(ctx, view)
c := &glContext{
ctx: ctx,
view: view,
glFlush: glFlush,
}
return c, nil
}
func (c *glContext) RenderTarget() gpu.RenderTarget {
return gpu.OpenGLRenderTarget{}
}
func (c *glContext) API() gpu.API {
return gpu.OpenGL{}
}
func (c *glContext) Release() {
if c.ctx != 0 {
C.gio_clearCurrentContext()
C.CFRelease(c.ctx)
c.ctx = 0
}
}
func (c *glContext) Present() error {
// Assume the caller already locked the context.
C.glFlush(c.glFlush)
return nil
}
func (c *glContext) Lock() error {
C.gio_lockContext(c.ctx)
C.gio_makeCurrentContext(c.ctx)
return nil
}
func (c *glContext) Unlock() {
C.gio_clearCurrentContext()
C.gio_unlockContext(c.ctx)
}
func (c *glContext) Refresh() error {
c.Lock()
defer c.Unlock()
C.gio_updateContext(c.ctx)
return nil
}
func (w *window) NewContext() (context, error) {
return newContext(w)
}