gl_ios.go raw

   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/p9c/p9/pkg/gel/gio/gpu"
  25  	"github.com/p9c/p9/pkg/gel/gio/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  	c := &context{
  50  		ctx:   ctx,
  51  		owner: w,
  52  		layer: C.CFTypeRef(w.contextLayer()),
  53  		c:     new(gl.Functions),
  54  	}
  55  	return c, nil
  56  }
  57  
  58  func (c *context) API() gpu.API {
  59  	return gpu.OpenGL{}
  60  }
  61  
  62  func (c *context) Release() {
  63  	if c.ctx == 0 {
  64  		return
  65  	}
  66  	C.gio_renderbufferStorage(c.ctx, 0, C.GLenum(gl.RENDERBUFFER))
  67  	c.c.DeleteFramebuffer(c.frameBuffer)
  68  	c.c.DeleteRenderbuffer(c.colorBuffer)
  69  	c.c.DeleteRenderbuffer(c.depthBuffer)
  70  	C.gio_makeCurrent(0)
  71  	C.CFRelease(c.ctx)
  72  	c.ctx = 0
  73  }
  74  
  75  func (c *context) Present() error {
  76  	if c.layer == 0 {
  77  		panic("context is not active")
  78  	}
  79  	// Discard depth buffer as recommended in
  80  	// https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html
  81  	c.c.BindFramebuffer(gl.FRAMEBUFFER, c.frameBuffer)
  82  	c.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT)
  83  	c.c.BindRenderbuffer(gl.RENDERBUFFER, c.colorBuffer)
  84  	if C.gio_presentRenderbuffer(c.ctx, C.GLenum(gl.RENDERBUFFER)) == 0 {
  85  		return errors.New("presentRenderBuffer failed")
  86  	}
  87  	return nil
  88  }
  89  
  90  func (c *context) Lock() {}
  91  
  92  func (c *context) Unlock() {}
  93  
  94  func (c *context) MakeCurrent() error {
  95  	if C.gio_makeCurrent(c.ctx) == 0 {
  96  		C.CFRelease(c.ctx)
  97  		c.ctx = 0
  98  		return errors.New("[EAGLContext setCurrentContext] failed")
  99  	}
 100  	if !c.init {
 101  		c.init = true
 102  		c.frameBuffer = c.c.CreateFramebuffer()
 103  		c.colorBuffer = c.c.CreateRenderbuffer()
 104  		c.depthBuffer = c.c.CreateRenderbuffer()
 105  	}
 106  	if !c.owner.isVisible() {
 107  		// Make sure any in-flight GL commands are complete.
 108  		c.c.Finish()
 109  		return nil
 110  	}
 111  	currentRB := gl.Renderbuffer{uint(c.c.GetInteger(gl.RENDERBUFFER_BINDING))}
 112  	c.c.BindRenderbuffer(gl.RENDERBUFFER, c.colorBuffer)
 113  	if C.gio_renderbufferStorage(c.ctx, c.layer, C.GLenum(gl.RENDERBUFFER)) == 0 {
 114  		return errors.New("renderbufferStorage failed")
 115  	}
 116  	w := c.c.GetRenderbufferParameteri(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH)
 117  	h := c.c.GetRenderbufferParameteri(gl.RENDERBUFFER, gl.RENDERBUFFER_HEIGHT)
 118  	c.c.BindRenderbuffer(gl.RENDERBUFFER, c.depthBuffer)
 119  	c.c.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h)
 120  	c.c.BindRenderbuffer(gl.RENDERBUFFER, currentRB)
 121  	c.c.BindFramebuffer(gl.FRAMEBUFFER, c.frameBuffer)
 122  	c.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, c.colorBuffer)
 123  	c.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, c.depthBuffer)
 124  	if st := c.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
 125  		return fmt.Errorf("framebuffer incomplete, status: %#x\n", st)
 126  	}
 127  	return nil
 128  }
 129  
 130  func (w *window) NewContext() (Context, error) {
 131  	return newContext(w)
 132  }
 133