forked from joejulian/gio
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:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user