gl_macos.go 2.8 KB

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