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