github.com/utopiagio/gio@v0.0.8/app/gl_ios.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 /* 9 @import UIKit; 10 11 #include <CoreFoundation/CoreFoundation.h> 12 #include <OpenGLES/ES2/gl.h> 13 #include <OpenGLES/ES2/glext.h> 14 15 __attribute__ ((visibility ("hidden"))) int gio_renderbufferStorage(CFTypeRef ctx, CFTypeRef layer, GLenum buffer); 16 __attribute__ ((visibility ("hidden"))) int gio_presentRenderbuffer(CFTypeRef ctx, GLenum buffer); 17 __attribute__ ((visibility ("hidden"))) int gio_makeCurrent(CFTypeRef ctx); 18 __attribute__ ((visibility ("hidden"))) CFTypeRef gio_createContext(void); 19 __attribute__ ((visibility ("hidden"))) CFTypeRef gio_createGLLayer(void); 20 21 static CFTypeRef getViewLayer(CFTypeRef viewRef) { 22 @autoreleasepool { 23 UIView *view = (__bridge UIView *)viewRef; 24 return CFBridgingRetain(view.layer); 25 } 26 } 27 28 */ 29 import "C" 30 31 import ( 32 "errors" 33 "fmt" 34 "runtime" 35 36 "github.com/utopiagio/gio/gpu" 37 "github.com/utopiagio/gio/internal/gl" 38 ) 39 40 type context struct { 41 owner *window 42 c *gl.Functions 43 ctx C.CFTypeRef 44 layer C.CFTypeRef 45 init bool 46 frameBuffer gl.Framebuffer 47 colorBuffer gl.Renderbuffer 48 } 49 50 func newContext(w *window) (*context, error) { 51 ctx := C.gio_createContext() 52 if ctx == 0 { 53 return nil, fmt.Errorf("failed to create EAGLContext") 54 } 55 api := contextAPI() 56 f, err := gl.NewFunctions(api.Context, api.ES) 57 if err != nil { 58 return nil, err 59 } 60 c := &context{ 61 ctx: ctx, 62 owner: w, 63 layer: C.getViewLayer(w.contextView()), 64 c: f, 65 } 66 return c, nil 67 } 68 69 func contextAPI() gpu.OpenGL { 70 return gpu.OpenGL{} 71 } 72 73 func (c *context) RenderTarget() gpu.RenderTarget { 74 return gpu.OpenGLRenderTarget(c.frameBuffer) 75 } 76 77 func (c *context) API() gpu.API { 78 return contextAPI() 79 } 80 81 func (c *context) Release() { 82 if c.ctx == 0 { 83 return 84 } 85 C.gio_renderbufferStorage(c.ctx, 0, C.GLenum(gl.RENDERBUFFER)) 86 c.c.DeleteFramebuffer(c.frameBuffer) 87 c.c.DeleteRenderbuffer(c.colorBuffer) 88 C.gio_makeCurrent(0) 89 C.CFRelease(c.ctx) 90 c.ctx = 0 91 } 92 93 func (c *context) Present() error { 94 if c.layer == 0 { 95 panic("context is not active") 96 } 97 c.c.BindRenderbuffer(gl.RENDERBUFFER, c.colorBuffer) 98 if C.gio_presentRenderbuffer(c.ctx, C.GLenum(gl.RENDERBUFFER)) == 0 { 99 return errors.New("presentRenderBuffer failed") 100 } 101 return nil 102 } 103 104 func (c *context) Lock() error { 105 // OpenGL contexts are implicit and thread-local. Lock the OS thread. 106 runtime.LockOSThread() 107 108 if C.gio_makeCurrent(c.ctx) == 0 { 109 return errors.New("[EAGLContext setCurrentContext] failed") 110 } 111 return nil 112 } 113 114 func (c *context) Unlock() { 115 C.gio_makeCurrent(0) 116 } 117 118 func (c *context) Refresh() error { 119 if C.gio_makeCurrent(c.ctx) == 0 { 120 return errors.New("[EAGLContext setCurrentContext] failed") 121 } 122 if !c.init { 123 c.init = true 124 c.frameBuffer = c.c.CreateFramebuffer() 125 c.colorBuffer = c.c.CreateRenderbuffer() 126 } 127 if !c.owner.visible { 128 // Make sure any in-flight GL commands are complete. 129 c.c.Finish() 130 return nil 131 } 132 currentRB := gl.Renderbuffer{uint(c.c.GetInteger(gl.RENDERBUFFER_BINDING))} 133 c.c.BindRenderbuffer(gl.RENDERBUFFER, c.colorBuffer) 134 if C.gio_renderbufferStorage(c.ctx, c.layer, C.GLenum(gl.RENDERBUFFER)) == 0 { 135 return errors.New("renderbufferStorage failed") 136 } 137 c.c.BindRenderbuffer(gl.RENDERBUFFER, currentRB) 138 c.c.BindFramebuffer(gl.FRAMEBUFFER, c.frameBuffer) 139 c.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, c.colorBuffer) 140 if st := c.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE { 141 return fmt.Errorf("framebuffer incomplete, status: %#x\n", st) 142 } 143 return nil 144 } 145 146 func (w *window) NewContext() (Context, error) { 147 return newContext(w) 148 }