gpu/internal/opengl: restore BeginFrame state in EndFrame

To ease the integration with foreign OpenGL contexts, carefully save the
context state before rendering a frame and restore it afterwards. Gio
rendering can then be mixed with OpenGL code that expects exclusive
control over context state.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-06-10 20:14:32 +02:00
parent 200957f924
commit 9b5e9ae607
9 changed files with 813 additions and 188 deletions
+2
View File
@@ -365,6 +365,8 @@ func New(api API) (GPU, error) {
if err != nil {
return nil, err
}
d.BeginFrame(false, image.Point{})
defer d.EndFrame()
forceCompute := os.Getenv("GIORENDERER") == "forcecompute"
feats := d.Caps().Features
switch {
+476 -110
View File
@@ -12,15 +12,16 @@ import (
"gioui.org/gpu/internal/driver"
"gioui.org/internal/gl"
"gioui.org/internal/srgb"
)
// Backend implements driver.Device.
type Backend struct {
funcs *gl.Functions
clear bool
state glstate
clear bool
glstate glState
state state
savedState glState
glver [2]int
gles bool
@@ -33,27 +34,61 @@ type Backend struct {
alphaTriple textureTriple
srgbaTriple textureTriple
sRGBFBO *srgb.FBO
enabledSRGB bool
defFBO gl.Framebuffer
sRGBFBO *SRGBFBO
// defVertArray is bound during a frame. We don't need it, but
// vertArray is bound during a frame. We don't need it, but
// core desktop OpenGL profile 3.3 requires some array bound.
defVertArray gl.VertexArray
vertArray gl.VertexArray
}
// State tracking.
type glstate struct {
// nattr is the current number of enabled vertex arrays.
nattr int
prog *gpuProgram
texUnits [4]*gpuTexture
layout *gpuInputLayout
buffer bufferBinding
type glState struct {
drawFBO gl.Framebuffer
readFBO gl.Framebuffer
renderBuf gl.Renderbuffer
vertAttribs [5]struct {
obj gl.Buffer
enabled bool
size int
typ gl.Enum
normalized bool
stride int
offset uintptr
}
prog gl.Program
texUnits struct {
active gl.Enum
binds [2]gl.Texture
}
arrayBuf gl.Buffer
elemBuf gl.Buffer
uniBuf gl.Buffer
uniBufs [2]gl.Buffer
storeBuf gl.Buffer
storeBufs [4]gl.Buffer
vertArray gl.VertexArray
depthMask bool
depthFunc gl.Enum
srgb bool
blend struct {
enable bool
srcRGB, dstRGB gl.Enum
srcA, dstA gl.Enum
}
depthTest bool
clearColor [4]float32
clearDepth float32
viewport [4]int
}
type state struct {
prog *gpuProgram
layout *gpuInputLayout
buffer bufferBinding
}
type bufferBinding struct {
buf *gpuBuffer
obj gl.Buffer
offset int
stride int
}
@@ -94,7 +129,6 @@ type gpuBuffer struct {
type gpuProgram struct {
backend *Backend
obj gl.Program
nattr int
vertUniforms uniformsTracker
fragUniforms uniformsTracker
storage [storageBindings]*gpuBuffer
@@ -179,21 +213,21 @@ func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) {
func (b *Backend) BeginFrame(clear bool, viewport image.Point) driver.Framebuffer {
b.clear = clear
// Assume GL state is reset between frames.
b.state = glstate{}
b.defFBO = gl.Framebuffer(b.funcs.GetBinding(gl.FRAMEBUFFER_BINDING))
renderFBO := b.defFBO
b.glstate = b.queryState()
b.savedState = b.glstate
b.state = state{}
renderFBO := b.glstate.drawFBO
if b.gles {
// If the output framebuffer is not in the sRGB colorspace already, emulate it.
var fbEncoding int
if !b.defFBO.Valid() {
if !renderFBO.Valid() {
fbEncoding = b.funcs.GetFramebufferAttachmentParameteri(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)
} else {
fbEncoding = b.funcs.GetFramebufferAttachmentParameteri(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)
}
if fbEncoding == gl.LINEAR {
if fbEncoding == gl.LINEAR && viewport != (image.Point{}) {
if b.sRGBFBO == nil {
sfbo, err := srgb.New(b.funcs)
sfbo, err := NewSRGBFBO(b.funcs, &b.glstate)
if err != nil {
panic(err)
}
@@ -205,16 +239,13 @@ func (b *Backend) BeginFrame(clear bool, viewport image.Point) driver.Framebuffe
renderFBO = b.sRGBFBO.Framebuffer()
}
} else {
b.enabledSRGB = !b.funcs.IsEnabled(gl.FRAMEBUFFER_SRGB)
if b.enabledSRGB {
b.funcs.Enable(gl.FRAMEBUFFER_SRGB)
b.glstate.set(b.funcs, gl.FRAMEBUFFER_SRGB, true)
if !b.vertArray.Valid() {
b.vertArray = b.funcs.CreateVertexArray()
}
if !b.defVertArray.Valid() {
b.defVertArray = b.funcs.CreateVertexArray()
}
b.funcs.BindVertexArray(b.defVertArray)
b.glstate.bindVertexArray(b.funcs, b.vertArray)
}
b.funcs.BindFramebuffer(gl.FRAMEBUFFER, renderFBO)
b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, renderFBO)
if b.sRGBFBO != nil && !clear {
b.Clear(0, 0, 0, 0)
}
@@ -222,9 +253,8 @@ func (b *Backend) BeginFrame(clear bool, viewport image.Point) driver.Framebuffe
}
func (b *Backend) EndFrame() {
b.funcs.ActiveTexture(gl.TEXTURE0)
if b.sRGBFBO != nil {
b.funcs.BindFramebuffer(gl.FRAMEBUFFER, b.defFBO)
b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, b.savedState.drawFBO)
if b.clear {
b.SetBlend(false)
} else {
@@ -233,15 +263,376 @@ func (b *Backend) EndFrame() {
}
b.sRGBFBO.Blit()
}
b.SetBlend(false)
b.funcs.BindFramebuffer(gl.FRAMEBUFFER, b.defFBO)
if b.enabledSRGB {
b.funcs.Disable(gl.FRAMEBUFFER_SRGB)
}
b.restoreState(b.savedState)
// For single-buffered framebuffers such as on macOS.
b.funcs.Flush()
}
func (b *Backend) queryState() glState {
s := glState{
prog: gl.Program(b.funcs.GetBinding(gl.CURRENT_PROGRAM)),
arrayBuf: gl.Buffer(b.funcs.GetBinding(gl.ARRAY_BUFFER_BINDING)),
elemBuf: gl.Buffer(b.funcs.GetBinding(gl.ELEMENT_ARRAY_BUFFER_BINDING)),
drawFBO: gl.Framebuffer(b.funcs.GetBinding(gl.FRAMEBUFFER_BINDING)),
depthMask: b.funcs.GetInteger(gl.DEPTH_WRITEMASK) != gl.FALSE,
depthTest: b.funcs.IsEnabled(gl.DEPTH_TEST),
depthFunc: gl.Enum(b.funcs.GetInteger(gl.DEPTH_FUNC)),
clearDepth: b.funcs.GetFloat(gl.DEPTH_CLEAR_VALUE),
clearColor: b.funcs.GetFloat4(gl.COLOR_CLEAR_VALUE),
viewport: b.funcs.GetInteger4(gl.VIEWPORT),
}
s.blend.enable = b.funcs.IsEnabled(gl.BLEND)
s.blend.srcRGB = gl.Enum(b.funcs.GetInteger(gl.BLEND_SRC_RGB))
s.blend.dstRGB = gl.Enum(b.funcs.GetInteger(gl.BLEND_DST_RGB))
s.blend.srcA = gl.Enum(b.funcs.GetInteger(gl.BLEND_SRC_ALPHA))
s.blend.dstA = gl.Enum(b.funcs.GetInteger(gl.BLEND_DST_ALPHA))
s.texUnits.active = gl.Enum(b.funcs.GetInteger(gl.ACTIVE_TEXTURE))
if !b.gles {
s.srgb = b.funcs.IsEnabled(gl.FRAMEBUFFER_SRGB)
}
if !b.gles || b.glver[0] >= 3 {
s.vertArray = gl.VertexArray(b.funcs.GetBinding(gl.VERTEX_ARRAY_BINDING))
s.readFBO = gl.Framebuffer(b.funcs.GetBinding(gl.READ_FRAMEBUFFER_BINDING))
s.uniBuf = gl.Buffer(b.funcs.GetBinding(gl.UNIFORM_BUFFER_BINDING))
for i := range s.uniBufs {
s.uniBufs[i] = gl.Buffer(b.funcs.GetBindingi(gl.UNIFORM_BUFFER_BINDING, i))
}
}
if b.gles && (b.glver[0] > 3 || (b.glver[0] == 3 && b.glver[1] >= 1)) {
s.storeBuf = gl.Buffer(b.funcs.GetBinding(gl.SHADER_STORAGE_BUFFER_BINDING))
for i := range s.storeBufs {
s.storeBufs[i] = gl.Buffer(b.funcs.GetBindingi(gl.SHADER_STORAGE_BUFFER_BINDING, i))
}
}
for i := range s.texUnits.binds {
s.activeTexture(b.funcs, gl.TEXTURE0+gl.Enum(i))
s.texUnits.binds[i] = gl.Texture(b.funcs.GetBinding(gl.TEXTURE_BINDING_2D))
}
for i := range s.vertAttribs {
a := &s.vertAttribs[i]
a.enabled = b.funcs.GetVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_ENABLED) != gl.FALSE
a.obj = gl.Buffer(b.funcs.GetVertexAttribBinding(i, gl.VERTEX_ATTRIB_ARRAY_ENABLED))
a.size = b.funcs.GetVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_SIZE)
a.typ = gl.Enum(b.funcs.GetVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_TYPE))
a.normalized = b.funcs.GetVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED) != gl.FALSE
a.stride = b.funcs.GetVertexAttrib(i, gl.VERTEX_ATTRIB_ARRAY_STRIDE)
a.offset = b.funcs.GetVertexAttribPointer(i, gl.VERTEX_ATTRIB_ARRAY_POINTER)
}
return s
}
func (b *Backend) restoreState(dst glState) {
src := b.glstate
f := b.funcs
for i, unit := range dst.texUnits.binds {
src.bindTexture(f, i, unit)
}
src.activeTexture(f, dst.texUnits.active)
src.bindFramebuffer(f, gl.FRAMEBUFFER, dst.drawFBO)
src.bindFramebuffer(f, gl.READ_FRAMEBUFFER, dst.readFBO)
src.set(f, gl.BLEND, dst.blend.enable)
bf := dst.blend
src.setBlendFuncSeparate(f, bf.srcRGB, bf.dstRGB, bf.srcA, bf.dstA)
src.set(f, gl.DEPTH_TEST, dst.depthTest)
src.setDepthFunc(f, dst.depthFunc)
src.set(f, gl.FRAMEBUFFER_SRGB, dst.srgb)
src.bindVertexArray(f, dst.vertArray)
src.useProgram(f, dst.prog)
src.bindBuffer(f, gl.ELEMENT_ARRAY_BUFFER, dst.elemBuf)
for i, b := range dst.uniBufs {
src.bindBufferBase(f, gl.UNIFORM_BUFFER, i, b)
}
src.bindBuffer(f, gl.UNIFORM_BUFFER, dst.uniBuf)
for i, b := range dst.storeBufs {
src.bindBufferBase(f, gl.SHADER_STORAGE_BUFFER, i, b)
}
src.bindBuffer(f, gl.SHADER_STORAGE_BUFFER, dst.storeBuf)
src.setDepthMask(f, dst.depthMask)
src.setClearDepth(f, dst.clearDepth)
col := dst.clearColor
src.setClearColor(f, col[0], col[1], col[2], col[3])
for i, attr := range dst.vertAttribs {
src.setVertexAttribArray(f, i, attr.enabled)
src.vertexAttribPointer(f, attr.obj, i, attr.size, attr.typ, attr.normalized, attr.stride, int(attr.offset))
}
src.bindBuffer(f, gl.ARRAY_BUFFER, dst.arrayBuf)
v := dst.viewport
src.setViewport(f, v[0], v[1], v[2], v[3])
}
func (s *glState) setVertexAttribArray(f *gl.Functions, idx int, enabled bool) {
a := &s.vertAttribs[idx]
if enabled != a.enabled {
if enabled {
f.EnableVertexAttribArray(gl.Attrib(idx))
} else {
f.DisableVertexAttribArray(gl.Attrib(idx))
}
a.enabled = enabled
}
}
func (s *glState) vertexAttribPointer(f *gl.Functions, buf gl.Buffer, idx, size int, typ gl.Enum, normalized bool, stride, offset int) {
s.bindBuffer(f, gl.ARRAY_BUFFER, buf)
a := &s.vertAttribs[idx]
a.obj = buf
a.size = size
a.typ = typ
a.normalized = normalized
a.stride = stride
a.offset = uintptr(offset)
f.VertexAttribPointer(gl.Attrib(idx), a.size, a.typ, a.normalized, a.stride, int(a.offset))
}
func (s *glState) activeTexture(f *gl.Functions, unit gl.Enum) {
if unit != s.texUnits.active {
f.ActiveTexture(unit)
s.texUnits.active = unit
}
}
func (s *glState) bindRenderbuffer(f *gl.Functions, target gl.Enum, r gl.Renderbuffer) {
if !r.Equal(s.renderBuf) {
f.BindRenderbuffer(gl.RENDERBUFFER, r)
s.renderBuf = r
}
}
func (s *glState) bindTexture(f *gl.Functions, unit int, t gl.Texture) {
s.activeTexture(f, gl.TEXTURE0+gl.Enum(unit))
if !t.Equal(s.texUnits.binds[unit]) {
f.BindTexture(gl.TEXTURE_2D, t)
s.texUnits.binds[unit] = t
}
}
func (s *glState) bindVertexArray(f *gl.Functions, a gl.VertexArray) {
if !a.Equal(s.vertArray) {
f.BindVertexArray(a)
s.vertArray = a
}
}
func (s *glState) deleteRenderbuffer(f *gl.Functions, r gl.Renderbuffer) {
f.DeleteRenderbuffer(r)
if r.Equal(s.renderBuf) {
s.renderBuf = gl.Renderbuffer{}
}
}
func (s *glState) deleteFramebuffer(f *gl.Functions, fbo gl.Framebuffer) {
f.DeleteFramebuffer(fbo)
if fbo.Equal(s.drawFBO) {
s.drawFBO = gl.Framebuffer{}
}
if fbo.Equal(s.readFBO) {
s.readFBO = gl.Framebuffer{}
}
}
func (s *glState) deleteBuffer(f *gl.Functions, b gl.Buffer) {
f.DeleteBuffer(b)
if b.Equal(s.arrayBuf) {
s.arrayBuf = gl.Buffer{}
}
if b.Equal(s.elemBuf) {
s.elemBuf = gl.Buffer{}
}
if b.Equal(s.uniBuf) {
s.uniBuf = gl.Buffer{}
}
if b.Equal(s.storeBuf) {
s.uniBuf = gl.Buffer{}
}
for i, b2 := range s.storeBufs {
if b.Equal(b2) {
s.storeBufs[i] = gl.Buffer{}
}
}
for i, b2 := range s.uniBufs {
if b.Equal(b2) {
s.uniBufs[i] = gl.Buffer{}
}
}
}
func (s *glState) deleteProgram(f *gl.Functions, p gl.Program) {
f.DeleteProgram(p)
if p.Equal(s.prog) {
s.prog = gl.Program{}
}
}
func (s *glState) deleteVertexArray(f *gl.Functions, a gl.VertexArray) {
f.DeleteVertexArray(a)
if a.Equal(s.vertArray) {
s.vertArray = gl.VertexArray{}
}
}
func (s *glState) deleteTexture(f *gl.Functions, t gl.Texture) {
f.DeleteTexture(t)
binds := &s.texUnits.binds
for i, obj := range binds {
if t.Equal(obj) {
binds[i] = gl.Texture{}
}
}
}
func (s *glState) useProgram(f *gl.Functions, p gl.Program) {
if !p.Equal(s.prog) {
f.UseProgram(p)
s.prog = p
}
}
func (s *glState) bindFramebuffer(f *gl.Functions, target gl.Enum, fbo gl.Framebuffer) {
switch target {
case gl.FRAMEBUFFER:
if fbo.Equal(s.drawFBO) && fbo.Equal(s.readFBO) {
return
}
s.drawFBO = fbo
s.readFBO = fbo
case gl.READ_FRAMEBUFFER:
if fbo.Equal(s.readFBO) {
return
}
s.readFBO = fbo
case gl.DRAW_FRAMEBUFFER:
if fbo.Equal(s.drawFBO) {
return
}
s.drawFBO = fbo
default:
panic("unknown target")
}
f.BindFramebuffer(target, fbo)
}
func (s *glState) bindBufferBase(f *gl.Functions, target gl.Enum, idx int, buf gl.Buffer) {
switch target {
case gl.UNIFORM_BUFFER:
if buf.Equal(s.uniBuf) && buf.Equal(s.uniBufs[idx]) {
return
}
s.uniBuf = buf
s.uniBufs[idx] = buf
case gl.SHADER_STORAGE_BUFFER:
if buf.Equal(s.storeBuf) && buf.Equal(s.storeBufs[idx]) {
return
}
s.storeBuf = buf
s.storeBufs[idx] = buf
default:
panic("unknown buffer target")
}
f.BindBufferBase(target, idx, buf)
}
func (s *glState) bindBuffer(f *gl.Functions, target gl.Enum, buf gl.Buffer) {
switch target {
case gl.ARRAY_BUFFER:
if buf.Equal(s.arrayBuf) {
return
}
s.arrayBuf = buf
case gl.ELEMENT_ARRAY_BUFFER:
if buf.Equal(s.elemBuf) {
return
}
s.elemBuf = buf
case gl.UNIFORM_BUFFER:
if buf.Equal(s.uniBuf) {
return
}
s.uniBuf = buf
case gl.SHADER_STORAGE_BUFFER:
if buf.Equal(s.storeBuf) {
return
}
s.storeBuf = buf
default:
panic("unknown buffer target")
}
f.BindBuffer(target, buf)
}
func (s *glState) setClearDepth(f *gl.Functions, d float32) {
if d != s.clearDepth {
f.ClearDepthf(d)
s.clearDepth = d
}
}
func (s *glState) setClearColor(f *gl.Functions, r, g, b, a float32) {
col := [4]float32{r, g, b, a}
if col != s.clearColor {
f.ClearColor(r, g, b, a)
s.clearColor = col
}
}
func (s *glState) setViewport(f *gl.Functions, x, y, width, height int) {
view := [4]int{x, y, width, height}
if view != s.viewport {
f.Viewport(x, y, width, height)
s.viewport = view
}
}
func (s *glState) setDepthFunc(f *gl.Functions, df gl.Enum) {
if df != s.depthFunc {
f.DepthFunc(df)
s.depthFunc = df
}
}
func (s *glState) setBlendFuncSeparate(f *gl.Functions, srcRGB, dstRGB, srcA, dstA gl.Enum) {
if srcRGB != s.blend.srcRGB || dstRGB != s.blend.dstRGB || srcA != s.blend.srcA || dstA != s.blend.dstA {
s.blend.srcRGB = srcRGB
s.blend.dstRGB = dstRGB
s.blend.srcA = srcA
s.blend.dstA = dstA
f.BlendFuncSeparate(srcA, dstA, srcA, dstA)
}
}
func (s *glState) setDepthMask(f *gl.Functions, enable bool) {
if enable != s.depthMask {
f.DepthMask(enable)
s.depthMask = enable
}
}
func (s *glState) set(f *gl.Functions, target gl.Enum, enable bool) {
switch target {
case gl.FRAMEBUFFER_SRGB:
if s.srgb == enable {
return
}
s.srgb = enable
case gl.BLEND:
if enable == s.blend.enable {
return
}
s.blend.enable = enable
case gl.DEPTH_TEST:
if enable == s.depthTest {
return
}
s.depthTest = enable
default:
panic("unknown enable")
}
if enable {
f.Enable(target)
} else {
f.Disable(target)
}
}
func (b *Backend) Caps() driver.Caps {
return b.feats
}
@@ -277,7 +668,7 @@ func (b *Backend) NewFramebuffer(tex driver.Texture, depthBits int) (driver.Fram
size = gl.DEPTH_COMPONENT24
}
depthBuf := b.funcs.CreateRenderbuffer()
b.funcs.BindRenderbuffer(gl.RENDERBUFFER, depthBuf)
b.glstate.bindRenderbuffer(b.funcs, gl.RENDERBUFFER, depthBuf)
b.funcs.RenderbufferStorage(gl.RENDERBUFFER, size, gltex.width, gltex.height)
b.funcs.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuf)
fbo.depthBuf = depthBuf
@@ -345,7 +736,7 @@ func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer,
return nil, err
}
firstBinding := firstBufferType(typ)
b.funcs.BindBuffer(firstBinding, buf.obj)
b.glstate.bindBuffer(b.funcs, firstBinding, buf.obj)
b.funcs.BufferData(firstBinding, size, gl.DYNAMIC_DRAW)
}
return buf, nil
@@ -356,7 +747,7 @@ func (b *Backend) NewImmutableBuffer(typ driver.BufferBinding, data []byte) (dri
obj := b.funcs.CreateBuffer()
buf := &gpuBuffer{backend: b, obj: obj, typ: typ, size: len(data), hasBuffer: true}
firstBinding := firstBufferType(typ)
b.funcs.BindBuffer(firstBinding, buf.obj)
b.glstate.bindBuffer(b.funcs, firstBinding, buf.obj)
b.funcs.BufferData(firstBinding, len(data), gl.STATIC_DRAW)
buf.Upload(data)
buf.immutable = true
@@ -378,8 +769,8 @@ func (b *Backend) Release() {
if b.sRGBFBO != nil {
b.sRGBFBO.Release()
}
if b.defVertArray.Valid() {
b.funcs.DeleteVertexArray(b.defVertArray)
if b.vertArray.Valid() {
b.glstate.deleteVertexArray(b.funcs, b.vertArray)
}
*b = Backend{}
}
@@ -392,7 +783,7 @@ func (b *Backend) DispatchCompute(x, y, z int) {
if p := b.state.prog; p != nil {
for binding, buf := range p.storage {
if buf != nil {
b.funcs.BindBufferBase(gl.SHADER_STORAGE_BUFFER, binding, buf.obj)
b.glstate.bindBufferBase(b.funcs, gl.SHADER_STORAGE_BUFFER, binding, buf.obj)
}
}
}
@@ -420,43 +811,18 @@ func (b *Backend) BindImageTexture(unit int, tex driver.Texture, access driver.A
b.funcs.BindImageTexture(unit, t.obj, 0, false, 0, acc, format)
}
func (b *Backend) bindTexture(unit int, t *gpuTexture) {
if b.state.texUnits[unit] != t {
b.funcs.ActiveTexture(gl.TEXTURE0 + gl.Enum(unit))
b.funcs.BindTexture(gl.TEXTURE_2D, t.obj)
b.state.texUnits[unit] = t
}
}
func (b *Backend) useProgram(p *gpuProgram) {
if b.state.prog != p {
p.backend.funcs.UseProgram(p.obj)
b.state.prog = p
}
}
func (b *Backend) enableVertexArrays(n int) {
// Enable needed arrays.
for i := b.state.nattr; i < n; i++ {
b.funcs.EnableVertexAttribArray(gl.Attrib(i))
}
// Disable extra arrays.
for i := n; i < b.state.nattr; i++ {
b.funcs.DisableVertexAttribArray(gl.Attrib(i))
}
b.state.nattr = n
b.glstate.useProgram(b.funcs, p.obj)
b.state.prog = p
}
func (b *Backend) SetDepthTest(enable bool) {
if enable {
b.funcs.Enable(gl.DEPTH_TEST)
} else {
b.funcs.Disable(gl.DEPTH_TEST)
}
b.glstate.set(b.funcs, gl.DEPTH_TEST, enable)
}
func (b *Backend) BlendFunc(sfactor, dfactor driver.BlendFactor) {
b.funcs.BlendFunc(toGLBlendFactor(sfactor), toGLBlendFactor(dfactor))
src, dst := toGLBlendFactor(sfactor), toGLBlendFactor(dfactor)
b.glstate.setBlendFuncSeparate(b.funcs, src, dst, src, dst)
}
func toGLBlendFactor(f driver.BlendFactor) gl.Enum {
@@ -475,15 +841,11 @@ func toGLBlendFactor(f driver.BlendFactor) gl.Enum {
}
func (b *Backend) DepthMask(mask bool) {
b.funcs.DepthMask(mask)
b.glstate.setDepthMask(b.funcs, mask)
}
func (b *Backend) SetBlend(enable bool) {
if enable {
b.funcs.Enable(gl.BLEND)
} else {
b.funcs.Disable(gl.BLEND)
}
b.glstate.set(b.funcs, gl.BLEND, enable)
}
func (b *Backend) DrawElements(mode driver.DrawMode, off, count int) {
@@ -499,14 +861,12 @@ func (b *Backend) DrawArrays(mode driver.DrawMode, off, count int) {
}
func (b *Backend) prepareDraw() {
nattr := b.state.prog.nattr
b.enableVertexArrays(nattr)
if nattr > 0 {
b.setupVertexArrays()
}
if p := b.state.prog; p != nil {
p.updateUniforms()
p := b.state.prog
if p == nil {
return
}
b.setupVertexArrays()
p.updateUniforms()
}
func toGLDrawMode(mode driver.DrawMode) gl.Enum {
@@ -521,16 +881,16 @@ func toGLDrawMode(mode driver.DrawMode) gl.Enum {
}
func (b *Backend) Viewport(x, y, width, height int) {
b.funcs.Viewport(x, y, width, height)
b.glstate.setViewport(b.funcs, x, y, width, height)
}
func (b *Backend) Clear(colR, colG, colB, colA float32) {
b.funcs.ClearColor(colR, colG, colB, colA)
b.glstate.setClearColor(b.funcs, colR, colG, colB, colA)
b.funcs.Clear(gl.COLOR_BUFFER_BIT)
}
func (b *Backend) ClearDepth(d float32) {
b.funcs.ClearDepthf(d)
b.glstate.setClearDepth(b.funcs, d)
b.funcs.Clear(gl.DEPTH_BUFFER_BIT)
}
@@ -544,7 +904,7 @@ func (b *Backend) DepthFunc(f driver.DepthFunc) {
default:
panic("unsupported depth func")
}
b.funcs.DepthFunc(glfunc)
b.glstate.setDepthFunc(b.funcs, glfunc)
}
func (b *Backend) NewInputLayout(vs driver.ShaderSources, layout []driver.InputDesc) (driver.InputLayout, error) {
@@ -599,7 +959,6 @@ func (b *Backend) NewProgram(vertShader, fragShader driver.ShaderSources) (drive
gpuProg := &gpuProgram{
backend: b,
obj: p,
nattr: len(attr),
}
b.BindProgram(gpuProg)
// Bind texture uniforms.
@@ -667,10 +1026,10 @@ func (p *gpuProgram) updateUniforms() {
f := p.backend.funcs
if p.backend.ubo {
if b := p.vertUniforms.buf; b != nil {
f.BindBufferBase(gl.UNIFORM_BUFFER, 0, b.obj)
p.backend.glstate.bindBufferBase(f, gl.UNIFORM_BUFFER, 0, b.obj)
}
if b := p.fragUniforms.buf; b != nil {
f.BindBufferBase(gl.UNIFORM_BUFFER, 1, b.obj)
p.backend.glstate.bindBufferBase(f, gl.UNIFORM_BUFFER, 1, b.obj)
}
} else {
p.vertUniforms.update(f)
@@ -684,7 +1043,7 @@ func (b *Backend) BindProgram(prog driver.Program) {
}
func (p *gpuProgram) Release() {
p.backend.funcs.DeleteProgram(p.obj)
p.backend.glstate.deleteProgram(p.backend.funcs, p.obj)
}
func (u *uniformsTracker) setup(funcs *gl.Functions, p gl.Program, uniformSize int, uniforms []driver.UniformLocation) {
@@ -751,7 +1110,7 @@ func (b *gpuBuffer) Upload(data []byte) {
copy(b.data, data)
if b.hasBuffer {
firstBinding := firstBufferType(b.typ)
b.backend.funcs.BindBuffer(firstBinding, b.obj)
b.backend.glstate.bindBuffer(b.backend.funcs, firstBinding, b.obj)
if len(data) == b.size {
// the iOS GL implementation doesn't recognize when BufferSubData
// clears the entire buffer. Tell it and avoid GPU stalls.
@@ -771,7 +1130,7 @@ func (b *gpuBuffer) Download(data []byte) error {
return nil
}
firstBinding := firstBufferType(b.typ)
b.backend.funcs.BindBuffer(firstBinding, b.obj)
b.backend.glstate.bindBuffer(b.backend.funcs, firstBinding, b.obj)
bufferMap := b.backend.funcs.MapBufferRange(firstBinding, 0, len(data), gl.MAP_READ_BIT)
if bufferMap == nil {
return fmt.Errorf("MapBufferRange: error %#x", b.backend.funcs.GetError())
@@ -785,7 +1144,7 @@ func (b *gpuBuffer) Download(data []byte) error {
func (b *gpuBuffer) Release() {
if b.hasBuffer {
b.backend.funcs.DeleteBuffer(b.obj)
b.backend.glstate.deleteBuffer(b.backend.funcs, b.obj)
b.hasBuffer = false
}
}
@@ -795,7 +1154,7 @@ func (b *Backend) BindVertexBuffer(buf driver.Buffer, stride, offset int) {
if gbuf.typ&driver.BufferBindingVertices == 0 {
panic("not a vertex buffer")
}
b.state.buffer = bufferBinding{buf: gbuf, stride: stride, offset: offset}
b.state.buffer = bufferBinding{obj: gbuf.obj, stride: stride, offset: offset}
}
func (b *Backend) setupVertexArrays() {
@@ -803,8 +1162,9 @@ func (b *Backend) setupVertexArrays() {
if layout == nil {
return
}
const max = len(b.glstate.vertAttribs)
var enabled [max]bool
buf := b.state.buffer
b.funcs.BindBuffer(gl.ARRAY_BUFFER, buf.buf.obj)
for i, inp := range layout.inputs {
l := layout.layout[i]
var gltyp gl.Enum
@@ -816,7 +1176,11 @@ func (b *Backend) setupVertexArrays() {
default:
panic("unsupported data type")
}
b.funcs.VertexAttribPointer(gl.Attrib(inp.Location), l.Size, gltyp, false, buf.stride, buf.offset+l.Offset)
enabled[inp.Location] = true
b.glstate.vertexAttribPointer(b.funcs, buf.obj, inp.Location, l.Size, gltyp, false, buf.stride, buf.offset+l.Offset)
}
for i := 0; i < max; i++ {
b.glstate.setVertexAttribArray(b.funcs, i, enabled[i])
}
}
@@ -825,12 +1189,12 @@ func (b *Backend) BindIndexBuffer(buf driver.Buffer) {
if gbuf.typ&driver.BufferBindingIndices == 0 {
panic("not an index buffer")
}
b.funcs.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gbuf.obj)
b.glstate.bindBuffer(b.funcs, gl.ELEMENT_ARRAY_BUFFER, gbuf.obj)
}
func (b *Backend) BlitFramebuffer(dst, src driver.Framebuffer, srect, drect image.Rectangle) {
b.funcs.BindFramebuffer(gl.DRAW_FRAMEBUFFER, dst.(*gpuFramebuffer).obj)
b.funcs.BindFramebuffer(gl.READ_FRAMEBUFFER, src.(*gpuFramebuffer).obj)
b.glstate.bindFramebuffer(b.funcs, gl.DRAW_FRAMEBUFFER, dst.(*gpuFramebuffer).obj)
b.glstate.bindFramebuffer(b.funcs, gl.READ_FRAMEBUFFER, src.(*gpuFramebuffer).obj)
b.funcs.BlitFramebuffer(
srect.Min.X, srect.Min.Y, srect.Max.X, srect.Max.Y,
drect.Min.X, drect.Min.Y, drect.Max.X, drect.Max.Y,
@@ -849,7 +1213,7 @@ func (f *gpuFramebuffer) ReadPixels(src image.Rectangle, pixels []byte) error {
}
func (b *Backend) BindFramebuffer(fbo driver.Framebuffer) {
b.funcs.BindFramebuffer(gl.FRAMEBUFFER, fbo.(*gpuFramebuffer).obj)
b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, fbo.(*gpuFramebuffer).obj)
}
func (f *gpuFramebuffer) Invalidate() {
@@ -861,9 +1225,9 @@ func (f *gpuFramebuffer) Release() {
if f.foreign {
panic("framebuffer not created by NewFramebuffer")
}
f.backend.funcs.DeleteFramebuffer(f.obj)
f.backend.glstate.deleteFramebuffer(f.backend.funcs, f.obj)
if f.hasDepth {
f.backend.funcs.DeleteRenderbuffer(f.depthBuf)
f.backend.glstate.deleteRenderbuffer(f.backend.funcs, f.depthBuf)
}
}
@@ -879,11 +1243,11 @@ func toTexFilter(f driver.TextureFilter) int {
}
func (b *Backend) BindTexture(unit int, t driver.Texture) {
b.bindTexture(unit, t.(*gpuTexture))
b.glstate.bindTexture(b.funcs, unit, t.(*gpuTexture).obj)
}
func (t *gpuTexture) Release() {
t.backend.funcs.DeleteTexture(t.obj)
t.backend.glstate.deleteTexture(t.backend.funcs, t.obj)
}
func (t *gpuTexture) Upload(offset, size image.Point, pixels []byte) {
@@ -945,6 +1309,8 @@ func floatTripleFor(f *gl.Functions, ver [2]int, exts []string) (textureTriple,
}
tex := f.CreateTexture()
defer f.DeleteTexture(tex)
defTex := gl.Texture(f.GetBinding(gl.TEXTURE_BINDING_2D))
defer f.BindTexture(gl.TEXTURE_2D, defTex)
f.BindTexture(gl.TEXTURE_2D, tex)
f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT
package srgb
package opengl
import (
"errors"
@@ -13,11 +13,12 @@ import (
"gioui.org/internal/gl"
)
// FBO implements an intermediate sRGB FBO
// SRGBFBO implements an intermediate sRGB FBO
// for gamma-correct rendering on platforms without
// sRGB enabled native framebuffers.
type FBO struct {
type SRGBFBO struct {
c *gl.Functions
state *glState
viewport image.Point
srgbBuffer gl.Framebuffer
depthBuffer gl.Renderbuffer
@@ -28,7 +29,7 @@ type FBO struct {
gl3 bool
}
func New(f *gl.Functions) (*FBO, error) {
func NewSRGBFBO(f *gl.Functions, state *glState) (*SRGBFBO, error) {
var gl3 bool
glVer := f.GetString(gl.VERSION)
ver, _, err := gl.ParseGLVersion(glVer)
@@ -43,14 +44,15 @@ func New(f *gl.Functions) (*FBO, error) {
return nil, fmt.Errorf("no support for OpenGL ES 3 nor EXT_sRGB")
}
}
s := &FBO{
s := &SRGBFBO{
c: f,
state: state,
gl3: gl3,
srgbBuffer: f.CreateFramebuffer(),
colorTex: f.CreateTexture(),
depthBuffer: f.CreateRenderbuffer(),
}
f.BindTexture(gl.TEXTURE_2D, s.colorTex)
state.bindTexture(f, 0, s.colorTex)
f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
@@ -58,17 +60,17 @@ func New(f *gl.Functions) (*FBO, error) {
return s, nil
}
func (s *FBO) Blit() {
func (s *SRGBFBO) Blit() {
if !s.blitted {
prog, err := gl.CreateProgram(s.c, blitVSrc, blitFSrc, []string{"pos", "uv"})
if err != nil {
panic(err)
}
s.prog = prog
s.c.UseProgram(prog)
s.state.useProgram(s.c, prog)
s.c.Uniform1i(s.c.GetUniformLocation(prog, "tex"), 0)
s.quad = s.c.CreateBuffer()
s.c.BindBuffer(gl.ARRAY_BUFFER, s.quad)
s.state.bindBuffer(s.c, gl.ARRAY_BUFFER, s.quad)
coords := byteslice.Slice([]float32{
-1, +1, 0, 1,
+1, +1, 1, 1,
@@ -79,27 +81,23 @@ func (s *FBO) Blit() {
s.c.BufferSubData(gl.ARRAY_BUFFER, 0, coords)
s.blitted = true
}
s.c.UseProgram(s.prog)
s.c.BindTexture(gl.TEXTURE_2D, s.colorTex)
s.c.BindBuffer(gl.ARRAY_BUFFER, s.quad)
s.c.VertexAttribPointer(0 /* pos */, 2, gl.FLOAT, false, 4*4, 0)
s.c.VertexAttribPointer(1 /* uv */, 2, gl.FLOAT, false, 4*4, 4*2)
s.c.EnableVertexAttribArray(0)
s.c.EnableVertexAttribArray(1)
s.state.useProgram(s.c, s.prog)
s.state.bindTexture(s.c, 0, s.colorTex)
s.state.vertexAttribPointer(s.c, s.quad, 0 /* pos */, 2, gl.FLOAT, false, 4*4, 0)
s.state.vertexAttribPointer(s.c, s.quad, 1 /* uv */, 2, gl.FLOAT, false, 4*4, 4*2)
s.state.setVertexAttribArray(s.c, 0, true)
s.state.setVertexAttribArray(s.c, 1, true)
s.c.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
s.c.BindTexture(gl.TEXTURE_2D, gl.Texture{})
s.c.DisableVertexAttribArray(0)
s.c.DisableVertexAttribArray(1)
s.c.BindFramebuffer(gl.FRAMEBUFFER, s.srgbBuffer)
s.state.bindFramebuffer(s.c, gl.FRAMEBUFFER, s.srgbBuffer)
s.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0)
s.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT)
}
func (s *FBO) Framebuffer() gl.Framebuffer {
func (s *SRGBFBO) Framebuffer() gl.Framebuffer {
return s.srgbBuffer
}
func (s *FBO) Refresh(viewport image.Point) error {
func (s *SRGBFBO) Refresh(viewport image.Point) error {
if viewport.X == 0 || viewport.Y == 0 {
return errors.New("srgb: zero-sized framebuffer")
}
@@ -107,17 +105,15 @@ func (s *FBO) Refresh(viewport image.Point) error {
return nil
}
s.viewport = viewport
s.c.BindTexture(gl.TEXTURE_2D, s.colorTex)
s.state.bindTexture(s.c, 0, s.colorTex)
if s.gl3 {
s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, viewport.X, viewport.Y, gl.RGBA, gl.UNSIGNED_BYTE)
} else /* EXT_sRGB */ {
s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.SRGB_ALPHA_EXT, viewport.X, viewport.Y, gl.SRGB_ALPHA_EXT, gl.UNSIGNED_BYTE)
}
currentRB := gl.Renderbuffer(s.c.GetBinding(gl.RENDERBUFFER_BINDING))
s.c.BindRenderbuffer(gl.RENDERBUFFER, s.depthBuffer)
s.state.bindRenderbuffer(s.c, gl.RENDERBUFFER, s.depthBuffer)
s.c.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, viewport.X, viewport.Y)
s.c.BindRenderbuffer(gl.RENDERBUFFER, currentRB)
s.c.BindFramebuffer(gl.FRAMEBUFFER, s.srgbBuffer)
s.state.bindFramebuffer(s.c, gl.FRAMEBUFFER, s.srgbBuffer)
s.c.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, s.colorTex, 0)
s.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, s.depthBuffer)
if st := s.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
@@ -128,7 +124,7 @@ func (s *FBO) Refresh(viewport image.Point) error {
// With macOS Safari, rendering to and then reading from a SRGB8_ALPHA8
// texture result in twice gamma corrected colors. Using a plain RGBA
// texture seems to work.
s.c.ClearColor(.5, .5, .5, 1.0)
s.state.setClearColor(s.c, .5, .5, .5, 1.0)
s.c.Clear(gl.COLOR_BUFFER_BIT)
var pixel [4]byte
s.c.ReadPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel[:])
@@ -143,13 +139,13 @@ func (s *FBO) Refresh(viewport image.Point) error {
return nil
}
func (s *FBO) Release() {
s.c.DeleteFramebuffer(s.srgbBuffer)
s.c.DeleteTexture(s.colorTex)
s.c.DeleteRenderbuffer(s.depthBuffer)
func (s *SRGBFBO) Release() {
s.state.deleteFramebuffer(s.c, s.srgbBuffer)
s.state.deleteTexture(s.c, s.colorTex)
s.state.deleteRenderbuffer(s.c, s.depthBuffer)
if s.blitted {
s.c.DeleteBuffer(s.quad)
s.c.DeleteProgram(s.prog)
s.state.deleteBuffer(s.c, s.quad)
s.state.deleteProgram(s.c, s.prog)
}
s.c = nil
}
+26 -1
View File
@@ -8,26 +8,38 @@ type (
)
const (
ACTIVE_TEXTURE = 0x84E0
ALL_BARRIER_BITS = 0xffffffff
ARRAY_BUFFER = 0x8892
ARRAY_BUFFER_BINDING = 0x8894
BACK = 0x0405
BLEND = 0xbe2
BLEND_DST_RGB = 0x80C8
BLEND_SRC_RGB = 0x80C9
BLEND_DST_ALPHA = 0x80CA
BLEND_SRC_ALPHA = 0x80CB
CLAMP_TO_EDGE = 0x812f
COLOR_ATTACHMENT0 = 0x8ce0
COLOR_BUFFER_BIT = 0x4000
COLOR_CLEAR_VALUE = 0x0C22
COMPILE_STATUS = 0x8b81
COMPUTE_SHADER = 0x91B9
DEPTH_BUFFER_BIT = 0x100
CURRENT_PROGRAM = 0x8B8D
DEPTH_ATTACHMENT = 0x8d00
DEPTH_BUFFER_BIT = 0x100
DEPTH_CLEAR_VALUE = 0x0B73
DEPTH_COMPONENT16 = 0x81a5
DEPTH_COMPONENT24 = 0x81A6
DEPTH_COMPONENT32F = 0x8CAC
DEPTH_FUNC = 0x0B74
DEPTH_TEST = 0xb71
DEPTH_WRITEMASK = 0x0B72
DRAW_FRAMEBUFFER = 0x8CA9
DST_COLOR = 0x306
DYNAMIC_DRAW = 0x88E8
DYNAMIC_READ = 0x88E9
ELEMENT_ARRAY_BUFFER = 0x8893
ELEMENT_ARRAY_BUFFER_BINDING = 0x8895
EXTENSIONS = 0x1f03
FALSE = 0
FLOAT = 0x1406
@@ -59,6 +71,7 @@ const (
R16F = 0x822d
R8 = 0x8229
READ_FRAMEBUFFER = 0x8ca8
READ_FRAMEBUFFER_BINDING = 0x8CAA
READ_ONLY = 0x88B8
READ_WRITE = 0x88BA
RED = 0x1903
@@ -71,6 +84,7 @@ const (
RGBA = 0x1908
RGBA8 = 0x8058
SHADER_STORAGE_BUFFER = 0x90D2
SHADER_STORAGE_BUFFER_BINDING = 0x90D3
SHORT = 0x1402
SRGB = 0x8c40
SRGB_ALPHA_EXT = 0x8c42
@@ -79,6 +93,7 @@ const (
STATIC_DRAW = 0x88e4
STENCIL_BUFFER_BIT = 0x00000400
TEXTURE_2D = 0xde1
TEXTURE_BINDING_2D = 0x8069
TEXTURE_MAG_FILTER = 0x2800
TEXTURE_MIN_FILTER = 0x2801
TEXTURE_WRAP_S = 0x2802
@@ -89,11 +104,21 @@ const (
TRIANGLES = 0x4
TRUE = 1
UNIFORM_BUFFER = 0x8A11
UNIFORM_BUFFER_BINDING = 0x8A28
UNPACK_ALIGNMENT = 0xcf5
UNSIGNED_BYTE = 0x1401
UNSIGNED_SHORT = 0x1403
VIEWPORT = 0x0BA2
VERSION = 0x1f02
VERTEX_ARRAY_BINDING = 0x85B5
VERTEX_SHADER = 0x8b31
VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F
VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622
VERTEX_ATTRIB_ARRAY_POINTER = 0x8645
VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A
VERTEX_ATTRIB_ARRAY_SIZE = 0x8623
VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624
VERTEX_ATTRIB_ARRAY_TYPE = 0x8625
WRITE_ONLY = 0x88B9
ZERO = 0x0
+46 -3
View File
@@ -101,8 +101,8 @@ func (f *Functions) BindVertexArray(a VertexArray) {
func (f *Functions) BlendEquation(mode Enum) {
f.Ctx.Call("blendEquation", int(mode))
}
func (f *Functions) BlendFunc(sfactor, dfactor Enum) {
f.Ctx.Call("blendFunc", int(sfactor), int(dfactor))
func (f *Functions) BlendFuncSeparate(srcRGB, dstRGB, srcA, dstA Enum) {
f.Ctx.Call("blendFunc", int(srcRGB), int(dstRGB), int(srcA), int(dstA))
}
func (f *Functions) BlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int, mask Enum, filter Enum) {
panic("not implemented")
@@ -241,11 +241,41 @@ func (f *Functions) GetFramebufferAttachmentParameteri(target, attachment, pname
return paramVal(f.Ctx.Call("getFramebufferAttachmentParameter", int(target), int(attachment), int(pname)))
}
func (f *Functions) GetBinding(pname Enum) Object {
return Object(f.Ctx.Call("getParameter", int(pname)))
obj := f.Ctx.Call("getParameter", int(pname))
if !obj.Truthy() {
return Object{}
}
return Object(obj)
}
func (f *Functions) GetBindingi(pname Enum, idx int) Object {
obj := f.Ctx.Call("getIndexedParameter", int(pname), idx)
if !obj.Truthy() {
return Object{}
}
return Object(obj)
}
func (f *Functions) GetInteger(pname Enum) int {
return paramVal(f.Ctx.Call("getParameter", int(pname)))
}
func (f *Functions) GetFloat(pname Enum) float32 {
return float32(f.Ctx.Call("getParameter", int(pname)).Float())
}
func (f *Functions) GetInteger4(pname Enum) [4]int {
arr := f.Ctx.Call("getParameter", int(pname))
var res [4]int
for i := range res {
res[i] = arr.Index(i).Int()
}
return res
}
func (f *Functions) GetFloat4(pname Enum) [4]float32 {
arr := f.Ctx.Call("getParameter", int(pname))
var res [4]float32
for i := range res {
res[i] = float32(arr.Index(i).Float())
}
return res
}
func (f *Functions) GetProgrami(p Program, pname Enum) int {
return paramVal(f.Ctx.Call("getProgramParameter", js.Value(p), int(pname)))
}
@@ -284,6 +314,19 @@ func (f *Functions) GetUniformBlockIndex(p Program, name string) uint {
func (f *Functions) GetUniformLocation(p Program, name string) Uniform {
return Uniform(f.Ctx.Call("getUniformLocation", js.Value(p), name))
}
func (f *Functions) GetVertexAttrib(index int, pname Enum) int {
return paramVal(f.Ctx.Call("getVertexAttrib", index, int(pname)))
}
func (f *Functions) GetVertexAttribBinding(index int, pname Enum) Object {
obj := f.Ctx.Call("getVertexAttrib", index, int(pname))
if !obj.Truthy() {
return Object{}
}
return Object(obj)
}
func (f *Functions) GetVertexAttribPointer(index int, pname Enum) uintptr {
return uintptr(f.Ctx.Call("getVertexAttribOffset", index, int(pname)).Int())
}
func (f *Functions) InvalidateFramebuffer(target, attachment Enum) {
fn := f.Ctx.Get("invalidateFramebuffer")
if !fn.IsUndefined() {
+74 -9
View File
@@ -42,7 +42,7 @@ typedef struct {
void (*glBindRenderbuffer)(GLenum target, GLuint renderbuffer);
void (*glBindTexture)(GLenum target, GLuint texture);
void (*glBlendEquation)(GLenum mode);
void (*glBlendFunc)(GLenum sfactor, GLenum dfactor);
void (*glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcA, GLenum dstA);
void (*glBufferData)(GLenum target, GLsizeiptr size, const void *data, GLenum usage);
void (*glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
GLenum (*glCheckFramebufferStatus)(GLenum target);
@@ -76,7 +76,9 @@ typedef struct {
void (*glGenTextures)(GLsizei n, GLuint *textures);
GLenum (*glGetError)(void);
void (*glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint *params);
void (*glGetFloatv)(GLenum pname, GLfloat *data);
void (*glGetIntegerv)(GLenum pname, GLint *data);
void (*glGetIntegeri_v)(GLenum pname, GLuint idx, GLint *data);
void (*glGetProgramiv)(GLuint program, GLenum pname, GLint *params);
void (*glGetProgramInfoLog)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
void (*glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint *params);
@@ -84,6 +86,8 @@ typedef struct {
void (*glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
const GLubyte *(*glGetString)(GLenum name);
GLint (*glGetUniformLocation)(GLuint program, const GLchar *name);
void (*glGetVertexAttribiv)(GLuint index, GLenum pname, GLint *params);
void (*glGetVertexAttribPointerv)(GLuint index, GLenum pname, void **params);
GLboolean (*glIsEnabled)(GLenum cap);
void (*glLinkProgram)(GLuint program);
void (*glPixelStorei)(GLenum pname, GLint param);
@@ -162,8 +166,8 @@ static void glBlendEquation(glFunctions *f, GLenum mode) {
f->glBlendEquation(mode);
}
static void glBlendFunc(glFunctions *f, GLenum sfactor, GLenum dfactor) {
f->glBlendFunc(sfactor, dfactor);
static void glBlendFuncSeparate(glFunctions *f, GLenum srcRGB, GLenum dstRGB, GLenum srcA, GLenum dstA) {
f->glBlendFuncSeparate(srcRGB, dstRGB, srcA, dstA);
}
static void glBufferData(glFunctions *f, GLenum target, GLsizeiptr size, const void *data, GLenum usage) {
@@ -303,6 +307,14 @@ static void glGetIntegerv(glFunctions *f, GLenum pname, GLint *data) {
f->glGetIntegerv(pname, data);
}
static void glGetFloatv(glFunctions *f, GLenum pname, GLfloat *data) {
f->glGetFloatv(pname, data);
}
static void glGetIntegeri_v(glFunctions *f, GLenum pname, GLuint idx, GLint *data) {
f->glGetIntegeri_v(pname, idx, data);
}
static void glGetProgramiv(glFunctions *f, GLuint program, GLenum pname, GLint *params) {
f->glGetProgramiv(program, pname, params);
}
@@ -331,6 +343,17 @@ static GLint glGetUniformLocation(glFunctions *f, GLuint program, const GLchar *
return f->glGetUniformLocation(program, name);
}
static void glGetVertexAttribiv(glFunctions *f, GLuint index, GLenum pname, GLint *data) {
f->glGetVertexAttribiv(index, pname, data);
}
// Return uintptr_t to avoid Cgo pointer check.
static uintptr_t glGetVertexAttribPointerv(glFunctions *f, GLuint index, GLenum pname) {
void *ptrs;
f->glGetVertexAttribPointerv(index, pname, &ptrs);
return (uintptr_t)ptrs;
}
static GLboolean glIsEnabled(glFunctions *f, GLenum cap) {
return f->glIsEnabled(cap);
}
@@ -493,8 +516,9 @@ type Context interface{}
type Functions struct {
// Query caches.
uints [100]C.GLuint
ints [100]C.GLint
uints [100]C.GLuint
ints [100]C.GLint
floats [100]C.GLfloat
f C.glFunctions
}
@@ -571,7 +595,7 @@ func (f *Functions) load(forceES bool) error {
f.f.glBindRenderbuffer = must("glBindRenderbuffer")
f.f.glBindTexture = must("glBindTexture")
f.f.glBlendEquation = must("glBlendEquation")
f.f.glBlendFunc = must("glBlendFunc")
f.f.glBlendFuncSeparate = must("glBlendFuncSeparate")
f.f.glBufferData = must("glBufferData")
f.f.glBufferSubData = must("glBufferSubData")
f.f.glCheckFramebufferStatus = must("glCheckFramebufferStatus")
@@ -606,6 +630,7 @@ func (f *Functions) load(forceES bool) error {
f.f.glGetError = must("glGetError")
f.f.glGetFramebufferAttachmentParameteriv = must("glGetFramebufferAttachmentParameteriv")
f.f.glGetIntegerv = must("glGetIntegerv")
f.f.glGetFloatv = must("glGetFloatv")
f.f.glGetProgramiv = must("glGetProgramiv")
f.f.glGetProgramInfoLog = must("glGetProgramInfoLog")
f.f.glGetRenderbufferParameteriv = must("glGetRenderbufferParameteriv")
@@ -613,6 +638,8 @@ func (f *Functions) load(forceES bool) error {
f.f.glGetShaderInfoLog = must("glGetShaderInfoLog")
f.f.glGetString = must("glGetString")
f.f.glGetUniformLocation = must("glGetUniformLocation")
f.f.glGetVertexAttribiv = must("glGetVertexAttribiv")
f.f.glGetVertexAttribPointerv = must("glGetVertexAttribPointerv")
f.f.glIsEnabled = must("glIsEnabled")
f.f.glLinkProgram = must("glLinkProgram")
f.f.glPixelStorei = must("glPixelStorei")
@@ -634,7 +661,8 @@ func (f *Functions) load(forceES bool) error {
// Extensions and GL ES 3 functions.
f.f.glBindBufferBase = load("glBindBufferBase")
f.f.glBindVertexArray = must("glBindVertexArray")
f.f.glBindVertexArray = load("glBindVertexArray")
f.f.glGetIntegeri_v = load("glGetIntegeri_v")
f.f.glGetUniformBlockIndex = load("glGetUniformBlockIndex")
f.f.glUniformBlockBinding = load("glUniformBlockBinding")
f.f.glInvalidateFramebuffer = load("glInvalidateFramebuffer")
@@ -733,8 +761,8 @@ func (f *Functions) BlendEquation(mode Enum) {
C.glBlendEquation(&f.f, C.GLenum(mode))
}
func (f *Functions) BlendFunc(sfactor, dfactor Enum) {
C.glBlendFunc(&f.f, C.GLenum(sfactor), C.GLenum(dfactor))
func (f *Functions) BlendFuncSeparate(srcRGB, dstRGB, srcA, dstA Enum) {
C.glBlendFuncSeparate(&f.f, C.GLenum(srcRGB), C.GLenum(dstRGB), C.GLenum(srcA), C.GLenum(dstA))
}
func (f *Functions) BlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int, mask Enum, filter Enum) {
@@ -917,6 +945,10 @@ func (c *Functions) GetBinding(pname Enum) Object {
return Object{uint(c.GetInteger(pname))}
}
func (c *Functions) GetBindingi(pname Enum, idx int) Object {
return Object{uint(c.GetIntegeri(pname, idx))}
}
func (f *Functions) GetError() Enum {
return Enum(C.glGetError(&f.f))
}
@@ -931,6 +963,20 @@ func (f *Functions) GetFramebufferAttachmentParameteri(target, attachment, pname
return int(f.ints[0])
}
func (f *Functions) GetFloat4(pname Enum) [4]float32 {
C.glGetFloatv(&f.f, C.GLenum(pname), &f.floats[0])
var r [4]float32
for i := range r {
r[i] = float32(f.floats[i])
}
return r
}
func (f *Functions) GetFloat(pname Enum) float32 {
C.glGetFloatv(&f.f, C.GLenum(pname), &f.floats[0])
return float32(f.floats[0])
}
func (f *Functions) GetInteger4(pname Enum) [4]int {
C.glGetIntegerv(&f.f, C.GLenum(pname), &f.ints[0])
var r [4]int
@@ -945,6 +991,11 @@ func (f *Functions) GetInteger(pname Enum) int {
return int(f.ints[0])
}
func (f *Functions) GetIntegeri(pname Enum, idx int) int {
C.glGetIntegeri_v(&f.f, C.GLenum(pname), C.GLuint(idx), &f.ints[0])
return int(f.ints[0])
}
func (f *Functions) GetProgrami(p Program, pname Enum) int {
C.glGetProgramiv(&f.f, C.GLuint(p.V), C.GLenum(pname), &f.ints[0])
return int(f.ints[0])
@@ -1023,6 +1074,20 @@ func (f *Functions) GetUniformLocation(p Program, name string) Uniform {
return Uniform{int(C.glGetUniformLocation(&f.f, C.GLuint(p.V), cname))}
}
func (f *Functions) GetVertexAttrib(index int, pname Enum) int {
C.glGetVertexAttribiv(&f.f, C.GLuint(index), C.GLenum(pname), &f.ints[0])
return int(f.ints[0])
}
func (f *Functions) GetVertexAttribBinding(index int, pname Enum) Object {
return Object{uint(f.GetVertexAttrib(index, pname))}
}
func (f *Functions) GetVertexAttribPointer(index int, pname Enum) uintptr {
ptr := C.glGetVertexAttribPointerv(&f.f, C.GLuint(index), C.GLenum(pname))
return uintptr(ptr)
}
func (f *Functions) InvalidateFramebuffer(target, attachment Enum) {
C.glInvalidateFramebuffer(&f.f, C.GLenum(target), C.GLenum(attachment))
}
+40 -4
View File
@@ -24,7 +24,7 @@ var (
_glBindTexture = LibGLESv2.NewProc("glBindTexture")
_glBindVertexArray = LibGLESv2.NewProc("glBindVertexArray")
_glBlendEquation = LibGLESv2.NewProc("glBlendEquation")
_glBlendFunc = LibGLESv2.NewProc("glBlendFunc")
_glBlendFuncSeparate = LibGLESv2.NewProc("glBlendFuncSeparate")
_glBufferData = LibGLESv2.NewProc("glBufferData")
_glBufferSubData = LibGLESv2.NewProc("glBufferSubData")
_glCheckFramebufferStatus = LibGLESv2.NewProc("glCheckFramebufferStatus")
@@ -64,8 +64,10 @@ var (
_glGenQueries = LibGLESv2.NewProc("glGenQueries")
_glGetError = LibGLESv2.NewProc("glGetError")
_glGetRenderbufferParameteriv = LibGLESv2.NewProc("glGetRenderbufferParameteriv")
_glGetFloatv = LibGLESv2.NewProc("glGetFloatv")
_glGetFramebufferAttachmentParameteriv = LibGLESv2.NewProc("glGetFramebufferAttachmentParameteriv")
_glGetIntegerv = LibGLESv2.NewProc("glGetIntegerv")
_glGetIntegeri_v = LibGLESv2.NewProc("glGetIntegeri_v")
_glGetProgramiv = LibGLESv2.NewProc("glGetProgramiv")
_glGetProgramInfoLog = LibGLESv2.NewProc("glGetProgramInfoLog")
_glGetQueryObjectuiv = LibGLESv2.NewProc("glGetQueryObjectuiv")
@@ -73,6 +75,8 @@ var (
_glGetShaderInfoLog = LibGLESv2.NewProc("glGetShaderInfoLog")
_glGetString = LibGLESv2.NewProc("glGetString")
_glGetUniformLocation = LibGLESv2.NewProc("glGetUniformLocation")
_glGetVertexAttribiv = LibGLESv2.NewProc("glGetVertexAttribiv")
_glGetVertexAttribPointerv = LibGLESv2.NewProc("glGetVertexAttribPointerv")
_glInvalidateFramebuffer = LibGLESv2.NewProc("glInvalidateFramebuffer")
_glIsEnabled = LibGLESv2.NewProc("glIsEnabled")
_glLinkProgram = LibGLESv2.NewProc("glLinkProgram")
@@ -98,7 +102,9 @@ var (
type Functions struct {
// Query caches.
int32s [100]int32
int32s [100]int32
float32s [100]float32
uintptrs [100]uintptr
}
type Context interface{}
@@ -149,8 +155,8 @@ func (c *Functions) BindVertexArray(a VertexArray) {
func (c *Functions) BlendEquation(mode Enum) {
syscall.Syscall(_glBlendEquation.Addr(), 1, uintptr(mode), 0, 0)
}
func (c *Functions) BlendFunc(sfactor, dfactor Enum) {
syscall.Syscall(_glBlendFunc.Addr(), 2, uintptr(sfactor), uintptr(dfactor), 0)
func (c *Functions) BlendFuncSeparate(srcRGB, dstRGB, srcA, dstA Enum) {
syscall.Syscall6(_glBlendFuncSeparate.Addr(), 4, uintptr(srcRGB), uintptr(dstRGB), uintptr(srcA), uintptr(dstA), 0, 0)
}
func (f *Functions) BlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int, mask Enum, filter Enum) {
panic("not implemented")
@@ -299,6 +305,9 @@ func (f *Functions) GetUniformBlockIndex(p Program, name string) uint {
func (c *Functions) GetBinding(pname Enum) Object {
return Object{uint(c.GetInteger(pname))}
}
func (c *Functions) GetBindingi(pname Enum, idx int) Object {
return Object{uint(c.GetIntegeri(pname, idx))}
}
func (c *Functions) GetError() Enum {
e, _, _ := syscall.Syscall(_glGetError.Addr(), 0, 0, 0, 0)
return Enum(e)
@@ -323,6 +332,20 @@ func (c *Functions) GetInteger(pname Enum) int {
syscall.Syscall(_glGetIntegerv.Addr(), 2, uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0])), 0)
return int(c.int32s[0])
}
func (c *Functions) GetIntegeri(pname Enum, idx int) int {
syscall.Syscall(_glGetIntegeri_v.Addr(), 3, uintptr(pname), uintptr(idx), uintptr(unsafe.Pointer(&c.int32s[0])))
return int(c.int32s[0])
}
func (c *Functions) GetFloat(pname Enum) float32 {
syscall.Syscall(_glGetFloatv.Addr(), 2, uintptr(pname), uintptr(unsafe.Pointer(&c.float32s[0])), 0)
return c.float32s[0]
}
func (c *Functions) GetFloat4(pname Enum) [4]float32 {
syscall.Syscall(_glGetFloatv.Addr(), 2, uintptr(pname), uintptr(unsafe.Pointer(&c.float32s[0])), 0)
var r [4]float32
copy(r[:], c.float32s[:])
return r
}
func (c *Functions) GetProgrami(p Program, pname Enum) int {
syscall.Syscall(_glGetProgramiv.Addr(), 3, uintptr(p.V), uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0])))
return int(c.int32s[0])
@@ -358,6 +381,19 @@ func (c *Functions) GetUniformLocation(p Program, name string) Uniform {
issue34474KeepAlive(c0)
return Uniform{int(u)}
}
func (c *Functions) GetVertexAttrib(index int, pname Enum) int {
syscall.Syscall(_glGetVertexAttribiv.Addr(), 3, uintptr(index), uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0])))
return int(c.int32s[0])
}
func (c *Functions) GetVertexAttribBinding(index int, pname Enum) Object {
return Object{uint(c.GetVertexAttrib(index, pname))}
}
func (c *Functions) GetVertexAttribPointer(index int, pname Enum) uintptr {
syscall.Syscall(_glGetVertexAttribPointerv.Addr(), 3, uintptr(index), uintptr(pname), uintptr(unsafe.Pointer(&c.uintptrs[0])))
return c.uintptrs[0]
}
func (c *Functions) InvalidateFramebuffer(target, attachment Enum) {
addr := _glInvalidateFramebuffer.Addr()
if addr == 0 {
+53 -13
View File
@@ -3,20 +3,28 @@
package gl
type (
Buffer struct{ V uint }
Framebuffer struct{ V uint }
Program struct{ V uint }
Renderbuffer struct{ V uint }
Shader struct{ V uint }
Texture struct{ V uint }
Query struct{ V uint }
Uniform struct{ V int }
VertexArray struct{ V uint }
Object struct{ V uint }
Buffer Object
Framebuffer Object
Program Object
Renderbuffer Object
Shader Object
Texture Object
Query Object
Uniform struct{ V int }
VertexArray Object
)
func (o Object) valid() bool {
return o.V != 0
}
func (o Object) equal(o2 Object) bool {
return o == o2
}
func (u Framebuffer) Valid() bool {
return u.V != 0
return Object(u).valid()
}
func (u Uniform) Valid() bool {
@@ -24,13 +32,45 @@ func (u Uniform) Valid() bool {
}
func (p Program) Valid() bool {
return p.V != 0
return Object(p).valid()
}
func (s Shader) Valid() bool {
return s.V != 0
return Object(s).valid()
}
func (a VertexArray) Valid() bool {
return a.V != 0
return Object(a).valid()
}
func (f Framebuffer) Equal(f2 Framebuffer) bool {
return Object(f).equal(Object(f2))
}
func (p Program) Equal(p2 Program) bool {
return Object(p).equal(Object(p2))
}
func (s Shader) Equal(s2 Shader) bool {
return Object(s).equal(Object(s2))
}
func (u Uniform) Equal(u2 Uniform) bool {
return u == u2
}
func (a VertexArray) Equal(a2 VertexArray) bool {
return Object(a).equal(Object(a2))
}
func (r Renderbuffer) Equal(r2 Renderbuffer) bool {
return Object(r).equal(Object(r2))
}
func (t Texture) Equal(t2 Texture) bool {
return Object(t).equal(Object(t2))
}
func (b Buffer) Equal(b2 Buffer) bool {
return Object(b).equal(Object(b2))
}
+66 -14
View File
@@ -5,34 +5,86 @@ package gl
import "syscall/js"
type (
Buffer js.Value
Framebuffer js.Value
Program js.Value
Renderbuffer js.Value
Shader js.Value
Texture js.Value
Query js.Value
Uniform js.Value
VertexArray js.Value
Object js.Value
Buffer Object
Framebuffer Object
Program Object
Renderbuffer Object
Shader Object
Texture Object
Query Object
Uniform Object
VertexArray Object
)
func (o Object) valid() bool {
return js.Value(o).Truthy()
}
func (o Object) equal(o2 Object) bool {
return js.Value(o).Equal(js.Value(o2))
}
func (b Buffer) Valid() bool {
return Object(b).valid()
}
func (f Framebuffer) Valid() bool {
return !js.Value(f).IsUndefined() && !js.Value(f).IsNull()
return Object(f).valid()
}
func (p Program) Valid() bool {
return !js.Value(p).IsUndefined() && !js.Value(p).IsNull()
return Object(p).valid()
}
func (r Renderbuffer) Valid() bool {
return Object(r).valid()
}
func (s Shader) Valid() bool {
return !js.Value(s).IsUndefined() && !js.Value(s).IsNull()
return Object(s).valid()
}
func (t Texture) Valid() bool {
return Object(t).valid()
}
func (u Uniform) Valid() bool {
return !js.Value(u).IsUndefined() && !js.Value(u).IsNull()
return Object(u).valid()
}
func (a VertexArray) Valid() bool {
return !js.Value(a).IsUndefined() && !js.Value(a).IsNull()
return Object(a).valid()
}
func (f Framebuffer) Equal(f2 Framebuffer) bool {
return Object(f).equal(Object(f2))
}
func (p Program) Equal(p2 Program) bool {
return Object(p).equal(Object(p2))
}
func (s Shader) Equal(s2 Shader) bool {
return Object(s).equal(Object(s2))
}
func (u Uniform) Equal(u2 Uniform) bool {
return Object(u).equal(Object(u2))
}
func (a VertexArray) Equal(a2 VertexArray) bool {
return Object(a).equal(Object(a2))
}
func (r Renderbuffer) Equal(r2 Renderbuffer) bool {
return Object(r).equal(Object(r2))
}
func (t Texture) Equal(t2 Texture) bool {
return Object(t).equal(Object(t2))
}
func (b Buffer) Equal(b2 Buffer) bool {
return Object(b).equal(Object(b2))
}