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