github.com/Seikaijyu/gio@v0.0.1/app/gl_macos.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 //go:build darwin && !ios && nometal 4 // +build darwin,!ios,nometal 5 6 package app 7 8 import ( 9 "errors" 10 "runtime" 11 12 "unsafe" 13 14 "github.com/Seikaijyu/gio/gpu" 15 "github.com/Seikaijyu/gio/internal/gl" 16 ) 17 18 /* 19 #cgo CFLAGS: -DGL_SILENCE_DEPRECATION -xobjective-c -fobjc-arc 20 #cgo LDFLAGS: -framework OpenGL 21 22 #include <CoreFoundation/CoreFoundation.h> 23 #include <CoreGraphics/CoreGraphics.h> 24 #include <AppKit/AppKit.h> 25 #include <dlfcn.h> 26 27 __attribute__ ((visibility ("hidden"))) CFTypeRef gio_createGLContext(void); 28 __attribute__ ((visibility ("hidden"))) void gio_setContextView(CFTypeRef ctx, CFTypeRef view); 29 __attribute__ ((visibility ("hidden"))) void gio_makeCurrentContext(CFTypeRef ctx); 30 __attribute__ ((visibility ("hidden"))) void gio_updateContext(CFTypeRef ctx); 31 __attribute__ ((visibility ("hidden"))) void gio_flushContextBuffer(CFTypeRef ctx); 32 __attribute__ ((visibility ("hidden"))) void gio_clearCurrentContext(void); 33 __attribute__ ((visibility ("hidden"))) void gio_lockContext(CFTypeRef ctxRef); 34 __attribute__ ((visibility ("hidden"))) void gio_unlockContext(CFTypeRef ctxRef); 35 36 typedef void (*PFN_glFlush)(void); 37 38 static void glFlush(PFN_glFlush f) { 39 f(); 40 } 41 */ 42 import "C" 43 44 type glContext struct { 45 c *gl.Functions 46 ctx C.CFTypeRef 47 view C.CFTypeRef 48 49 glFlush C.PFN_glFlush 50 } 51 52 func newContext(w *window) (*glContext, error) { 53 clib := C.CString("/System/Library/Frameworks/OpenGL.framework/OpenGL") 54 defer C.free(unsafe.Pointer(clib)) 55 lib, err := C.dlopen(clib, C.RTLD_NOW|C.RTLD_LOCAL) 56 if err != nil { 57 return nil, err 58 } 59 csym := C.CString("glFlush") 60 defer C.free(unsafe.Pointer(csym)) 61 glFlush := C.PFN_glFlush(C.dlsym(lib, csym)) 62 if glFlush == nil { 63 return nil, errors.New("gl: missing symbol glFlush in the OpenGL framework") 64 } 65 view := w.contextView() 66 ctx := C.gio_createGLContext() 67 if ctx == 0 { 68 return nil, errors.New("gl: failed to create NSOpenGLContext") 69 } 70 C.gio_setContextView(ctx, view) 71 c := &glContext{ 72 ctx: ctx, 73 view: view, 74 glFlush: glFlush, 75 } 76 return c, nil 77 } 78 79 func (c *glContext) RenderTarget() (gpu.RenderTarget, error) { 80 return gpu.OpenGLRenderTarget{}, nil 81 } 82 83 func (c *glContext) API() gpu.API { 84 return gpu.OpenGL{} 85 } 86 87 func (c *glContext) Release() { 88 if c.ctx != 0 { 89 C.gio_clearCurrentContext() 90 C.CFRelease(c.ctx) 91 c.ctx = 0 92 } 93 } 94 95 func (c *glContext) Present() error { 96 // Assume the caller already locked the context. 97 C.glFlush(c.glFlush) 98 return nil 99 } 100 101 func (c *glContext) Lock() error { 102 // OpenGL contexts are implicit and thread-local. Lock the OS thread. 103 runtime.LockOSThread() 104 105 C.gio_lockContext(c.ctx) 106 C.gio_makeCurrentContext(c.ctx) 107 return nil 108 } 109 110 func (c *glContext) Unlock() { 111 C.gio_clearCurrentContext() 112 C.gio_unlockContext(c.ctx) 113 } 114 115 func (c *glContext) Refresh() error { 116 c.Lock() 117 defer c.Unlock() 118 C.gio_updateContext(c.ctx) 119 return nil 120 } 121 122 func (w *window) NewContext() (context, error) { 123 return newContext(w) 124 }