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  }