github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/app/internal/wm/gl_ios.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 // +build darwin,ios 4 5 package wm 6 7 /* 8 #include <CoreFoundation/CoreFoundation.h> 9 #include <OpenGLES/ES2/gl.h> 10 #include <OpenGLES/ES2/glext.h> 11 12 __attribute__ ((visibility ("hidden"))) int gio_renderbufferStorage(CFTypeRef ctx, CFTypeRef layer, GLenum buffer); 13 __attribute__ ((visibility ("hidden"))) int gio_presentRenderbuffer(CFTypeRef ctx, GLenum buffer); 14 __attribute__ ((visibility ("hidden"))) int gio_makeCurrent(CFTypeRef ctx); 15 __attribute__ ((visibility ("hidden"))) CFTypeRef gio_createContext(void); 16 __attribute__ ((visibility ("hidden"))) CFTypeRef gio_createGLLayer(void); 17 */ 18 import "C" 19 20 import ( 21 "errors" 22 "fmt" 23 24 "github.com/cybriq/giocore/gpu" 25 "github.com/cybriq/giocore/internal/gl" 26 ) 27 28 type context struct { 29 owner *window 30 c *gl.Functions 31 ctx C.CFTypeRef 32 layer C.CFTypeRef 33 init bool 34 frameBuffer gl.Framebuffer 35 colorBuffer, depthBuffer gl.Renderbuffer 36 } 37 38 func init() { 39 layerFactory = func() uintptr { 40 return uintptr(C.gio_createGLLayer()) 41 } 42 } 43 44 func newContext(w *window) (*context, error) { 45 ctx := C.gio_createContext() 46 if ctx == 0 { 47 return nil, fmt.Errorf("failed to create EAGLContext") 48 } 49 api := contextAPI() 50 f, err := gl.NewFunctions(api.Context, api.ES) 51 if err != nil { 52 return nil, err 53 } 54 c := &context{ 55 ctx: ctx, 56 owner: w, 57 layer: C.CFTypeRef(w.contextLayer()), 58 c: f, 59 } 60 return c, nil 61 } 62 63 func contextAPI() gpu.OpenGL { 64 return gpu.OpenGL{} 65 } 66 67 func (c *context) API() gpu.API { 68 return contextAPI() 69 } 70 71 func (c *context) Release() { 72 if c.ctx == 0 { 73 return 74 } 75 C.gio_renderbufferStorage(c.ctx, 0, C.GLenum(gl.RENDERBUFFER)) 76 c.c.DeleteFramebuffer(c.frameBuffer) 77 c.c.DeleteRenderbuffer(c.colorBuffer) 78 c.c.DeleteRenderbuffer(c.depthBuffer) 79 C.gio_makeCurrent(0) 80 C.CFRelease(c.ctx) 81 c.ctx = 0 82 } 83 84 func (c *context) Present() error { 85 if c.layer == 0 { 86 panic("context is not active") 87 } 88 // Discard depth buffer as recommended in 89 // https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html 90 c.c.BindFramebuffer(gl.FRAMEBUFFER, c.frameBuffer) 91 c.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT) 92 c.c.BindRenderbuffer(gl.RENDERBUFFER, c.colorBuffer) 93 if C.gio_presentRenderbuffer(c.ctx, C.GLenum(gl.RENDERBUFFER)) == 0 { 94 return errors.New("presentRenderBuffer failed") 95 } 96 return nil 97 } 98 99 func (c *context) Lock() {} 100 101 func (c *context) Unlock() {} 102 103 func (c *context) Refresh() error { 104 return nil 105 } 106 107 func (c *context) MakeCurrent() error { 108 if C.gio_makeCurrent(c.ctx) == 0 { 109 return errors.New("[EAGLContext setCurrentContext] failed") 110 } 111 if !c.init { 112 c.init = true 113 c.frameBuffer = c.c.CreateFramebuffer() 114 c.colorBuffer = c.c.CreateRenderbuffer() 115 c.depthBuffer = c.c.CreateRenderbuffer() 116 } 117 if !c.owner.isVisible() { 118 // Make sure any in-flight GL commands are complete. 119 c.c.Finish() 120 return nil 121 } 122 currentRB := gl.Renderbuffer{uint(c.c.GetInteger(gl.RENDERBUFFER_BINDING))} 123 c.c.BindRenderbuffer(gl.RENDERBUFFER, c.colorBuffer) 124 if C.gio_renderbufferStorage(c.ctx, c.layer, C.GLenum(gl.RENDERBUFFER)) == 0 { 125 return errors.New("renderbufferStorage failed") 126 } 127 w := c.c.GetRenderbufferParameteri(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH) 128 h := c.c.GetRenderbufferParameteri(gl.RENDERBUFFER, gl.RENDERBUFFER_HEIGHT) 129 c.c.BindRenderbuffer(gl.RENDERBUFFER, c.depthBuffer) 130 c.c.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h) 131 c.c.BindRenderbuffer(gl.RENDERBUFFER, currentRB) 132 c.c.BindFramebuffer(gl.FRAMEBUFFER, c.frameBuffer) 133 c.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, c.colorBuffer) 134 c.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, c.depthBuffer) 135 if st := c.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE { 136 return fmt.Errorf("framebuffer incomplete, status: %#x\n", st) 137 } 138 return nil 139 } 140 141 func (w *window) NewContext() (Context, error) { 142 return newContext(w) 143 }