opengl.go raw

   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/p9c/p9/pkg/gel/gio/gpu/internal/driver"
  14  	"github.com/p9c/p9/pkg/gel/gio/internal/gl"
  15  )
  16  
  17  // Backend implements driver.Device.
  18  type Backend struct {
  19  	funcs *gl.Functions
  20  
  21  	state glstate
  22  
  23  	glver [2]int
  24  	gles  bool
  25  	ubo   bool
  26  	feats driver.Caps
  27  	// floatTriple holds the settings for floating point
  28  	// textures.
  29  	floatTriple textureTriple
  30  	// Single channel alpha textures.
  31  	alphaTriple textureTriple
  32  	srgbaTriple textureTriple
  33  }
  34  
  35  // State tracking.
  36  type glstate struct {
  37  	// nattr is the current number of enabled vertex arrays.
  38  	nattr    int
  39  	prog     *gpuProgram
  40  	texUnits [4]*gpuTexture
  41  	layout   *gpuInputLayout
  42  	buffer   bufferBinding
  43  }
  44  
  45  type bufferBinding struct {
  46  	buf    *gpuBuffer
  47  	offset int
  48  	stride int
  49  }
  50  
  51  type gpuTimer struct {
  52  	funcs *gl.Functions
  53  	obj   gl.Query
  54  }
  55  
  56  type gpuTexture struct {
  57  	backend *Backend
  58  	obj     gl.Texture
  59  	triple  textureTriple
  60  	width   int
  61  	height  int
  62  }
  63  
  64  type gpuFramebuffer struct {
  65  	backend  *Backend
  66  	obj      gl.Framebuffer
  67  	hasDepth bool
  68  	depthBuf gl.Renderbuffer
  69  	foreign  bool
  70  }
  71  
  72  type gpuBuffer struct {
  73  	backend   *Backend
  74  	hasBuffer bool
  75  	obj       gl.Buffer
  76  	typ       driver.BufferBinding
  77  	size      int
  78  	immutable bool
  79  	version   int
  80  	// For emulation of uniform buffers.
  81  	data []byte
  82  }
  83  
  84  type gpuProgram struct {
  85  	backend      *Backend
  86  	obj          gl.Program
  87  	nattr        int
  88  	vertUniforms uniformsTracker
  89  	fragUniforms uniformsTracker
  90  	storage      [storageBindings]*gpuBuffer
  91  }
  92  
  93  type uniformsTracker struct {
  94  	locs    []uniformLocation
  95  	size    int
  96  	buf     *gpuBuffer
  97  	version int
  98  }
  99  
 100  type uniformLocation struct {
 101  	uniform gl.Uniform
 102  	offset  int
 103  	typ     driver.DataType
 104  	size    int
 105  }
 106  
 107  type gpuInputLayout struct {
 108  	inputs []driver.InputLocation
 109  	layout []driver.InputDesc
 110  }
 111  
 112  // textureTriple holds the type settings for
 113  // a TexImage2D call.
 114  type textureTriple struct {
 115  	internalFormat gl.Enum
 116  	format         gl.Enum
 117  	typ            gl.Enum
 118  }
 119  
 120  type Context = gl.Context
 121  
 122  const (
 123  	storageBindings = 32
 124  )
 125  
 126  func init() {
 127  	driver.NewOpenGLDevice = newOpenGLDevice
 128  }
 129  
 130  func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) {
 131  	f, err := gl.NewFunctions(api.Context)
 132  	if err != nil {
 133  		return nil, err
 134  	}
 135  	exts := strings.Split(f.GetString(gl.EXTENSIONS), " ")
 136  	glVer := f.GetString(gl.VERSION)
 137  	ver, gles, err := gl.ParseGLVersion(glVer)
 138  	if err != nil {
 139  		return nil, err
 140  	}
 141  	floatTriple, ffboErr := floatTripleFor(f, ver, exts)
 142  	srgbaTriple, err := srgbaTripleFor(ver, exts)
 143  	if err != nil {
 144  		return nil, err
 145  	}
 146  	gles30 := gles && ver[0] >= 3
 147  	gles31 := gles && (ver[0] > 3 || (ver[0] == 3 && ver[1] >= 1))
 148  	gl40 := !gles && ver[0] >= 4
 149  	b := &Backend{
 150  		glver:       ver,
 151  		gles:        gles,
 152  		ubo:         gles30 || gl40,
 153  		funcs:       f,
 154  		floatTriple: floatTriple,
 155  		alphaTriple: alphaTripleFor(ver),
 156  		srgbaTriple: srgbaTriple,
 157  	}
 158  	b.feats.BottomLeftOrigin = true
 159  	if ffboErr == nil {
 160  		b.feats.Features |= driver.FeatureFloatRenderTargets
 161  	}
 162  	if gles31 {
 163  		b.feats.Features |= driver.FeatureCompute
 164  	}
 165  	if hasExtension(exts, "GL_EXT_disjoint_timer_query_webgl2") || hasExtension(exts, "GL_EXT_disjoint_timer_query") {
 166  		b.feats.Features |= driver.FeatureTimers
 167  	}
 168  	b.feats.MaxTextureSize = f.GetInteger(gl.MAX_TEXTURE_SIZE)
 169  	return b, nil
 170  }
 171  
 172  func (b *Backend) BeginFrame() driver.Framebuffer {
 173  	// Assume GL state is reset between frames.
 174  	b.state = glstate{}
 175  	fboID := gl.Framebuffer(b.funcs.GetBinding(gl.FRAMEBUFFER_BINDING))
 176  	return &gpuFramebuffer{backend: b, obj: fboID, foreign: true}
 177  }
 178  
 179  func (b *Backend) EndFrame() {
 180  	b.funcs.ActiveTexture(gl.TEXTURE0)
 181  }
 182  
 183  func (b *Backend) Caps() driver.Caps {
 184  	return b.feats
 185  }
 186  
 187  func (b *Backend) NewTimer() driver.Timer {
 188  	return &gpuTimer{
 189  		funcs: b.funcs,
 190  		obj:   b.funcs.CreateQuery(),
 191  	}
 192  }
 193  
 194  func (b *Backend) IsTimeContinuous() bool {
 195  	return b.funcs.GetInteger(gl.GPU_DISJOINT_EXT) == gl.FALSE
 196  }
 197  
 198  func (b *Backend) NewFramebuffer(tex driver.Texture, depthBits int) (driver.Framebuffer, error) {
 199  	glErr(b.funcs)
 200  	gltex := tex.(*gpuTexture)
 201  	fb := b.funcs.CreateFramebuffer()
 202  	fbo := &gpuFramebuffer{backend: b, obj: fb}
 203  	b.BindFramebuffer(fbo)
 204  	if err := glErr(b.funcs); err != nil {
 205  		fbo.Release()
 206  		return nil, err
 207  	}
 208  	b.funcs.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, gltex.obj, 0)
 209  	if depthBits > 0 {
 210  		size := gl.Enum(gl.DEPTH_COMPONENT16)
 211  		switch {
 212  		case depthBits > 24:
 213  			size = gl.DEPTH_COMPONENT32F
 214  		case depthBits > 16:
 215  			size = gl.DEPTH_COMPONENT24
 216  		}
 217  		depthBuf := b.funcs.CreateRenderbuffer()
 218  		b.funcs.BindRenderbuffer(gl.RENDERBUFFER, depthBuf)
 219  		b.funcs.RenderbufferStorage(gl.RENDERBUFFER, size, gltex.width, gltex.height)
 220  		b.funcs.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuf)
 221  		fbo.depthBuf = depthBuf
 222  		fbo.hasDepth = true
 223  		if err := glErr(b.funcs); err != nil {
 224  			fbo.Release()
 225  			return nil, err
 226  		}
 227  	}
 228  	if st := b.funcs.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
 229  		fbo.Release()
 230  		return nil, fmt.Errorf("incomplete framebuffer, status = 0x%x, err = %d", st, b.funcs.GetError())
 231  	}
 232  	return fbo, nil
 233  }
 234  
 235  func (b *Backend) NewTexture(format driver.TextureFormat, width, height int, minFilter, magFilter driver.TextureFilter, binding driver.BufferBinding) (driver.Texture, error) {
 236  	glErr(b.funcs)
 237  	tex := &gpuTexture{backend: b, obj: b.funcs.CreateTexture(), width: width, height: height}
 238  	switch format {
 239  	case driver.TextureFormatFloat:
 240  		tex.triple = b.floatTriple
 241  	case driver.TextureFormatSRGB:
 242  		tex.triple = b.srgbaTriple
 243  	case driver.TextureFormatRGBA8:
 244  		tex.triple = textureTriple{gl.RGBA8, gl.RGBA, gl.UNSIGNED_BYTE}
 245  	default:
 246  		return nil, errors.New("unsupported texture format")
 247  	}
 248  	b.BindTexture(0, tex)
 249  	b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, toTexFilter(magFilter))
 250  	b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, toTexFilter(minFilter))
 251  	b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
 252  	b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
 253  	if b.gles && b.glver[0] >= 3 {
 254  		// Immutable textures are required for BindImageTexture, and can't hurt otherwise.
 255  		b.funcs.TexStorage2D(gl.TEXTURE_2D, 1, tex.triple.internalFormat, width, height)
 256  	} else {
 257  		b.funcs.TexImage2D(gl.TEXTURE_2D, 0, tex.triple.internalFormat, width, height, tex.triple.format, tex.triple.typ)
 258  	}
 259  	if err := glErr(b.funcs); err != nil {
 260  		tex.Release()
 261  		return nil, err
 262  	}
 263  	return tex, nil
 264  }
 265  
 266  func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer, error) {
 267  	glErr(b.funcs)
 268  	buf := &gpuBuffer{backend: b, typ: typ, size: size}
 269  	if typ&driver.BufferBindingUniforms != 0 {
 270  		if typ != driver.BufferBindingUniforms {
 271  			return nil, errors.New("uniforms buffers cannot be bound as anything else")
 272  		}
 273  		if !b.ubo {
 274  			// GLES 2 doesn't support uniform buffers.
 275  			buf.data = make([]byte, size)
 276  		}
 277  	}
 278  	if typ&^driver.BufferBindingUniforms != 0 || b.ubo {
 279  		buf.hasBuffer = true
 280  		buf.obj = b.funcs.CreateBuffer()
 281  		if err := glErr(b.funcs); err != nil {
 282  			buf.Release()
 283  			return nil, err
 284  		}
 285  		firstBinding := firstBufferType(typ)
 286  		b.funcs.BindBuffer(firstBinding, buf.obj)
 287  		b.funcs.BufferData(firstBinding, size, gl.DYNAMIC_DRAW)
 288  	}
 289  	return buf, nil
 290  }
 291  
 292  func (b *Backend) NewImmutableBuffer(typ driver.BufferBinding, data []byte) (driver.Buffer, error) {
 293  	glErr(b.funcs)
 294  	obj := b.funcs.CreateBuffer()
 295  	buf := &gpuBuffer{backend: b, obj: obj, typ: typ, size: len(data), hasBuffer: true}
 296  	firstBinding := firstBufferType(typ)
 297  	b.funcs.BindBuffer(firstBinding, buf.obj)
 298  	b.funcs.BufferData(firstBinding, len(data), gl.STATIC_DRAW)
 299  	buf.Upload(data)
 300  	buf.immutable = true
 301  	if err := glErr(b.funcs); err != nil {
 302  		buf.Release()
 303  		return nil, err
 304  	}
 305  	return buf, nil
 306  }
 307  
 308  func glErr(f *gl.Functions) error {
 309  	if st := f.GetError(); st != gl.NO_ERROR {
 310  		return fmt.Errorf("glGetError: %#x", st)
 311  	}
 312  	return nil
 313  }
 314  
 315  func (b *Backend) Release() {
 316  }
 317  
 318  func (b *Backend) MemoryBarrier() {
 319  	b.funcs.MemoryBarrier(gl.ALL_BARRIER_BITS)
 320  }
 321  
 322  func (b *Backend) DispatchCompute(x, y, z int) {
 323  	if p := b.state.prog; p != nil {
 324  		for binding, buf := range p.storage {
 325  			if buf != nil {
 326  				b.funcs.BindBufferBase(gl.SHADER_STORAGE_BUFFER, binding, buf.obj)
 327  			}
 328  		}
 329  	}
 330  	b.funcs.DispatchCompute(x, y, z)
 331  }
 332  
 333  func (b *Backend) BindImageTexture(unit int, tex driver.Texture, access driver.AccessBits, f driver.TextureFormat) {
 334  	t := tex.(*gpuTexture)
 335  	var acc gl.Enum
 336  	switch access {
 337  	case driver.AccessWrite:
 338  		acc = gl.WRITE_ONLY
 339  	case driver.AccessRead:
 340  		acc = gl.READ_ONLY
 341  	default:
 342  		panic("unsupported access bits")
 343  	}
 344  	var format gl.Enum
 345  	switch f {
 346  	case driver.TextureFormatRGBA8:
 347  		format = gl.RGBA8
 348  	default:
 349  		panic("unsupported format")
 350  	}
 351  	b.funcs.BindImageTexture(unit, t.obj, 0, false, 0, acc, format)
 352  }
 353  
 354  func (b *Backend) bindTexture(unit int, t *gpuTexture) {
 355  	if b.state.texUnits[unit] != t {
 356  		b.funcs.ActiveTexture(gl.TEXTURE0 + gl.Enum(unit))
 357  		b.funcs.BindTexture(gl.TEXTURE_2D, t.obj)
 358  		b.state.texUnits[unit] = t
 359  	}
 360  }
 361  
 362  func (b *Backend) useProgram(p *gpuProgram) {
 363  	if b.state.prog != p {
 364  		p.backend.funcs.UseProgram(p.obj)
 365  		b.state.prog = p
 366  	}
 367  }
 368  
 369  func (b *Backend) enableVertexArrays(n int) {
 370  	// Enable needed arrays.
 371  	for i := b.state.nattr; i < n; i++ {
 372  		b.funcs.EnableVertexAttribArray(gl.Attrib(i))
 373  	}
 374  	// Disable extra arrays.
 375  	for i := n; i < b.state.nattr; i++ {
 376  		b.funcs.DisableVertexAttribArray(gl.Attrib(i))
 377  	}
 378  	b.state.nattr = n
 379  }
 380  
 381  func (b *Backend) SetDepthTest(enable bool) {
 382  	if enable {
 383  		b.funcs.Enable(gl.DEPTH_TEST)
 384  	} else {
 385  		b.funcs.Disable(gl.DEPTH_TEST)
 386  	}
 387  }
 388  
 389  func (b *Backend) BlendFunc(sfactor, dfactor driver.BlendFactor) {
 390  	b.funcs.BlendFunc(toGLBlendFactor(sfactor), toGLBlendFactor(dfactor))
 391  }
 392  
 393  func toGLBlendFactor(f driver.BlendFactor) gl.Enum {
 394  	switch f {
 395  	case driver.BlendFactorOne:
 396  		return gl.ONE
 397  	case driver.BlendFactorOneMinusSrcAlpha:
 398  		return gl.ONE_MINUS_SRC_ALPHA
 399  	case driver.BlendFactorZero:
 400  		return gl.ZERO
 401  	case driver.BlendFactorDstColor:
 402  		return gl.DST_COLOR
 403  	default:
 404  		panic("unsupported blend factor")
 405  	}
 406  }
 407  
 408  func (b *Backend) DepthMask(mask bool) {
 409  	b.funcs.DepthMask(mask)
 410  }
 411  
 412  func (b *Backend) SetBlend(enable bool) {
 413  	if enable {
 414  		b.funcs.Enable(gl.BLEND)
 415  	} else {
 416  		b.funcs.Disable(gl.BLEND)
 417  	}
 418  }
 419  
 420  func (b *Backend) DrawElements(mode driver.DrawMode, off, count int) {
 421  	b.prepareDraw()
 422  	// off is in 16-bit indices, but DrawElements take a byte offset.
 423  	byteOff := off * 2
 424  	b.funcs.DrawElements(toGLDrawMode(mode), count, gl.UNSIGNED_SHORT, byteOff)
 425  }
 426  
 427  func (b *Backend) DrawArrays(mode driver.DrawMode, off, count int) {
 428  	b.prepareDraw()
 429  	b.funcs.DrawArrays(toGLDrawMode(mode), off, count)
 430  }
 431  
 432  func (b *Backend) prepareDraw() {
 433  	nattr := b.state.prog.nattr
 434  	b.enableVertexArrays(nattr)
 435  	if nattr > 0 {
 436  		b.setupVertexArrays()
 437  	}
 438  	if p := b.state.prog; p != nil {
 439  		p.updateUniforms()
 440  	}
 441  }
 442  
 443  func toGLDrawMode(mode driver.DrawMode) gl.Enum {
 444  	switch mode {
 445  	case driver.DrawModeTriangleStrip:
 446  		return gl.TRIANGLE_STRIP
 447  	case driver.DrawModeTriangles:
 448  		return gl.TRIANGLES
 449  	default:
 450  		panic("unsupported draw mode")
 451  	}
 452  }
 453  
 454  func (b *Backend) Viewport(x, y, width, height int) {
 455  	b.funcs.Viewport(x, y, width, height)
 456  }
 457  
 458  func (b *Backend) Clear(colR, colG, colB, colA float32) {
 459  	b.funcs.ClearColor(colR, colG, colB, colA)
 460  	b.funcs.Clear(gl.COLOR_BUFFER_BIT)
 461  }
 462  
 463  func (b *Backend) ClearDepth(d float32) {
 464  	b.funcs.ClearDepthf(d)
 465  	b.funcs.Clear(gl.DEPTH_BUFFER_BIT)
 466  }
 467  
 468  func (b *Backend) DepthFunc(f driver.DepthFunc) {
 469  	var glfunc gl.Enum
 470  	switch f {
 471  	case driver.DepthFuncGreater:
 472  		glfunc = gl.GREATER
 473  	case driver.DepthFuncGreaterEqual:
 474  		glfunc = gl.GEQUAL
 475  	default:
 476  		panic("unsupported depth func")
 477  	}
 478  	b.funcs.DepthFunc(glfunc)
 479  }
 480  
 481  func (b *Backend) NewInputLayout(vs driver.ShaderSources, layout []driver.InputDesc) (driver.InputLayout, error) {
 482  	if len(vs.Inputs) != len(layout) {
 483  		return nil, fmt.Errorf("NewInputLayout: got %d inputs, expected %d", len(layout), len(vs.Inputs))
 484  	}
 485  	for i, inp := range vs.Inputs {
 486  		if exp, got := inp.Size, layout[i].Size; exp != got {
 487  			return nil, fmt.Errorf("NewInputLayout: data size mismatch for %q: got %d expected %d", inp.Name, got, exp)
 488  		}
 489  	}
 490  	return &gpuInputLayout{
 491  		inputs: vs.Inputs,
 492  		layout: layout,
 493  	}, nil
 494  }
 495  
 496  func (b *Backend) NewComputeProgram(src driver.ShaderSources) (driver.Program, error) {
 497  	p, err := gl.CreateComputeProgram(b.funcs, src.GLSL310ES)
 498  	if err != nil {
 499  		return nil, fmt.Errorf("%s: %v", src.Name, err)
 500  	}
 501  	gpuProg := &gpuProgram{
 502  		backend: b,
 503  		obj:     p,
 504  	}
 505  	return gpuProg, nil
 506  }
 507  
 508  func (b *Backend) NewProgram(vertShader, fragShader driver.ShaderSources) (driver.Program, error) {
 509  	attr := make([]string, len(vertShader.Inputs))
 510  	for _, inp := range vertShader.Inputs {
 511  		attr[inp.Location] = inp.Name
 512  	}
 513  	vsrc, fsrc := vertShader.GLSL100ES, fragShader.GLSL100ES
 514  	if b.glver[0] >= 3 {
 515  		// OpenGL (ES) 3.0.
 516  		switch {
 517  		case b.gles:
 518  			vsrc, fsrc = vertShader.GLSL300ES, fragShader.GLSL300ES
 519  		case b.glver[0] >= 4 || b.glver[1] >= 2:
 520  			// OpenGL 3.2 Core only accepts glsl 1.50 or newer.
 521  			vsrc, fsrc = vertShader.GLSL150, fragShader.GLSL150
 522  		default:
 523  			vsrc, fsrc = vertShader.GLSL130, fragShader.GLSL130
 524  		}
 525  	}
 526  	p, err := gl.CreateProgram(b.funcs, vsrc, fsrc, attr)
 527  	if err != nil {
 528  		return nil, err
 529  	}
 530  	gpuProg := &gpuProgram{
 531  		backend: b,
 532  		obj:     p,
 533  		nattr:   len(attr),
 534  	}
 535  	b.BindProgram(gpuProg)
 536  	// Bind texture uniforms.
 537  	for _, tex := range vertShader.Textures {
 538  		u := b.funcs.GetUniformLocation(p, tex.Name)
 539  		if u.Valid() {
 540  			b.funcs.Uniform1i(u, tex.Binding)
 541  		}
 542  	}
 543  	for _, tex := range fragShader.Textures {
 544  		u := b.funcs.GetUniformLocation(p, tex.Name)
 545  		if u.Valid() {
 546  			b.funcs.Uniform1i(u, tex.Binding)
 547  		}
 548  	}
 549  	if b.ubo {
 550  		for _, block := range vertShader.Uniforms.Blocks {
 551  			blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name)
 552  			if blockIdx != gl.INVALID_INDEX {
 553  				b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding))
 554  			}
 555  		}
 556  		// To match Direct3D 11 with separate vertex and fragment
 557  		// shader uniform buffers, offset all fragment blocks to be
 558  		// located after the vertex blocks.
 559  		off := len(vertShader.Uniforms.Blocks)
 560  		for _, block := range fragShader.Uniforms.Blocks {
 561  			blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name)
 562  			if blockIdx != gl.INVALID_INDEX {
 563  				b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding+off))
 564  			}
 565  		}
 566  	} else {
 567  		gpuProg.vertUniforms.setup(b.funcs, p, vertShader.Uniforms.Size, vertShader.Uniforms.Locations)
 568  		gpuProg.fragUniforms.setup(b.funcs, p, fragShader.Uniforms.Size, fragShader.Uniforms.Locations)
 569  	}
 570  	return gpuProg, nil
 571  }
 572  
 573  func lookupUniform(funcs *gl.Functions, p gl.Program, loc driver.UniformLocation) uniformLocation {
 574  	u := funcs.GetUniformLocation(p, loc.Name)
 575  	if !u.Valid() {
 576  		panic(fmt.Errorf("uniform %q not found", loc.Name))
 577  	}
 578  	return uniformLocation{uniform: u, offset: loc.Offset, typ: loc.Type, size: loc.Size}
 579  }
 580  
 581  func (p *gpuProgram) SetStorageBuffer(binding int, buffer driver.Buffer) {
 582  	buf := buffer.(*gpuBuffer)
 583  	if buf.typ&driver.BufferBindingShaderStorage == 0 {
 584  		panic("not a shader storage buffer")
 585  	}
 586  	p.storage[binding] = buf
 587  }
 588  
 589  func (p *gpuProgram) SetVertexUniforms(buffer driver.Buffer) {
 590  	p.vertUniforms.setBuffer(buffer)
 591  }
 592  
 593  func (p *gpuProgram) SetFragmentUniforms(buffer driver.Buffer) {
 594  	p.fragUniforms.setBuffer(buffer)
 595  }
 596  
 597  func (p *gpuProgram) updateUniforms() {
 598  	f := p.backend.funcs
 599  	if p.backend.ubo {
 600  		if b := p.vertUniforms.buf; b != nil {
 601  			f.BindBufferBase(gl.UNIFORM_BUFFER, 0, b.obj)
 602  		}
 603  		if b := p.fragUniforms.buf; b != nil {
 604  			f.BindBufferBase(gl.UNIFORM_BUFFER, 1, b.obj)
 605  		}
 606  	} else {
 607  		p.vertUniforms.update(f)
 608  		p.fragUniforms.update(f)
 609  	}
 610  }
 611  
 612  func (b *Backend) BindProgram(prog driver.Program) {
 613  	p := prog.(*gpuProgram)
 614  	b.useProgram(p)
 615  }
 616  
 617  func (p *gpuProgram) Release() {
 618  	p.backend.funcs.DeleteProgram(p.obj)
 619  }
 620  
 621  func (u *uniformsTracker) setup(funcs *gl.Functions, p gl.Program, uniformSize int, uniforms []driver.UniformLocation) {
 622  	u.locs = make([]uniformLocation, len(uniforms))
 623  	for i, uniform := range uniforms {
 624  		u.locs[i] = lookupUniform(funcs, p, uniform)
 625  	}
 626  	u.size = uniformSize
 627  }
 628  
 629  func (u *uniformsTracker) setBuffer(buffer driver.Buffer) {
 630  	buf := buffer.(*gpuBuffer)
 631  	if buf.typ&driver.BufferBindingUniforms == 0 {
 632  		panic("not a uniform buffer")
 633  	}
 634  	if buf.size < u.size {
 635  		panic(fmt.Errorf("uniform buffer too small, got %d need %d", buf.size, u.size))
 636  	}
 637  	u.buf = buf
 638  	// Force update.
 639  	u.version = buf.version - 1
 640  }
 641  
 642  func (p *uniformsTracker) update(funcs *gl.Functions) {
 643  	b := p.buf
 644  	if b == nil || b.version == p.version {
 645  		return
 646  	}
 647  	p.version = b.version
 648  	data := b.data
 649  	for _, u := range p.locs {
 650  		data := data[u.offset:]
 651  		switch {
 652  		case u.typ == driver.DataTypeFloat && u.size == 1:
 653  			data := data[:4]
 654  			v := *(*[1]float32)(unsafe.Pointer(&data[0]))
 655  			funcs.Uniform1f(u.uniform, v[0])
 656  		case u.typ == driver.DataTypeFloat && u.size == 2:
 657  			data := data[:8]
 658  			v := *(*[2]float32)(unsafe.Pointer(&data[0]))
 659  			funcs.Uniform2f(u.uniform, v[0], v[1])
 660  		case u.typ == driver.DataTypeFloat && u.size == 3:
 661  			data := data[:12]
 662  			v := *(*[3]float32)(unsafe.Pointer(&data[0]))
 663  			funcs.Uniform3f(u.uniform, v[0], v[1], v[2])
 664  		case u.typ == driver.DataTypeFloat && u.size == 4:
 665  			data := data[:16]
 666  			v := *(*[4]float32)(unsafe.Pointer(&data[0]))
 667  			funcs.Uniform4f(u.uniform, v[0], v[1], v[2], v[3])
 668  		default:
 669  			panic("unsupported uniform data type or size")
 670  		}
 671  	}
 672  }
 673  
 674  func (b *gpuBuffer) Upload(data []byte) {
 675  	if b.immutable {
 676  		panic("immutable buffer")
 677  	}
 678  	if len(data) > b.size {
 679  		panic("buffer size overflow")
 680  	}
 681  	b.version++
 682  	copy(b.data, data)
 683  	if b.hasBuffer {
 684  		firstBinding := firstBufferType(b.typ)
 685  		b.backend.funcs.BindBuffer(firstBinding, b.obj)
 686  		if len(data) == b.size {
 687  			// the iOS GL implementation doesn't recognize when BufferSubData
 688  			// clears the entire buffer. Tell it and avoid GPU stalls.
 689  			// See also https://github.com/godotengine/godot/issues/23956.
 690  			b.backend.funcs.BufferData(firstBinding, b.size, gl.DYNAMIC_DRAW)
 691  		}
 692  		b.backend.funcs.BufferSubData(firstBinding, 0, data)
 693  	}
 694  }
 695  
 696  func (b *gpuBuffer) Download(data []byte) error {
 697  	if len(data) > b.size {
 698  		panic("buffer size overflow")
 699  	}
 700  	if !b.hasBuffer {
 701  		copy(data, b.data)
 702  		return nil
 703  	}
 704  	firstBinding := firstBufferType(b.typ)
 705  	b.backend.funcs.BindBuffer(firstBinding, b.obj)
 706  	bufferMap := b.backend.funcs.MapBufferRange(firstBinding, 0, len(data), gl.MAP_READ_BIT)
 707  	if bufferMap == nil {
 708  		return fmt.Errorf("MapBufferRange: error %#x", b.backend.funcs.GetError())
 709  	}
 710  	copy(data, bufferMap)
 711  	if !b.backend.funcs.UnmapBuffer(firstBinding) {
 712  		return driver.ErrContentLost
 713  	}
 714  	return nil
 715  }
 716  
 717  func (b *gpuBuffer) Release() {
 718  	if b.hasBuffer {
 719  		b.backend.funcs.DeleteBuffer(b.obj)
 720  		b.hasBuffer = false
 721  	}
 722  }
 723  
 724  func (b *Backend) BindVertexBuffer(buf driver.Buffer, stride, offset int) {
 725  	gbuf := buf.(*gpuBuffer)
 726  	if gbuf.typ&driver.BufferBindingVertices == 0 {
 727  		panic("not a vertex buffer")
 728  	}
 729  	b.state.buffer = bufferBinding{buf: gbuf, stride: stride, offset: offset}
 730  }
 731  
 732  func (b *Backend) setupVertexArrays() {
 733  	layout := b.state.layout
 734  	if layout == nil {
 735  		return
 736  	}
 737  	buf := b.state.buffer
 738  	b.funcs.BindBuffer(gl.ARRAY_BUFFER, buf.buf.obj)
 739  	for i, inp := range layout.inputs {
 740  		l := layout.layout[i]
 741  		var gltyp gl.Enum
 742  		switch l.Type {
 743  		case driver.DataTypeFloat:
 744  			gltyp = gl.FLOAT
 745  		case driver.DataTypeShort:
 746  			gltyp = gl.SHORT
 747  		default:
 748  			panic("unsupported data type")
 749  		}
 750  		b.funcs.VertexAttribPointer(gl.Attrib(inp.Location), l.Size, gltyp, false, buf.stride, buf.offset+l.Offset)
 751  	}
 752  }
 753  
 754  func (b *Backend) BindIndexBuffer(buf driver.Buffer) {
 755  	gbuf := buf.(*gpuBuffer)
 756  	if gbuf.typ&driver.BufferBindingIndices == 0 {
 757  		panic("not an index buffer")
 758  	}
 759  	b.funcs.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gbuf.obj)
 760  }
 761  
 762  func (b *Backend) BlitFramebuffer(dst, src driver.Framebuffer, srect, drect image.Rectangle) {
 763  	b.funcs.BindFramebuffer(gl.DRAW_FRAMEBUFFER, dst.(*gpuFramebuffer).obj)
 764  	b.funcs.BindFramebuffer(gl.READ_FRAMEBUFFER, src.(*gpuFramebuffer).obj)
 765  	b.funcs.BlitFramebuffer(
 766  		srect.Min.X, srect.Min.Y, srect.Max.X, srect.Max.Y,
 767  		drect.Min.X, drect.Min.Y, drect.Max.X, drect.Max.Y,
 768  		gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT|gl.STENCIL_BUFFER_BIT,
 769  		gl.NEAREST)
 770  }
 771  
 772  func (f *gpuFramebuffer) ReadPixels(src image.Rectangle, pixels []byte) error {
 773  	glErr(f.backend.funcs)
 774  	f.backend.BindFramebuffer(f)
 775  	if len(pixels) < src.Dx()*src.Dy()*4 {
 776  		return errors.New("unexpected RGBA size")
 777  	}
 778  	f.backend.funcs.ReadPixels(src.Min.X, src.Min.Y, src.Dx(), src.Dy(), gl.RGBA, gl.UNSIGNED_BYTE, pixels)
 779  	return glErr(f.backend.funcs)
 780  }
 781  
 782  func (b *Backend) BindFramebuffer(fbo driver.Framebuffer) {
 783  	b.funcs.BindFramebuffer(gl.FRAMEBUFFER, fbo.(*gpuFramebuffer).obj)
 784  }
 785  
 786  func (f *gpuFramebuffer) Invalidate() {
 787  	f.backend.BindFramebuffer(f)
 788  	f.backend.funcs.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0)
 789  }
 790  
 791  func (f *gpuFramebuffer) Release() {
 792  	if f.foreign {
 793  		panic("framebuffer not created by NewFramebuffer")
 794  	}
 795  	f.backend.funcs.DeleteFramebuffer(f.obj)
 796  	if f.hasDepth {
 797  		f.backend.funcs.DeleteRenderbuffer(f.depthBuf)
 798  	}
 799  }
 800  
 801  func toTexFilter(f driver.TextureFilter) int {
 802  	switch f {
 803  	case driver.FilterNearest:
 804  		return gl.NEAREST
 805  	case driver.FilterLinear:
 806  		return gl.LINEAR
 807  	default:
 808  		panic("unsupported texture filter")
 809  	}
 810  }
 811  
 812  func (b *Backend) BindTexture(unit int, t driver.Texture) {
 813  	b.bindTexture(unit, t.(*gpuTexture))
 814  }
 815  
 816  func (t *gpuTexture) Release() {
 817  	t.backend.funcs.DeleteTexture(t.obj)
 818  }
 819  
 820  func (t *gpuTexture) Upload(offset, size image.Point, pixels []byte) {
 821  	if min := size.X * size.Y * 4; min > len(pixels) {
 822  		panic(fmt.Errorf("size %d larger than data %d", min, len(pixels)))
 823  	}
 824  	t.backend.BindTexture(0, t)
 825  	t.backend.funcs.TexSubImage2D(gl.TEXTURE_2D, 0, offset.X, offset.Y, size.X, size.Y, t.triple.format, t.triple.typ, pixels)
 826  }
 827  
 828  func (t *gpuTimer) Begin() {
 829  	t.funcs.BeginQuery(gl.TIME_ELAPSED_EXT, t.obj)
 830  }
 831  
 832  func (t *gpuTimer) End() {
 833  	t.funcs.EndQuery(gl.TIME_ELAPSED_EXT)
 834  }
 835  
 836  func (t *gpuTimer) ready() bool {
 837  	return t.funcs.GetQueryObjectuiv(t.obj, gl.QUERY_RESULT_AVAILABLE) == gl.TRUE
 838  }
 839  
 840  func (t *gpuTimer) Release() {
 841  	t.funcs.DeleteQuery(t.obj)
 842  }
 843  
 844  func (t *gpuTimer) Duration() (time.Duration, bool) {
 845  	if !t.ready() {
 846  		return 0, false
 847  	}
 848  	nanos := t.funcs.GetQueryObjectuiv(t.obj, gl.QUERY_RESULT)
 849  	return time.Duration(nanos), true
 850  }
 851  
 852  func (b *Backend) BindInputLayout(l driver.InputLayout) {
 853  	b.state.layout = l.(*gpuInputLayout)
 854  }
 855  
 856  func (l *gpuInputLayout) Release() {}
 857  
 858  // floatTripleFor determines the best texture triple for floating point FBOs.
 859  func floatTripleFor(f *gl.Functions, ver [2]int, exts []string) (textureTriple, error) {
 860  	var triples []textureTriple
 861  	if ver[0] >= 3 {
 862  		triples = append(triples, textureTriple{gl.R16F, gl.Enum(gl.RED), gl.Enum(gl.HALF_FLOAT)})
 863  	}
 864  	// According to the OES_texture_half_float specification, EXT_color_buffer_half_float is needed to
 865  	// render to FBOs. However, the Safari WebGL1 implementation does support half-float FBOs but does not
 866  	// report EXT_color_buffer_half_float support. The triples are verified below, so it doesn't matter if we're
 867  	// wrong.
 868  	if hasExtension(exts, "GL_OES_texture_half_float") || hasExtension(exts, "GL_EXT_color_buffer_half_float") {
 869  		// Try single channel.
 870  		triples = append(triples, textureTriple{gl.LUMINANCE, gl.Enum(gl.LUMINANCE), gl.Enum(gl.HALF_FLOAT_OES)})
 871  		// Fallback to 4 channels.
 872  		triples = append(triples, textureTriple{gl.RGBA, gl.Enum(gl.RGBA), gl.Enum(gl.HALF_FLOAT_OES)})
 873  	}
 874  	if hasExtension(exts, "GL_OES_texture_float") || hasExtension(exts, "GL_EXT_color_buffer_float") {
 875  		triples = append(triples, textureTriple{gl.RGBA, gl.Enum(gl.RGBA), gl.Enum(gl.FLOAT)})
 876  	}
 877  	tex := f.CreateTexture()
 878  	defer f.DeleteTexture(tex)
 879  	f.BindTexture(gl.TEXTURE_2D, tex)
 880  	f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
 881  	f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
 882  	f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
 883  	f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
 884  	fbo := f.CreateFramebuffer()
 885  	defer f.DeleteFramebuffer(fbo)
 886  	defFBO := gl.Framebuffer(f.GetBinding(gl.FRAMEBUFFER_BINDING))
 887  	f.BindFramebuffer(gl.FRAMEBUFFER, fbo)
 888  	defer f.BindFramebuffer(gl.FRAMEBUFFER, defFBO)
 889  	var attempts []string
 890  	for _, tt := range triples {
 891  		const size = 256
 892  		f.TexImage2D(gl.TEXTURE_2D, 0, tt.internalFormat, size, size, tt.format, tt.typ)
 893  		f.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)
 894  		st := f.CheckFramebufferStatus(gl.FRAMEBUFFER)
 895  		if st == gl.FRAMEBUFFER_COMPLETE {
 896  			return tt, nil
 897  		}
 898  		attempts = append(attempts, fmt.Sprintf("(0x%x, 0x%x, 0x%x): 0x%x", tt.internalFormat, tt.format, tt.typ, st))
 899  	}
 900  	return textureTriple{}, fmt.Errorf("floating point fbos not supported (attempted %s)", attempts)
 901  }
 902  
 903  func srgbaTripleFor(ver [2]int, exts []string) (textureTriple, error) {
 904  	switch {
 905  	case ver[0] >= 3:
 906  		return textureTriple{gl.SRGB8_ALPHA8, gl.Enum(gl.RGBA), gl.Enum(gl.UNSIGNED_BYTE)}, nil
 907  	case hasExtension(exts, "GL_EXT_sRGB"):
 908  		return textureTriple{gl.SRGB_ALPHA_EXT, gl.Enum(gl.SRGB_ALPHA_EXT), gl.Enum(gl.UNSIGNED_BYTE)}, nil
 909  	default:
 910  		return textureTriple{}, errors.New("no sRGB texture formats found")
 911  	}
 912  }
 913  
 914  func alphaTripleFor(ver [2]int) textureTriple {
 915  	intf, f := gl.Enum(gl.R8), gl.Enum(gl.RED)
 916  	if ver[0] < 3 {
 917  		// R8, RED not supported on OpenGL ES 2.0.
 918  		intf, f = gl.LUMINANCE, gl.Enum(gl.LUMINANCE)
 919  	}
 920  	return textureTriple{intf, f, gl.UNSIGNED_BYTE}
 921  }
 922  
 923  func hasExtension(exts []string, ext string) bool {
 924  	for _, e := range exts {
 925  		if ext == e {
 926  			return true
 927  		}
 928  	}
 929  	return false
 930  }
 931  
 932  func firstBufferType(typ driver.BufferBinding) gl.Enum {
 933  	switch {
 934  	case typ&driver.BufferBindingIndices != 0:
 935  		return gl.ELEMENT_ARRAY_BUFFER
 936  	case typ&driver.BufferBindingVertices != 0:
 937  		return gl.ARRAY_BUFFER
 938  	case typ&driver.BufferBindingUniforms != 0:
 939  		return gl.UNIFORM_BUFFER
 940  	case typ&driver.BufferBindingShaderStorage != 0:
 941  		return gl.SHADER_STORAGE_BUFFER
 942  	default:
 943  		panic("unsupported buffer type")
 944  	}
 945  }
 946