github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/gpu/internal/opengl/opengl.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package opengl
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  	"image"
     9  	"strings"
    10  	"time"
    11  	"unsafe"
    12  
    13  	"github.com/cybriq/giocore/gpu/internal/driver"
    14  	"github.com/cybriq/giocore/internal/gl"
    15  )
    16  
    17  // Backend implements driver.Device.
    18  type Backend struct {
    19  	funcs *gl.Functions
    20  
    21  	clear      bool
    22  	glstate    glState
    23  	state      state
    24  	savedState glState
    25  
    26  	glver [2]int
    27  	gles  bool
    28  	ubo   bool
    29  	feats driver.Caps
    30  	// floatTriple holds the settings for floating point
    31  	// textures.
    32  	floatTriple textureTriple
    33  	// Single channel alpha textures.
    34  	alphaTriple textureTriple
    35  	srgbaTriple textureTriple
    36  
    37  	sRGBFBO *SRGBFBO
    38  
    39  	// vertArray is bound during a frame. We don't need it, but
    40  	// core desktop OpenGL profile 3.3 requires some array bound.
    41  	vertArray gl.VertexArray
    42  }
    43  
    44  // State tracking.
    45  type glState struct {
    46  	drawFBO     gl.Framebuffer
    47  	readFBO     gl.Framebuffer
    48  	renderBuf   gl.Renderbuffer
    49  	vertAttribs [5]struct {
    50  		obj        gl.Buffer
    51  		enabled    bool
    52  		size       int
    53  		typ        gl.Enum
    54  		normalized bool
    55  		stride     int
    56  		offset     uintptr
    57  	}
    58  	prog     gl.Program
    59  	texUnits struct {
    60  		active gl.Enum
    61  		binds  [2]gl.Texture
    62  	}
    63  	arrayBuf  gl.Buffer
    64  	elemBuf   gl.Buffer
    65  	uniBuf    gl.Buffer
    66  	uniBufs   [2]gl.Buffer
    67  	storeBuf  gl.Buffer
    68  	storeBufs [4]gl.Buffer
    69  	vertArray gl.VertexArray
    70  	depthMask bool
    71  	depthFunc gl.Enum
    72  	srgb      bool
    73  	blend     struct {
    74  		enable         bool
    75  		srcRGB, dstRGB gl.Enum
    76  		srcA, dstA     gl.Enum
    77  	}
    78  	depthTest  bool
    79  	clearColor [4]float32
    80  	clearDepth float32
    81  	viewport   [4]int
    82  }
    83  
    84  type state struct {
    85  	prog   *gpuProgram
    86  	layout *gpuInputLayout
    87  	buffer bufferBinding
    88  }
    89  
    90  type bufferBinding struct {
    91  	obj    gl.Buffer
    92  	offset int
    93  	stride int
    94  }
    95  
    96  type gpuTimer struct {
    97  	funcs *gl.Functions
    98  	obj   gl.Query
    99  }
   100  
   101  type gpuTexture struct {
   102  	backend *Backend
   103  	obj     gl.Texture
   104  	triple  textureTriple
   105  	width   int
   106  	height  int
   107  }
   108  
   109  type gpuFramebuffer struct {
   110  	backend  *Backend
   111  	obj      gl.Framebuffer
   112  	hasDepth bool
   113  	depthBuf gl.Renderbuffer
   114  	foreign  bool
   115  }
   116  
   117  type gpuBuffer struct {
   118  	backend   *Backend
   119  	hasBuffer bool
   120  	obj       gl.Buffer
   121  	typ       driver.BufferBinding
   122  	size      int
   123  	immutable bool
   124  	version   int
   125  	// For emulation of uniform buffers.
   126  	data []byte
   127  }
   128  
   129  type gpuProgram struct {
   130  	backend      *Backend
   131  	obj          gl.Program
   132  	vertUniforms uniformsTracker
   133  	fragUniforms uniformsTracker
   134  	storage      [storageBindings]*gpuBuffer
   135  }
   136  
   137  type uniformsTracker struct {
   138  	locs    []uniformLocation
   139  	size    int
   140  	buf     *gpuBuffer
   141  	version int
   142  }
   143  
   144  type uniformLocation struct {
   145  	uniform gl.Uniform
   146  	offset  int
   147  	typ     driver.DataType
   148  	size    int
   149  }
   150  
   151  type gpuInputLayout struct {
   152  	inputs []driver.InputLocation
   153  	layout []driver.InputDesc
   154  }
   155  
   156  // textureTriple holds the type settings for
   157  // a TexImage2D call.
   158  type textureTriple struct {
   159  	internalFormat gl.Enum
   160  	format         gl.Enum
   161  	typ            gl.Enum
   162  }
   163  
   164  const (
   165  	storageBindings = 32
   166  )
   167  
   168  func init() {
   169  	driver.NewOpenGLDevice = newOpenGLDevice
   170  }
   171  
   172  func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) {
   173  	f, err := gl.NewFunctions(api.Context, api.ES)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	exts := strings.Split(f.GetString(gl.EXTENSIONS), " ")
   178  	glVer := f.GetString(gl.VERSION)
   179  	ver, gles, err := gl.ParseGLVersion(glVer)
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  	floatTriple, ffboErr := floatTripleFor(f, ver, exts)
   184  	srgbaTriple, err := srgbaTripleFor(ver, exts)
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  	gles30 := gles && ver[0] >= 3
   189  	gles31 := gles && (ver[0] > 3 || (ver[0] == 3 && ver[1] >= 1))
   190  	gl40 := !gles && ver[0] >= 4
   191  	b := &Backend{
   192  		glver:       ver,
   193  		gles:        gles,
   194  		ubo:         gles30 || gl40,
   195  		funcs:       f,
   196  		floatTriple: floatTriple,
   197  		alphaTriple: alphaTripleFor(ver),
   198  		srgbaTriple: srgbaTriple,
   199  	}
   200  	b.feats.BottomLeftOrigin = true
   201  	if ffboErr == nil {
   202  		b.feats.Features |= driver.FeatureFloatRenderTargets
   203  	}
   204  	if gles31 {
   205  		b.feats.Features |= driver.FeatureCompute
   206  	}
   207  	if hasExtension(exts, "GL_EXT_disjoint_timer_query_webgl2") || hasExtension(exts, "GL_EXT_disjoint_timer_query") {
   208  		b.feats.Features |= driver.FeatureTimers
   209  	}
   210  	b.feats.MaxTextureSize = f.GetInteger(gl.MAX_TEXTURE_SIZE)
   211  	return b, nil
   212  }
   213  
   214  func (b *Backend) BeginFrame(clear bool, viewport image.Point) driver.Framebuffer {
   215  	b.clear = clear
   216  	b.glstate = b.queryState()
   217  	b.savedState = b.glstate
   218  	b.state = state{}
   219  	renderFBO := b.glstate.drawFBO
   220  	if b.gles {
   221  		// If the output framebuffer is not in the sRGB colorspace already, emulate it.
   222  		var fbEncoding int
   223  		if !renderFBO.Valid() {
   224  			fbEncoding = b.funcs.GetFramebufferAttachmentParameteri(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)
   225  		} else {
   226  			fbEncoding = b.funcs.GetFramebufferAttachmentParameteri(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)
   227  		}
   228  		if fbEncoding == gl.LINEAR && viewport != (image.Point{}) {
   229  			if b.sRGBFBO == nil {
   230  				sfbo, err := NewSRGBFBO(b.funcs, &b.glstate)
   231  				if err != nil {
   232  					panic(err)
   233  				}
   234  				b.sRGBFBO = sfbo
   235  			}
   236  			if err := b.sRGBFBO.Refresh(viewport); err != nil {
   237  				panic(err)
   238  			}
   239  			renderFBO = b.sRGBFBO.Framebuffer()
   240  		}
   241  	} else {
   242  		b.glstate.set(b.funcs, gl.FRAMEBUFFER_SRGB, true)
   243  		if !b.vertArray.Valid() {
   244  			b.vertArray = b.funcs.CreateVertexArray()
   245  		}
   246  		b.glstate.bindVertexArray(b.funcs, b.vertArray)
   247  	}
   248  	b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, renderFBO)
   249  	if b.sRGBFBO != nil && !clear {
   250  		b.Clear(0, 0, 0, 0)
   251  	}
   252  	return &gpuFramebuffer{backend: b, obj: renderFBO, foreign: true}
   253  }
   254  
   255  func (b *Backend) EndFrame() {
   256  	if b.sRGBFBO != nil {
   257  		b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, b.savedState.drawFBO)
   258  		if b.clear {
   259  			b.SetBlend(false)
   260  		} else {
   261  			b.BlendFunc(driver.BlendFactorOne, driver.BlendFactorOneMinusSrcAlpha)
   262  			b.SetBlend(true)
   263  		}
   264  		b.sRGBFBO.Blit()
   265  	}
   266  	b.restoreState(b.savedState)
   267  	// For single-buffered framebuffers such as on macOS.
   268  	b.funcs.Flush()
   269  }
   270  
   271  func (b *Backend) queryState() glState {
   272  	s := glState{
   273  		prog:       gl.Program(b.funcs.GetBinding(gl.CURRENT_PROGRAM)),
   274  		arrayBuf:   gl.Buffer(b.funcs.GetBinding(gl.ARRAY_BUFFER_BINDING)),
   275  		elemBuf:    gl.Buffer(b.funcs.GetBinding(gl.ELEMENT_ARRAY_BUFFER_BINDING)),
   276  		drawFBO:    gl.Framebuffer(b.funcs.GetBinding(gl.FRAMEBUFFER_BINDING)),
   277  		depthMask:  b.funcs.GetInteger(gl.DEPTH_WRITEMASK) != gl.FALSE,
   278  		depthTest:  b.funcs.IsEnabled(gl.DEPTH_TEST),
   279  		depthFunc:  gl.Enum(b.funcs.GetInteger(gl.DEPTH_FUNC)),
   280  		clearDepth: b.funcs.GetFloat(gl.DEPTH_CLEAR_VALUE),
   281  		clearColor: b.funcs.GetFloat4(gl.COLOR_CLEAR_VALUE),
   282  		viewport:   b.funcs.GetInteger4(gl.VIEWPORT),
   283  	}
   284  	s.blend.enable = b.funcs.IsEnabled(gl.BLEND)
   285  	s.blend.srcRGB = gl.Enum(b.funcs.GetInteger(gl.BLEND_SRC_RGB))
   286  	s.blend.dstRGB = gl.Enum(b.funcs.GetInteger(gl.BLEND_DST_RGB))
   287  	s.blend.srcA = gl.Enum(b.funcs.GetInteger(gl.BLEND_SRC_ALPHA))
   288  	s.blend.dstA = gl.Enum(b.funcs.GetInteger(gl.BLEND_DST_ALPHA))
   289  	s.texUnits.active = gl.Enum(b.funcs.GetInteger(gl.ACTIVE_TEXTURE))
   290  	if !b.gles {
   291  		s.srgb = b.funcs.IsEnabled(gl.FRAMEBUFFER_SRGB)
   292  	}
   293  	if !b.gles || b.glver[0] >= 3 {
   294  		s.vertArray = gl.VertexArray(b.funcs.GetBinding(gl.VERTEX_ARRAY_BINDING))
   295  		s.readFBO = gl.Framebuffer(b.funcs.GetBinding(gl.READ_FRAMEBUFFER_BINDING))
   296  		s.uniBuf = gl.Buffer(b.funcs.GetBinding(gl.UNIFORM_BUFFER_BINDING))
   297  		for i := range s.uniBufs {
   298  			s.uniBufs[i] = gl.Buffer(b.funcs.GetBindingi(gl.UNIFORM_BUFFER_BINDING, i))
   299  		}
   300  	}
   301  	if b.gles && (b.glver[0] > 3 || (b.glver[0] == 3 && b.glver[1] >= 1)) {
   302  		s.storeBuf = gl.Buffer(b.funcs.GetBinding(gl.SHADER_STORAGE_BUFFER_BINDING))
   303  		for i := range s.storeBufs {
   304  			s.storeBufs[i] = gl.Buffer(b.funcs.GetBindingi(gl.SHADER_STORAGE_BUFFER_BINDING, i))
   305  		}
   306  	}
   307  	for i := range s.texUnits.binds {
   308  		s.activeTexture(b.funcs, gl.TEXTURE0+gl.Enum(i))
   309  		s.texUnits.binds[i] = gl.Texture(b.funcs.GetBinding(gl.TEXTURE_BINDING_2D))
   310  	}
   311  	for i := range s.vertAttribs {
   312  		a := &s.vertAttribs[i]
   313  		a.enabled = b.funcs.GetVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_ENABLED) != gl.FALSE
   314  		a.obj = gl.Buffer(b.funcs.GetVertexAttribBinding(i, gl.VERTEX_ATTRIB_ARRAY_ENABLED))
   315  		a.size = b.funcs.GetVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_SIZE)
   316  		a.typ = gl.Enum(b.funcs.GetVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_TYPE))
   317  		a.normalized = b.funcs.GetVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED) != gl.FALSE
   318  		a.stride = b.funcs.GetVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_STRIDE)
   319  		a.offset = b.funcs.GetVertexAttribPointer(i, gl.VERTEX_ATTRIB_ARRAY_POINTER)
   320  	}
   321  	return s
   322  }
   323  
   324  func (b *Backend) restoreState(dst glState) {
   325  	src := b.glstate
   326  	f := b.funcs
   327  	for i, unit := range dst.texUnits.binds {
   328  		src.bindTexture(f, i, unit)
   329  	}
   330  	src.activeTexture(f, dst.texUnits.active)
   331  	src.bindFramebuffer(f, gl.FRAMEBUFFER, dst.drawFBO)
   332  	src.bindFramebuffer(f, gl.READ_FRAMEBUFFER, dst.readFBO)
   333  	src.set(f, gl.BLEND, dst.blend.enable)
   334  	bf := dst.blend
   335  	src.setBlendFuncSeparate(f, bf.srcRGB, bf.dstRGB, bf.srcA, bf.dstA)
   336  	src.set(f, gl.DEPTH_TEST, dst.depthTest)
   337  	src.setDepthFunc(f, dst.depthFunc)
   338  	src.set(f, gl.FRAMEBUFFER_SRGB, dst.srgb)
   339  	src.bindVertexArray(f, dst.vertArray)
   340  	src.useProgram(f, dst.prog)
   341  	src.bindBuffer(f, gl.ELEMENT_ARRAY_BUFFER, dst.elemBuf)
   342  	for i, b := range dst.uniBufs {
   343  		src.bindBufferBase(f, gl.UNIFORM_BUFFER, i, b)
   344  	}
   345  	src.bindBuffer(f, gl.UNIFORM_BUFFER, dst.uniBuf)
   346  	for i, b := range dst.storeBufs {
   347  		src.bindBufferBase(f, gl.SHADER_STORAGE_BUFFER, i, b)
   348  	}
   349  	src.bindBuffer(f, gl.SHADER_STORAGE_BUFFER, dst.storeBuf)
   350  	src.setDepthMask(f, dst.depthMask)
   351  	src.setClearDepth(f, dst.clearDepth)
   352  	col := dst.clearColor
   353  	src.setClearColor(f, col[0], col[1], col[2], col[3])
   354  	for i, attr := range dst.vertAttribs {
   355  		src.setVertexAttribArray(f, i, attr.enabled)
   356  		src.vertexAttribPointer(f, attr.obj, i, attr.size, attr.typ, attr.normalized, attr.stride, int(attr.offset))
   357  	}
   358  	src.bindBuffer(f, gl.ARRAY_BUFFER, dst.arrayBuf)
   359  	v := dst.viewport
   360  	src.setViewport(f, v[0], v[1], v[2], v[3])
   361  }
   362  
   363  func (s *glState) setVertexAttribArray(f *gl.Functions, idx int, enabled bool) {
   364  	a := &s.vertAttribs[idx]
   365  	if enabled != a.enabled {
   366  		if enabled {
   367  			f.EnableVertexAttribArray(gl.Attrib(idx))
   368  		} else {
   369  			f.DisableVertexAttribArray(gl.Attrib(idx))
   370  		}
   371  		a.enabled = enabled
   372  	}
   373  }
   374  
   375  func (s *glState) vertexAttribPointer(f *gl.Functions, buf gl.Buffer, idx, size int, typ gl.Enum, normalized bool, stride, offset int) {
   376  	s.bindBuffer(f, gl.ARRAY_BUFFER, buf)
   377  	a := &s.vertAttribs[idx]
   378  	a.obj = buf
   379  	a.size = size
   380  	a.typ = typ
   381  	a.normalized = normalized
   382  	a.stride = stride
   383  	a.offset = uintptr(offset)
   384  	f.VertexAttribPointer(gl.Attrib(idx), a.size, a.typ, a.normalized, a.stride, int(a.offset))
   385  }
   386  
   387  func (s *glState) activeTexture(f *gl.Functions, unit gl.Enum) {
   388  	if unit != s.texUnits.active {
   389  		f.ActiveTexture(unit)
   390  		s.texUnits.active = unit
   391  	}
   392  }
   393  
   394  func (s *glState) bindRenderbuffer(f *gl.Functions, target gl.Enum, r gl.Renderbuffer) {
   395  	if !r.Equal(s.renderBuf) {
   396  		f.BindRenderbuffer(gl.RENDERBUFFER, r)
   397  		s.renderBuf = r
   398  	}
   399  }
   400  
   401  func (s *glState) bindTexture(f *gl.Functions, unit int, t gl.Texture) {
   402  	s.activeTexture(f, gl.TEXTURE0+gl.Enum(unit))
   403  	if !t.Equal(s.texUnits.binds[unit]) {
   404  		f.BindTexture(gl.TEXTURE_2D, t)
   405  		s.texUnits.binds[unit] = t
   406  	}
   407  }
   408  
   409  func (s *glState) bindVertexArray(f *gl.Functions, a gl.VertexArray) {
   410  	if !a.Equal(s.vertArray) {
   411  		f.BindVertexArray(a)
   412  		s.vertArray = a
   413  	}
   414  }
   415  
   416  func (s *glState) deleteRenderbuffer(f *gl.Functions, r gl.Renderbuffer) {
   417  	f.DeleteRenderbuffer(r)
   418  	if r.Equal(s.renderBuf) {
   419  		s.renderBuf = gl.Renderbuffer{}
   420  	}
   421  }
   422  
   423  func (s *glState) deleteFramebuffer(f *gl.Functions, fbo gl.Framebuffer) {
   424  	f.DeleteFramebuffer(fbo)
   425  	if fbo.Equal(s.drawFBO) {
   426  		s.drawFBO = gl.Framebuffer{}
   427  	}
   428  	if fbo.Equal(s.readFBO) {
   429  		s.readFBO = gl.Framebuffer{}
   430  	}
   431  }
   432  
   433  func (s *glState) deleteBuffer(f *gl.Functions, b gl.Buffer) {
   434  	f.DeleteBuffer(b)
   435  	if b.Equal(s.arrayBuf) {
   436  		s.arrayBuf = gl.Buffer{}
   437  	}
   438  	if b.Equal(s.elemBuf) {
   439  		s.elemBuf = gl.Buffer{}
   440  	}
   441  	if b.Equal(s.uniBuf) {
   442  		s.uniBuf = gl.Buffer{}
   443  	}
   444  	if b.Equal(s.storeBuf) {
   445  		s.uniBuf = gl.Buffer{}
   446  	}
   447  	for i, b2 := range s.storeBufs {
   448  		if b.Equal(b2) {
   449  			s.storeBufs[i] = gl.Buffer{}
   450  		}
   451  	}
   452  	for i, b2 := range s.uniBufs {
   453  		if b.Equal(b2) {
   454  			s.uniBufs[i] = gl.Buffer{}
   455  		}
   456  	}
   457  }
   458  
   459  func (s *glState) deleteProgram(f *gl.Functions, p gl.Program) {
   460  	f.DeleteProgram(p)
   461  	if p.Equal(s.prog) {
   462  		s.prog = gl.Program{}
   463  	}
   464  }
   465  
   466  func (s *glState) deleteVertexArray(f *gl.Functions, a gl.VertexArray) {
   467  	f.DeleteVertexArray(a)
   468  	if a.Equal(s.vertArray) {
   469  		s.vertArray = gl.VertexArray{}
   470  	}
   471  }
   472  
   473  func (s *glState) deleteTexture(f *gl.Functions, t gl.Texture) {
   474  	f.DeleteTexture(t)
   475  	binds := &s.texUnits.binds
   476  	for i, obj := range binds {
   477  		if t.Equal(obj) {
   478  			binds[i] = gl.Texture{}
   479  		}
   480  	}
   481  }
   482  
   483  func (s *glState) useProgram(f *gl.Functions, p gl.Program) {
   484  	if !p.Equal(s.prog) {
   485  		f.UseProgram(p)
   486  		s.prog = p
   487  	}
   488  }
   489  
   490  func (s *glState) bindFramebuffer(f *gl.Functions, target gl.Enum, fbo gl.Framebuffer) {
   491  	switch target {
   492  	case gl.FRAMEBUFFER:
   493  		if fbo.Equal(s.drawFBO) && fbo.Equal(s.readFBO) {
   494  			return
   495  		}
   496  		s.drawFBO = fbo
   497  		s.readFBO = fbo
   498  	case gl.READ_FRAMEBUFFER:
   499  		if fbo.Equal(s.readFBO) {
   500  			return
   501  		}
   502  		s.readFBO = fbo
   503  	case gl.DRAW_FRAMEBUFFER:
   504  		if fbo.Equal(s.drawFBO) {
   505  			return
   506  		}
   507  		s.drawFBO = fbo
   508  	default:
   509  		panic("unknown target")
   510  	}
   511  	f.BindFramebuffer(target, fbo)
   512  }
   513  
   514  func (s *glState) bindBufferBase(f *gl.Functions, target gl.Enum, idx int, buf gl.Buffer) {
   515  	switch target {
   516  	case gl.UNIFORM_BUFFER:
   517  		if buf.Equal(s.uniBuf) && buf.Equal(s.uniBufs[idx]) {
   518  			return
   519  		}
   520  		s.uniBuf = buf
   521  		s.uniBufs[idx] = buf
   522  	case gl.SHADER_STORAGE_BUFFER:
   523  		if buf.Equal(s.storeBuf) && buf.Equal(s.storeBufs[idx]) {
   524  			return
   525  		}
   526  		s.storeBuf = buf
   527  		s.storeBufs[idx] = buf
   528  	default:
   529  		panic("unknown buffer target")
   530  	}
   531  	f.BindBufferBase(target, idx, buf)
   532  }
   533  
   534  func (s *glState) bindBuffer(f *gl.Functions, target gl.Enum, buf gl.Buffer) {
   535  	switch target {
   536  	case gl.ARRAY_BUFFER:
   537  		if buf.Equal(s.arrayBuf) {
   538  			return
   539  		}
   540  		s.arrayBuf = buf
   541  	case gl.ELEMENT_ARRAY_BUFFER:
   542  		if buf.Equal(s.elemBuf) {
   543  			return
   544  		}
   545  		s.elemBuf = buf
   546  	case gl.UNIFORM_BUFFER:
   547  		if buf.Equal(s.uniBuf) {
   548  			return
   549  		}
   550  		s.uniBuf = buf
   551  	case gl.SHADER_STORAGE_BUFFER:
   552  		if buf.Equal(s.storeBuf) {
   553  			return
   554  		}
   555  		s.storeBuf = buf
   556  	default:
   557  		panic("unknown buffer target")
   558  	}
   559  	f.BindBuffer(target, buf)
   560  }
   561  
   562  func (s *glState) setClearDepth(f *gl.Functions, d float32) {
   563  	if d != s.clearDepth {
   564  		f.ClearDepthf(d)
   565  		s.clearDepth = d
   566  	}
   567  }
   568  
   569  func (s *glState) setClearColor(f *gl.Functions, r, g, b, a float32) {
   570  	col := [4]float32{r, g, b, a}
   571  	if col != s.clearColor {
   572  		f.ClearColor(r, g, b, a)
   573  		s.clearColor = col
   574  	}
   575  }
   576  
   577  func (s *glState) setViewport(f *gl.Functions, x, y, width, height int) {
   578  	view := [4]int{x, y, width, height}
   579  	if view != s.viewport {
   580  		f.Viewport(x, y, width, height)
   581  		s.viewport = view
   582  	}
   583  }
   584  
   585  func (s *glState) setDepthFunc(f *gl.Functions, df gl.Enum) {
   586  	if df != s.depthFunc {
   587  		f.DepthFunc(df)
   588  		s.depthFunc = df
   589  	}
   590  }
   591  
   592  func (s *glState) setBlendFuncSeparate(f *gl.Functions, srcRGB, dstRGB, srcA, dstA gl.Enum) {
   593  	if srcRGB != s.blend.srcRGB || dstRGB != s.blend.dstRGB || srcA != s.blend.srcA || dstA != s.blend.dstA {
   594  		s.blend.srcRGB = srcRGB
   595  		s.blend.dstRGB = dstRGB
   596  		s.blend.srcA = srcA
   597  		s.blend.dstA = dstA
   598  		f.BlendFuncSeparate(srcA, dstA, srcA, dstA)
   599  	}
   600  }
   601  
   602  func (s *glState) setDepthMask(f *gl.Functions, enable bool) {
   603  	if enable != s.depthMask {
   604  		f.DepthMask(enable)
   605  		s.depthMask = enable
   606  	}
   607  }
   608  
   609  func (s *glState) set(f *gl.Functions, target gl.Enum, enable bool) {
   610  	switch target {
   611  	case gl.FRAMEBUFFER_SRGB:
   612  		if s.srgb == enable {
   613  			return
   614  		}
   615  		s.srgb = enable
   616  	case gl.BLEND:
   617  		if enable == s.blend.enable {
   618  			return
   619  		}
   620  		s.blend.enable = enable
   621  	case gl.DEPTH_TEST:
   622  		if enable == s.depthTest {
   623  			return
   624  		}
   625  		s.depthTest = enable
   626  	default:
   627  		panic("unknown enable")
   628  	}
   629  	if enable {
   630  		f.Enable(target)
   631  	} else {
   632  		f.Disable(target)
   633  	}
   634  }
   635  
   636  func (b *Backend) Caps() driver.Caps {
   637  	return b.feats
   638  }
   639  
   640  func (b *Backend) NewTimer() driver.Timer {
   641  	return &gpuTimer{
   642  		funcs: b.funcs,
   643  		obj:   b.funcs.CreateQuery(),
   644  	}
   645  }
   646  
   647  func (b *Backend) IsTimeContinuous() bool {
   648  	return b.funcs.GetInteger(gl.GPU_DISJOINT_EXT) == gl.FALSE
   649  }
   650  
   651  func (b *Backend) NewFramebuffer(tex driver.Texture, depthBits int) (driver.Framebuffer, error) {
   652  	glErr(b.funcs)
   653  	gltex := tex.(*gpuTexture)
   654  	fb := b.funcs.CreateFramebuffer()
   655  	fbo := &gpuFramebuffer{backend: b, obj: fb}
   656  	b.BindFramebuffer(fbo)
   657  	if err := glErr(b.funcs); err != nil {
   658  		fbo.Release()
   659  		return nil, err
   660  	}
   661  	b.funcs.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, gltex.obj, 0)
   662  	if depthBits > 0 {
   663  		size := gl.Enum(gl.DEPTH_COMPONENT16)
   664  		switch {
   665  		case depthBits > 24:
   666  			size = gl.DEPTH_COMPONENT32F
   667  		case depthBits > 16:
   668  			size = gl.DEPTH_COMPONENT24
   669  		}
   670  		depthBuf := b.funcs.CreateRenderbuffer()
   671  		b.glstate.bindRenderbuffer(b.funcs, gl.RENDERBUFFER, depthBuf)
   672  		b.funcs.RenderbufferStorage(gl.RENDERBUFFER, size, gltex.width, gltex.height)
   673  		b.funcs.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuf)
   674  		fbo.depthBuf = depthBuf
   675  		fbo.hasDepth = true
   676  		if err := glErr(b.funcs); err != nil {
   677  			fbo.Release()
   678  			return nil, err
   679  		}
   680  	}
   681  	if st := b.funcs.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
   682  		fbo.Release()
   683  		return nil, fmt.Errorf("incomplete framebuffer, status = 0x%x, err = %d", st, b.funcs.GetError())
   684  	}
   685  	return fbo, nil
   686  }
   687  
   688  func (b *Backend) NewTexture(format driver.TextureFormat, width, height int, minFilter, magFilter driver.TextureFilter, binding driver.BufferBinding) (driver.Texture, error) {
   689  	glErr(b.funcs)
   690  	tex := &gpuTexture{backend: b, obj: b.funcs.CreateTexture(), width: width, height: height}
   691  	switch format {
   692  	case driver.TextureFormatFloat:
   693  		tex.triple = b.floatTriple
   694  	case driver.TextureFormatSRGB:
   695  		tex.triple = b.srgbaTriple
   696  	case driver.TextureFormatRGBA8:
   697  		tex.triple = textureTriple{gl.RGBA8, gl.RGBA, gl.UNSIGNED_BYTE}
   698  	default:
   699  		return nil, errors.New("unsupported texture format")
   700  	}
   701  	b.BindTexture(0, tex)
   702  	b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, toTexFilter(magFilter))
   703  	b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, toTexFilter(minFilter))
   704  	b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
   705  	b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
   706  	if b.gles && b.glver[0] >= 3 {
   707  		// Immutable textures are required for BindImageTexture, and can't hurt otherwise.
   708  		b.funcs.TexStorage2D(gl.TEXTURE_2D, 1, tex.triple.internalFormat, width, height)
   709  	} else {
   710  		b.funcs.TexImage2D(gl.TEXTURE_2D, 0, tex.triple.internalFormat, width, height, tex.triple.format, tex.triple.typ)
   711  	}
   712  	if err := glErr(b.funcs); err != nil {
   713  		tex.Release()
   714  		return nil, err
   715  	}
   716  	return tex, nil
   717  }
   718  
   719  func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer, error) {
   720  	glErr(b.funcs)
   721  	buf := &gpuBuffer{backend: b, typ: typ, size: size}
   722  	if typ&driver.BufferBindingUniforms != 0 {
   723  		if typ != driver.BufferBindingUniforms {
   724  			return nil, errors.New("uniforms buffers cannot be bound as anything else")
   725  		}
   726  		if !b.ubo {
   727  			// GLES 2 doesn't support uniform buffers.
   728  			buf.data = make([]byte, size)
   729  		}
   730  	}
   731  	if typ&^driver.BufferBindingUniforms != 0 || b.ubo {
   732  		buf.hasBuffer = true
   733  		buf.obj = b.funcs.CreateBuffer()
   734  		if err := glErr(b.funcs); err != nil {
   735  			buf.Release()
   736  			return nil, err
   737  		}
   738  		firstBinding := firstBufferType(typ)
   739  		b.glstate.bindBuffer(b.funcs, firstBinding, buf.obj)
   740  		b.funcs.BufferData(firstBinding, size, gl.DYNAMIC_DRAW)
   741  	}
   742  	return buf, nil
   743  }
   744  
   745  func (b *Backend) NewImmutableBuffer(typ driver.BufferBinding, data []byte) (driver.Buffer, error) {
   746  	glErr(b.funcs)
   747  	obj := b.funcs.CreateBuffer()
   748  	buf := &gpuBuffer{backend: b, obj: obj, typ: typ, size: len(data), hasBuffer: true}
   749  	firstBinding := firstBufferType(typ)
   750  	b.glstate.bindBuffer(b.funcs, firstBinding, buf.obj)
   751  	b.funcs.BufferData(firstBinding, len(data), gl.STATIC_DRAW)
   752  	buf.Upload(data)
   753  	buf.immutable = true
   754  	if err := glErr(b.funcs); err != nil {
   755  		buf.Release()
   756  		return nil, err
   757  	}
   758  	return buf, nil
   759  }
   760  
   761  func glErr(f *gl.Functions) error {
   762  	if st := f.GetError(); st != gl.NO_ERROR {
   763  		return fmt.Errorf("glGetError: %#x", st)
   764  	}
   765  	return nil
   766  }
   767  
   768  func (b *Backend) Release() {
   769  	if b.sRGBFBO != nil {
   770  		b.sRGBFBO.Release()
   771  	}
   772  	if b.vertArray.Valid() {
   773  		b.glstate.deleteVertexArray(b.funcs, b.vertArray)
   774  	}
   775  	*b = Backend{}
   776  }
   777  
   778  func (b *Backend) MemoryBarrier() {
   779  	b.funcs.MemoryBarrier(gl.ALL_BARRIER_BITS)
   780  }
   781  
   782  func (b *Backend) DispatchCompute(x, y, z int) {
   783  	if p := b.state.prog; p != nil {
   784  		for binding, buf := range p.storage {
   785  			if buf != nil {
   786  				b.glstate.bindBufferBase(b.funcs, gl.SHADER_STORAGE_BUFFER, binding, buf.obj)
   787  			}
   788  		}
   789  	}
   790  	b.funcs.DispatchCompute(x, y, z)
   791  }
   792  
   793  func (b *Backend) BindImageTexture(unit int, tex driver.Texture, access driver.AccessBits, f driver.TextureFormat) {
   794  	t := tex.(*gpuTexture)
   795  	var acc gl.Enum
   796  	switch access {
   797  	case driver.AccessWrite:
   798  		acc = gl.WRITE_ONLY
   799  	case driver.AccessRead:
   800  		acc = gl.READ_ONLY
   801  	default:
   802  		panic("unsupported access bits")
   803  	}
   804  	var format gl.Enum
   805  	switch f {
   806  	case driver.TextureFormatRGBA8:
   807  		format = gl.RGBA8
   808  	default:
   809  		panic("unsupported format")
   810  	}
   811  	b.funcs.BindImageTexture(unit, t.obj, 0, false, 0, acc, format)
   812  }
   813  
   814  func (b *Backend) useProgram(p *gpuProgram) {
   815  	b.glstate.useProgram(b.funcs, p.obj)
   816  	b.state.prog = p
   817  }
   818  
   819  func (b *Backend) SetDepthTest(enable bool) {
   820  	b.glstate.set(b.funcs, gl.DEPTH_TEST, enable)
   821  }
   822  
   823  func (b *Backend) BlendFunc(sfactor, dfactor driver.BlendFactor) {
   824  	src, dst := toGLBlendFactor(sfactor), toGLBlendFactor(dfactor)
   825  	b.glstate.setBlendFuncSeparate(b.funcs, src, dst, src, dst)
   826  }
   827  
   828  func toGLBlendFactor(f driver.BlendFactor) gl.Enum {
   829  	switch f {
   830  	case driver.BlendFactorOne:
   831  		return gl.ONE
   832  	case driver.BlendFactorOneMinusSrcAlpha:
   833  		return gl.ONE_MINUS_SRC_ALPHA
   834  	case driver.BlendFactorZero:
   835  		return gl.ZERO
   836  	case driver.BlendFactorDstColor:
   837  		return gl.DST_COLOR
   838  	default:
   839  		panic("unsupported blend factor")
   840  	}
   841  }
   842  
   843  func (b *Backend) DepthMask(mask bool) {
   844  	b.glstate.setDepthMask(b.funcs, mask)
   845  }
   846  
   847  func (b *Backend) SetBlend(enable bool) {
   848  	b.glstate.set(b.funcs, gl.BLEND, enable)
   849  }
   850  
   851  func (b *Backend) DrawElements(mode driver.DrawMode, off, count int) {
   852  	b.prepareDraw()
   853  	// off is in 16-bit indices, but DrawElements take a byte offset.
   854  	byteOff := off * 2
   855  	b.funcs.DrawElements(toGLDrawMode(mode), count, gl.UNSIGNED_SHORT, byteOff)
   856  }
   857  
   858  func (b *Backend) DrawArrays(mode driver.DrawMode, off, count int) {
   859  	b.prepareDraw()
   860  	b.funcs.DrawArrays(toGLDrawMode(mode), off, count)
   861  }
   862  
   863  func (b *Backend) prepareDraw() {
   864  	p := b.state.prog
   865  	if p == nil {
   866  		return
   867  	}
   868  	b.setupVertexArrays()
   869  	p.updateUniforms()
   870  }
   871  
   872  func toGLDrawMode(mode driver.DrawMode) gl.Enum {
   873  	switch mode {
   874  	case driver.DrawModeTriangleStrip:
   875  		return gl.TRIANGLE_STRIP
   876  	case driver.DrawModeTriangles:
   877  		return gl.TRIANGLES
   878  	default:
   879  		panic("unsupported draw mode")
   880  	}
   881  }
   882  
   883  func (b *Backend) Viewport(x, y, width, height int) {
   884  	b.glstate.setViewport(b.funcs, x, y, width, height)
   885  }
   886  
   887  func (b *Backend) Clear(colR, colG, colB, colA float32) {
   888  	b.glstate.setClearColor(b.funcs, colR, colG, colB, colA)
   889  	b.funcs.Clear(gl.COLOR_BUFFER_BIT)
   890  }
   891  
   892  func (b *Backend) ClearDepth(d float32) {
   893  	b.glstate.setClearDepth(b.funcs, d)
   894  	b.funcs.Clear(gl.DEPTH_BUFFER_BIT)
   895  }
   896  
   897  func (b *Backend) DepthFunc(f driver.DepthFunc) {
   898  	var glfunc gl.Enum
   899  	switch f {
   900  	case driver.DepthFuncGreater:
   901  		glfunc = gl.GREATER
   902  	case driver.DepthFuncGreaterEqual:
   903  		glfunc = gl.GEQUAL
   904  	default:
   905  		panic("unsupported depth func")
   906  	}
   907  	b.glstate.setDepthFunc(b.funcs, glfunc)
   908  }
   909  
   910  func (b *Backend) NewInputLayout(vs driver.ShaderSources, layout []driver.InputDesc) (driver.InputLayout, error) {
   911  	if len(vs.Inputs) != len(layout) {
   912  		return nil, fmt.Errorf("NewInputLayout: got %d inputs, expected %d", len(layout), len(vs.Inputs))
   913  	}
   914  	for i, inp := range vs.Inputs {
   915  		if exp, got := inp.Size, layout[i].Size; exp != got {
   916  			return nil, fmt.Errorf("NewInputLayout: data size mismatch for %q: got %d expected %d", inp.Name, got, exp)
   917  		}
   918  	}
   919  	return &gpuInputLayout{
   920  		inputs: vs.Inputs,
   921  		layout: layout,
   922  	}, nil
   923  }
   924  
   925  func (b *Backend) NewComputeProgram(src driver.ShaderSources) (driver.Program, error) {
   926  	p, err := gl.CreateComputeProgram(b.funcs, src.GLSL310ES)
   927  	if err != nil {
   928  		return nil, fmt.Errorf("%s: %v", src.Name, err)
   929  	}
   930  	gpuProg := &gpuProgram{
   931  		backend: b,
   932  		obj:     p,
   933  	}
   934  	return gpuProg, nil
   935  }
   936  
   937  func (b *Backend) NewProgram(vertShader, fragShader driver.ShaderSources) (driver.Program, error) {
   938  	attr := make([]string, len(vertShader.Inputs))
   939  	for _, inp := range vertShader.Inputs {
   940  		attr[inp.Location] = inp.Name
   941  	}
   942  	vsrc, fsrc := vertShader.GLSL100ES, fragShader.GLSL100ES
   943  	if b.glver[0] >= 3 {
   944  		// OpenGL (ES) 3.0.
   945  		switch {
   946  		case b.gles:
   947  			vsrc, fsrc = vertShader.GLSL300ES, fragShader.GLSL300ES
   948  		case b.glver[0] >= 4 || b.glver[1] >= 2:
   949  			// OpenGL 3.2 Core only accepts glsl 1.50 or newer.
   950  			vsrc, fsrc = vertShader.GLSL150, fragShader.GLSL150
   951  		default:
   952  			vsrc, fsrc = vertShader.GLSL130, fragShader.GLSL130
   953  		}
   954  	}
   955  	p, err := gl.CreateProgram(b.funcs, vsrc, fsrc, attr)
   956  	if err != nil {
   957  		return nil, err
   958  	}
   959  	gpuProg := &gpuProgram{
   960  		backend: b,
   961  		obj:     p,
   962  	}
   963  	b.BindProgram(gpuProg)
   964  	// Bind texture uniforms.
   965  	for _, tex := range vertShader.Textures {
   966  		u := b.funcs.GetUniformLocation(p, tex.Name)
   967  		if u.Valid() {
   968  			b.funcs.Uniform1i(u, tex.Binding)
   969  		}
   970  	}
   971  	for _, tex := range fragShader.Textures {
   972  		u := b.funcs.GetUniformLocation(p, tex.Name)
   973  		if u.Valid() {
   974  			b.funcs.Uniform1i(u, tex.Binding)
   975  		}
   976  	}
   977  	if b.ubo {
   978  		for _, block := range vertShader.Uniforms.Blocks {
   979  			blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name)
   980  			if blockIdx != gl.INVALID_INDEX {
   981  				b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding))
   982  			}
   983  		}
   984  		// To match Direct3D 11 with separate vertex and fragment
   985  		// shader uniform buffers, offset all fragment blocks to be
   986  		// located after the vertex blocks.
   987  		off := len(vertShader.Uniforms.Blocks)
   988  		for _, block := range fragShader.Uniforms.Blocks {
   989  			blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name)
   990  			if blockIdx != gl.INVALID_INDEX {
   991  				b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding+off))
   992  			}
   993  		}
   994  	} else {
   995  		gpuProg.vertUniforms.setup(b.funcs, p, vertShader.Uniforms.Size, vertShader.Uniforms.Locations)
   996  		gpuProg.fragUniforms.setup(b.funcs, p, fragShader.Uniforms.Size, fragShader.Uniforms.Locations)
   997  	}
   998  	return gpuProg, nil
   999  }
  1000  
  1001  func lookupUniform(funcs *gl.Functions, p gl.Program, loc driver.UniformLocation) uniformLocation {
  1002  	u := funcs.GetUniformLocation(p, loc.Name)
  1003  	if !u.Valid() {
  1004  		panic(fmt.Errorf("uniform %q not found", loc.Name))
  1005  	}
  1006  	return uniformLocation{uniform: u, offset: loc.Offset, typ: loc.Type, size: loc.Size}
  1007  }
  1008  
  1009  func (p *gpuProgram) SetStorageBuffer(binding int, buffer driver.Buffer) {
  1010  	buf := buffer.(*gpuBuffer)
  1011  	if buf.typ&driver.BufferBindingShaderStorage == 0 {
  1012  		panic("not a shader storage buffer")
  1013  	}
  1014  	p.storage[binding] = buf
  1015  }
  1016  
  1017  func (p *gpuProgram) SetVertexUniforms(buffer driver.Buffer) {
  1018  	p.vertUniforms.setBuffer(buffer)
  1019  }
  1020  
  1021  func (p *gpuProgram) SetFragmentUniforms(buffer driver.Buffer) {
  1022  	p.fragUniforms.setBuffer(buffer)
  1023  }
  1024  
  1025  func (p *gpuProgram) updateUniforms() {
  1026  	f := p.backend.funcs
  1027  	if p.backend.ubo {
  1028  		if b := p.vertUniforms.buf; b != nil {
  1029  			p.backend.glstate.bindBufferBase(f, gl.UNIFORM_BUFFER, 0, b.obj)
  1030  		}
  1031  		if b := p.fragUniforms.buf; b != nil {
  1032  			p.backend.glstate.bindBufferBase(f, gl.UNIFORM_BUFFER, 1, b.obj)
  1033  		}
  1034  	} else {
  1035  		p.vertUniforms.update(f)
  1036  		p.fragUniforms.update(f)
  1037  	}
  1038  }
  1039  
  1040  func (b *Backend) BindProgram(prog driver.Program) {
  1041  	p := prog.(*gpuProgram)
  1042  	b.useProgram(p)
  1043  }
  1044  
  1045  func (p *gpuProgram) Release() {
  1046  	p.backend.glstate.deleteProgram(p.backend.funcs, p.obj)
  1047  }
  1048  
  1049  func (u *uniformsTracker) setup(funcs *gl.Functions, p gl.Program, uniformSize int, uniforms []driver.UniformLocation) {
  1050  	u.locs = make([]uniformLocation, len(uniforms))
  1051  	for i, uniform := range uniforms {
  1052  		u.locs[i] = lookupUniform(funcs, p, uniform)
  1053  	}
  1054  	u.size = uniformSize
  1055  }
  1056  
  1057  func (u *uniformsTracker) setBuffer(buffer driver.Buffer) {
  1058  	buf := buffer.(*gpuBuffer)
  1059  	if buf.typ&driver.BufferBindingUniforms == 0 {
  1060  		panic("not a uniform buffer")
  1061  	}
  1062  	if buf.size < u.size {
  1063  		panic(fmt.Errorf("uniform buffer too small, got %d need %d", buf.size, u.size))
  1064  	}
  1065  	u.buf = buf
  1066  	// Force update.
  1067  	u.version = buf.version - 1
  1068  }
  1069  
  1070  func (p *uniformsTracker) update(funcs *gl.Functions) {
  1071  	b := p.buf
  1072  	if b == nil || b.version == p.version {
  1073  		return
  1074  	}
  1075  	p.version = b.version
  1076  	data := b.data
  1077  	for _, u := range p.locs {
  1078  		data := data[u.offset:]
  1079  		switch {
  1080  		case u.typ == driver.DataTypeFloat && u.size == 1:
  1081  			data := data[:4]
  1082  			v := *(*[1]float32)(unsafe.Pointer(&data[0]))
  1083  			funcs.Uniform1f(u.uniform, v[0])
  1084  		case u.typ == driver.DataTypeFloat && u.size == 2:
  1085  			data := data[:8]
  1086  			v := *(*[2]float32)(unsafe.Pointer(&data[0]))
  1087  			funcs.Uniform2f(u.uniform, v[0], v[1])
  1088  		case u.typ == driver.DataTypeFloat && u.size == 3:
  1089  			data := data[:12]
  1090  			v := *(*[3]float32)(unsafe.Pointer(&data[0]))
  1091  			funcs.Uniform3f(u.uniform, v[0], v[1], v[2])
  1092  		case u.typ == driver.DataTypeFloat && u.size == 4:
  1093  			data := data[:16]
  1094  			v := *(*[4]float32)(unsafe.Pointer(&data[0]))
  1095  			funcs.Uniform4f(u.uniform, v[0], v[1], v[2], v[3])
  1096  		default:
  1097  			panic("unsupported uniform data type or size")
  1098  		}
  1099  	}
  1100  }
  1101  
  1102  func (b *gpuBuffer) Upload(data []byte) {
  1103  	if b.immutable {
  1104  		panic("immutable buffer")
  1105  	}
  1106  	if len(data) > b.size {
  1107  		panic("buffer size overflow")
  1108  	}
  1109  	b.version++
  1110  	copy(b.data, data)
  1111  	if b.hasBuffer {
  1112  		firstBinding := firstBufferType(b.typ)
  1113  		b.backend.glstate.bindBuffer(b.backend.funcs, firstBinding, b.obj)
  1114  		if len(data) == b.size {
  1115  			// the iOS GL implementation doesn't recognize when BufferSubData
  1116  			// clears the entire buffer. Tell it and avoid GPU stalls.
  1117  			// See also https://github.com/godotengine/godot/issues/23956.
  1118  			b.backend.funcs.BufferData(firstBinding, b.size, gl.DYNAMIC_DRAW)
  1119  		}
  1120  		b.backend.funcs.BufferSubData(firstBinding, 0, data)
  1121  	}
  1122  }
  1123  
  1124  func (b *gpuBuffer) Download(data []byte) error {
  1125  	if len(data) > b.size {
  1126  		panic("buffer size overflow")
  1127  	}
  1128  	if !b.hasBuffer {
  1129  		copy(data, b.data)
  1130  		return nil
  1131  	}
  1132  	firstBinding := firstBufferType(b.typ)
  1133  	b.backend.glstate.bindBuffer(b.backend.funcs, firstBinding, b.obj)
  1134  	bufferMap := b.backend.funcs.MapBufferRange(firstBinding, 0, len(data), gl.MAP_READ_BIT)
  1135  	if bufferMap == nil {
  1136  		return fmt.Errorf("MapBufferRange: error %#x", b.backend.funcs.GetError())
  1137  	}
  1138  	copy(data, bufferMap)
  1139  	if !b.backend.funcs.UnmapBuffer(firstBinding) {
  1140  		return driver.ErrContentLost
  1141  	}
  1142  	return nil
  1143  }
  1144  
  1145  func (b *gpuBuffer) Release() {
  1146  	if b.hasBuffer {
  1147  		b.backend.glstate.deleteBuffer(b.backend.funcs, b.obj)
  1148  		b.hasBuffer = false
  1149  	}
  1150  }
  1151  
  1152  func (b *Backend) BindVertexBuffer(buf driver.Buffer, stride, offset int) {
  1153  	gbuf := buf.(*gpuBuffer)
  1154  	if gbuf.typ&driver.BufferBindingVertices == 0 {
  1155  		panic("not a vertex buffer")
  1156  	}
  1157  	b.state.buffer = bufferBinding{obj: gbuf.obj, stride: stride, offset: offset}
  1158  }
  1159  
  1160  func (b *Backend) setupVertexArrays() {
  1161  	layout := b.state.layout
  1162  	if layout == nil {
  1163  		return
  1164  	}
  1165  	const max = len(b.glstate.vertAttribs)
  1166  	var enabled [max]bool
  1167  	buf := b.state.buffer
  1168  	for i, inp := range layout.inputs {
  1169  		l := layout.layout[i]
  1170  		var gltyp gl.Enum
  1171  		switch l.Type {
  1172  		case driver.DataTypeFloat:
  1173  			gltyp = gl.FLOAT
  1174  		case driver.DataTypeShort:
  1175  			gltyp = gl.SHORT
  1176  		default:
  1177  			panic("unsupported data type")
  1178  		}
  1179  		enabled[inp.Location] = true
  1180  		b.glstate.vertexAttribPointer(b.funcs, buf.obj, inp.Location, l.Size, gltyp, false, buf.stride, buf.offset+l.Offset)
  1181  	}
  1182  	for i := 0; i < max; i++ {
  1183  		b.glstate.setVertexAttribArray(b.funcs, i, enabled[i])
  1184  	}
  1185  }
  1186  
  1187  func (b *Backend) BindIndexBuffer(buf driver.Buffer) {
  1188  	gbuf := buf.(*gpuBuffer)
  1189  	if gbuf.typ&driver.BufferBindingIndices == 0 {
  1190  		panic("not an index buffer")
  1191  	}
  1192  	b.glstate.bindBuffer(b.funcs, gl.ELEMENT_ARRAY_BUFFER, gbuf.obj)
  1193  }
  1194  
  1195  func (b *Backend) BlitFramebuffer(dst, src driver.Framebuffer, srect, drect image.Rectangle) {
  1196  	b.glstate.bindFramebuffer(b.funcs, gl.DRAW_FRAMEBUFFER, dst.(*gpuFramebuffer).obj)
  1197  	b.glstate.bindFramebuffer(b.funcs, gl.READ_FRAMEBUFFER, src.(*gpuFramebuffer).obj)
  1198  	b.funcs.BlitFramebuffer(
  1199  		srect.Min.X, srect.Min.Y, srect.Max.X, srect.Max.Y,
  1200  		drect.Min.X, drect.Min.Y, drect.Max.X, drect.Max.Y,
  1201  		gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT|gl.STENCIL_BUFFER_BIT,
  1202  		gl.NEAREST)
  1203  }
  1204  
  1205  func (f *gpuFramebuffer) ReadPixels(src image.Rectangle, pixels []byte) error {
  1206  	glErr(f.backend.funcs)
  1207  	f.backend.BindFramebuffer(f)
  1208  	if len(pixels) < src.Dx()*src.Dy()*4 {
  1209  		return errors.New("unexpected RGBA size")
  1210  	}
  1211  	f.backend.funcs.ReadPixels(src.Min.X, src.Min.Y, src.Dx(), src.Dy(), gl.RGBA, gl.UNSIGNED_BYTE, pixels)
  1212  	return glErr(f.backend.funcs)
  1213  }
  1214  
  1215  func (b *Backend) BindFramebuffer(fbo driver.Framebuffer) {
  1216  	b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, fbo.(*gpuFramebuffer).obj)
  1217  }
  1218  
  1219  func (f *gpuFramebuffer) Invalidate() {
  1220  	f.backend.BindFramebuffer(f)
  1221  	f.backend.funcs.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0)
  1222  }
  1223  
  1224  func (f *gpuFramebuffer) Release() {
  1225  	if f.foreign {
  1226  		panic("framebuffer not created by NewFramebuffer")
  1227  	}
  1228  	f.backend.glstate.deleteFramebuffer(f.backend.funcs, f.obj)
  1229  	if f.hasDepth {
  1230  		f.backend.glstate.deleteRenderbuffer(f.backend.funcs, f.depthBuf)
  1231  	}
  1232  }
  1233  
  1234  func toTexFilter(f driver.TextureFilter) int {
  1235  	switch f {
  1236  	case driver.FilterNearest:
  1237  		return gl.NEAREST
  1238  	case driver.FilterLinear:
  1239  		return gl.LINEAR
  1240  	default:
  1241  		panic("unsupported texture filter")
  1242  	}
  1243  }
  1244  
  1245  func (b *Backend) BindTexture(unit int, t driver.Texture) {
  1246  	b.glstate.bindTexture(b.funcs, unit, t.(*gpuTexture).obj)
  1247  }
  1248  
  1249  func (t *gpuTexture) Release() {
  1250  	t.backend.glstate.deleteTexture(t.backend.funcs, t.obj)
  1251  }
  1252  
  1253  func (t *gpuTexture) Upload(offset, size image.Point, pixels []byte) {
  1254  	if min := size.X * size.Y * 4; min > len(pixels) {
  1255  		panic(fmt.Errorf("size %d larger than data %d", min, len(pixels)))
  1256  	}
  1257  	t.backend.BindTexture(0, t)
  1258  	t.backend.funcs.TexSubImage2D(gl.TEXTURE_2D, 0, offset.X, offset.Y, size.X, size.Y, t.triple.format, t.triple.typ, pixels)
  1259  }
  1260  
  1261  func (t *gpuTimer) Begin() {
  1262  	t.funcs.BeginQuery(gl.TIME_ELAPSED_EXT, t.obj)
  1263  }
  1264  
  1265  func (t *gpuTimer) End() {
  1266  	t.funcs.EndQuery(gl.TIME_ELAPSED_EXT)
  1267  }
  1268  
  1269  func (t *gpuTimer) ready() bool {
  1270  	return t.funcs.GetQueryObjectuiv(t.obj, gl.QUERY_RESULT_AVAILABLE) == gl.TRUE
  1271  }
  1272  
  1273  func (t *gpuTimer) Release() {
  1274  	t.funcs.DeleteQuery(t.obj)
  1275  }
  1276  
  1277  func (t *gpuTimer) Duration() (time.Duration, bool) {
  1278  	if !t.ready() {
  1279  		return 0, false
  1280  	}
  1281  	nanos := t.funcs.GetQueryObjectuiv(t.obj, gl.QUERY_RESULT)
  1282  	return time.Duration(nanos), true
  1283  }
  1284  
  1285  func (b *Backend) BindInputLayout(l driver.InputLayout) {
  1286  	b.state.layout = l.(*gpuInputLayout)
  1287  }
  1288  
  1289  func (l *gpuInputLayout) Release() {}
  1290  
  1291  // floatTripleFor determines the best texture triple for floating point FBOs.
  1292  func floatTripleFor(f *gl.Functions, ver [2]int, exts []string) (textureTriple, error) {
  1293  	var triples []textureTriple
  1294  	if ver[0] >= 3 {
  1295  		triples = append(triples, textureTriple{gl.R16F, gl.Enum(gl.RED), gl.Enum(gl.HALF_FLOAT)})
  1296  	}
  1297  	// According to the OES_texture_half_float specification, EXT_color_buffer_half_float is needed to
  1298  	// render to FBOs. However, the Safari WebGL1 implementation does support half-float FBOs but does not
  1299  	// report EXT_color_buffer_half_float support. The triples are verified below, so it doesn't matter if we're
  1300  	// wrong.
  1301  	if hasExtension(exts, "GL_OES_texture_half_float") || hasExtension(exts, "GL_EXT_color_buffer_half_float") {
  1302  		// Try single channel.
  1303  		triples = append(triples, textureTriple{gl.LUMINANCE, gl.Enum(gl.LUMINANCE), gl.Enum(gl.HALF_FLOAT_OES)})
  1304  		// Fallback to 4 channels.
  1305  		triples = append(triples, textureTriple{gl.RGBA, gl.Enum(gl.RGBA), gl.Enum(gl.HALF_FLOAT_OES)})
  1306  	}
  1307  	if hasExtension(exts, "GL_OES_texture_float") || hasExtension(exts, "GL_EXT_color_buffer_float") {
  1308  		triples = append(triples, textureTriple{gl.RGBA, gl.Enum(gl.RGBA), gl.Enum(gl.FLOAT)})
  1309  	}
  1310  	tex := f.CreateTexture()
  1311  	defer f.DeleteTexture(tex)
  1312  	defTex := gl.Texture(f.GetBinding(gl.TEXTURE_BINDING_2D))
  1313  	defer f.BindTexture(gl.TEXTURE_2D, defTex)
  1314  	f.BindTexture(gl.TEXTURE_2D, tex)
  1315  	f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
  1316  	f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
  1317  	f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
  1318  	f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
  1319  	fbo := f.CreateFramebuffer()
  1320  	defer f.DeleteFramebuffer(fbo)
  1321  	defFBO := gl.Framebuffer(f.GetBinding(gl.FRAMEBUFFER_BINDING))
  1322  	f.BindFramebuffer(gl.FRAMEBUFFER, fbo)
  1323  	defer f.BindFramebuffer(gl.FRAMEBUFFER, defFBO)
  1324  	var attempts []string
  1325  	for _, tt := range triples {
  1326  		const size = 256
  1327  		f.TexImage2D(gl.TEXTURE_2D, 0, tt.internalFormat, size, size, tt.format, tt.typ)
  1328  		f.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)
  1329  		st := f.CheckFramebufferStatus(gl.FRAMEBUFFER)
  1330  		if st == gl.FRAMEBUFFER_COMPLETE {
  1331  			return tt, nil
  1332  		}
  1333  		attempts = append(attempts, fmt.Sprintf("(0x%x, 0x%x, 0x%x): 0x%x", tt.internalFormat, tt.format, tt.typ, st))
  1334  	}
  1335  	return textureTriple{}, fmt.Errorf("floating point fbos not supported (attempted %s)", attempts)
  1336  }
  1337  
  1338  func srgbaTripleFor(ver [2]int, exts []string) (textureTriple, error) {
  1339  	switch {
  1340  	case ver[0] >= 3:
  1341  		return textureTriple{gl.SRGB8_ALPHA8, gl.Enum(gl.RGBA), gl.Enum(gl.UNSIGNED_BYTE)}, nil
  1342  	case hasExtension(exts, "GL_EXT_sRGB"):
  1343  		return textureTriple{gl.SRGB_ALPHA_EXT, gl.Enum(gl.SRGB_ALPHA_EXT), gl.Enum(gl.UNSIGNED_BYTE)}, nil
  1344  	default:
  1345  		return textureTriple{}, errors.New("no sRGB texture formats found")
  1346  	}
  1347  }
  1348  
  1349  func alphaTripleFor(ver [2]int) textureTriple {
  1350  	intf, f := gl.Enum(gl.R8), gl.Enum(gl.RED)
  1351  	if ver[0] < 3 {
  1352  		// R8, RED not supported on OpenGL ES 2.0.
  1353  		intf, f = gl.LUMINANCE, gl.Enum(gl.LUMINANCE)
  1354  	}
  1355  	return textureTriple{intf, f, gl.UNSIGNED_BYTE}
  1356  }
  1357  
  1358  func hasExtension(exts []string, ext string) bool {
  1359  	for _, e := range exts {
  1360  		if ext == e {
  1361  			return true
  1362  		}
  1363  	}
  1364  	return false
  1365  }
  1366  
  1367  func firstBufferType(typ driver.BufferBinding) gl.Enum {
  1368  	switch {
  1369  	case typ&driver.BufferBindingIndices != 0:
  1370  		return gl.ELEMENT_ARRAY_BUFFER
  1371  	case typ&driver.BufferBindingVertices != 0:
  1372  		return gl.ARRAY_BUFFER
  1373  	case typ&driver.BufferBindingUniforms != 0:
  1374  		return gl.UNIFORM_BUFFER
  1375  	case typ&driver.BufferBindingShaderStorage != 0:
  1376  		return gl.SHADER_STORAGE_BUFFER
  1377  	default:
  1378  		panic("unsupported buffer type")
  1379  	}
  1380  }