gl_js.go raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  package wm
   4  
   5  import (
   6  	"errors"
   7  	"syscall/js"
   8  
   9  	"github.com/p9c/p9/pkg/gel/gio/gpu"
  10  	"github.com/p9c/p9/pkg/gel/gio/internal/gl"
  11  	"github.com/p9c/p9/pkg/gel/gio/internal/srgb"
  12  )
  13  
  14  type context struct {
  15  	ctx     js.Value
  16  	cnv     js.Value
  17  	srgbFBO *srgb.FBO
  18  }
  19  
  20  func newContext(w *window) (*context, error) {
  21  	args := map[string]interface{}{
  22  		// Enable low latency rendering.
  23  		// See https://developers.google.com/web/updates/2019/05/desynchronized.
  24  		"desynchronized":        true,
  25  		"preserveDrawingBuffer": true,
  26  	}
  27  	ctx := w.cnv.Call("getContext", "webgl2", args)
  28  	if ctx.IsNull() {
  29  		ctx = w.cnv.Call("getContext", "webgl", args)
  30  	}
  31  	if ctx.IsNull() {
  32  		return nil, errors.New("app: webgl is not supported")
  33  	}
  34  	c := &context{
  35  		ctx: ctx,
  36  		cnv: w.cnv,
  37  	}
  38  	return c, nil
  39  }
  40  
  41  func (c *context) API() gpu.API {
  42  	return gpu.OpenGL{Context: gl.Context(c.ctx)}
  43  }
  44  
  45  func (c *context) Release() {
  46  	if c.srgbFBO != nil {
  47  		c.srgbFBO.Release()
  48  		c.srgbFBO = nil
  49  	}
  50  }
  51  
  52  func (c *context) Present() error {
  53  	if c.srgbFBO != nil {
  54  		c.srgbFBO.Blit()
  55  	}
  56  	if c.srgbFBO != nil {
  57  		c.srgbFBO.AfterPresent()
  58  	}
  59  	if c.ctx.Call("isContextLost").Bool() {
  60  		return errors.New("context lost")
  61  	}
  62  	return nil
  63  }
  64  
  65  func (c *context) Lock() {}
  66  
  67  func (c *context) Unlock() {}
  68  
  69  func (c *context) MakeCurrent() error {
  70  	if c.srgbFBO == nil {
  71  		var err error
  72  		c.srgbFBO, err = srgb.New(gl.Context(c.ctx))
  73  		if err != nil {
  74  			c.Release()
  75  			c.srgbFBO = nil
  76  			return err
  77  		}
  78  	}
  79  	w, h := c.cnv.Get("width").Int(), c.cnv.Get("height").Int()
  80  	if err := c.srgbFBO.Refresh(w, h); err != nil {
  81  		c.Release()
  82  		return err
  83  	}
  84  	return nil
  85  }
  86  
  87  func (w *window) NewContext() (Context, error) {
  88  	return newContext(w)
  89  }
  90