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 }