gioui.org@v0.6.1-0.20240506124620-7a9ce51988ce/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  	"gioui.org/gpu"
    15  	"gioui.org/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  }