diff --git a/app/headless/headless.go b/app/headless/headless.go index 04b3e9dc..741a6f16 100644 --- a/app/headless/headless.go +++ b/app/headless/headless.go @@ -59,7 +59,7 @@ func NewWindow(width, height int) (*Window, error) { fboTex.Release() return err } - fbo.Bind() + backend.BindFramebuffer(fbo) gp, err := gpu.New(backend) if err != nil { fbo.Release() diff --git a/gpu/backend.go b/gpu/backend.go index 32000d1c..92b1a5cf 100644 --- a/gpu/backend.go +++ b/gpu/backend.go @@ -37,6 +37,13 @@ type Backend interface { SetDepthTest(enable bool) DepthMask(mask bool) BlendFunc(sfactor, dfactor BlendFactor) + + BindInputLayout(i InputLayout) + BindProgram(p Program) + BindFramebuffer(f Framebuffer) + BindTexture(unit int, t Texture) + BindVertexBuffer(b Buffer, stride, offset int) + BindIndexBuffer(b Buffer) } type ShaderSources struct { @@ -83,7 +90,6 @@ type InputDesc struct { // InputLayout is the backend specific representation of the mapping // between Buffers and shader attributes. type InputLayout interface { - Bind() Release() } @@ -110,21 +116,17 @@ type Caps struct { } type Program interface { - Bind() Release() SetVertexUniforms(buf Buffer) SetFragmentUniforms(buf Buffer) } type Buffer interface { - BindVertex(stride, offset int) - BindIndex() Release() Upload(data []byte) } type Framebuffer interface { - Bind() Invalidate() Release() ReadPixels(src image.Rectangle, pixels []byte) error @@ -140,7 +142,6 @@ type Timer interface { type Texture interface { Upload(img *image.RGBA) Release() - Bind(unit int) } const ( diff --git a/gpu/gl/backend.go b/gpu/gl/backend.go index 033693fd..939179e7 100644 --- a/gpu/gl/backend.go +++ b/gpu/gl/backend.go @@ -59,7 +59,7 @@ type gpuTexture struct { } type gpuFramebuffer struct { - funcs Functions + backend *Backend obj Framebuffer hasDepth bool depthBuf Renderbuffer @@ -129,12 +129,12 @@ func NewBackend(f Functions) (*Backend, error) { } defFBO := Framebuffer(f.GetBinding(FRAMEBUFFER_BINDING)) b := &Backend{ - defFBO: &gpuFramebuffer{funcs: f, obj: defFBO}, funcs: f, floatTriple: floatTriple, alphaTriple: alphaTripleFor(ver), srgbaTriple: srgbaTriple, } + b.defFBO = &gpuFramebuffer{backend: b, obj: defFBO} if hasExtension(exts, "GL_EXT_disjoint_timer_query_webgl2") || hasExtension(exts, "GL_EXT_disjoint_timer_query") { b.feats.Features |= gpu.FeatureTimers } @@ -170,8 +170,8 @@ func (b *Backend) NewFramebuffer(tex gpu.Texture, depthBits int) (gpu.Framebuffe glErr(b.funcs) gltex := tex.(*gpuTexture) fb := b.funcs.CreateFramebuffer() - fbo := &gpuFramebuffer{funcs: b.funcs, obj: fb} - fbo.Bind() + fbo := &gpuFramebuffer{backend: b, obj: fb} + b.BindFramebuffer(fbo) if err := glErr(b.funcs); err != nil { fbo.Release() return nil, err @@ -217,7 +217,7 @@ func (b *Backend) NewTexture(format gpu.TextureFormat, width, height int, minFil default: return nil, errors.New("unsupported texture format") } - tex.Bind(0) + b.BindTexture(0, tex) b.funcs.TexParameteri(TEXTURE_2D, TEXTURE_MAG_FILTER, toTexFilter(magFilter)) b.funcs.TexParameteri(TEXTURE_2D, TEXTURE_MIN_FILTER, toTexFilter(minFilter)) b.funcs.TexParameteri(TEXTURE_2D, TEXTURE_WRAP_S, CLAMP_TO_EDGE) @@ -430,7 +430,7 @@ func (b *Backend) NewProgram(vssrc, fssrc gpu.ShaderSources) (gpu.Program, error obj: p, nattr: len(attr), } - gpuProg.Bind() + b.BindProgram(gpuProg) // Bind texture uniforms. for _, tex := range vssrc.Textures { u := b.funcs.GetUniformLocation(p, tex.Name) @@ -467,9 +467,10 @@ func (p *gpuProgram) updateUniforms() { p.fragUniforms.update(p.backend.funcs) } -func (p *gpuProgram) Bind() { - p.backend.useProgram(p) - p.backend.enableVertexArrays(p.nattr) +func (b *Backend) BindProgram(prog gpu.Program) { + p := prog.(*gpuProgram) + b.useProgram(p) + b.enableVertexArrays(p.nattr) } func (p *gpuProgram) Release() { @@ -553,11 +554,12 @@ func (b *gpuBuffer) Release() { } } -func (b *gpuBuffer) BindVertex(stride, offset int) { - if b.typ&gpu.BufferBindingVertices == 0 { +func (b *Backend) BindVertexBuffer(buf gpu.Buffer, stride, offset int) { + gbuf := buf.(*gpuBuffer) + if gbuf.typ&gpu.BufferBindingVertices == 0 { panic("not a vertex buffer") } - b.backend.state.buffer = bufferBinding{buf: b, stride: stride, offset: offset} + b.state.buffer = bufferBinding{buf: gbuf, stride: stride, offset: offset} } func (b *Backend) setupVertexArrays() { @@ -582,36 +584,37 @@ func (b *Backend) setupVertexArrays() { } } -func (b *gpuBuffer) BindIndex() { - if b.typ&gpu.BufferBindingIndices == 0 { +func (b *Backend) BindIndexBuffer(buf gpu.Buffer) { + gbuf := buf.(*gpuBuffer) + if gbuf.typ&gpu.BufferBindingIndices == 0 { panic("not an index buffer") } - b.backend.funcs.BindBuffer(ELEMENT_ARRAY_BUFFER, b.obj) + b.funcs.BindBuffer(ELEMENT_ARRAY_BUFFER, gbuf.obj) } func (f *gpuFramebuffer) ReadPixels(src image.Rectangle, pixels []byte) error { - glErr(f.funcs) - f.Bind() + glErr(f.backend.funcs) + f.backend.BindFramebuffer(f) if len(pixels) < src.Dx()*src.Dy() { return errors.New("unexpected RGBA size") } - f.funcs.ReadPixels(src.Min.X, src.Min.Y, src.Dx(), src.Dy(), RGBA, UNSIGNED_BYTE, pixels) - return glErr(f.funcs) + f.backend.funcs.ReadPixels(src.Min.X, src.Min.Y, src.Dx(), src.Dy(), RGBA, UNSIGNED_BYTE, pixels) + return glErr(f.backend.funcs) } -func (f *gpuFramebuffer) Bind() { - f.funcs.BindFramebuffer(FRAMEBUFFER, f.obj) +func (b *Backend) BindFramebuffer(fbo gpu.Framebuffer) { + b.funcs.BindFramebuffer(FRAMEBUFFER, fbo.(*gpuFramebuffer).obj) } func (f *gpuFramebuffer) Invalidate() { - f.Bind() - f.funcs.InvalidateFramebuffer(FRAMEBUFFER, COLOR_ATTACHMENT0) + f.backend.BindFramebuffer(f) + f.backend.funcs.InvalidateFramebuffer(FRAMEBUFFER, COLOR_ATTACHMENT0) } func (f *gpuFramebuffer) Release() { - f.funcs.DeleteFramebuffer(f.obj) + f.backend.funcs.DeleteFramebuffer(f.obj) if f.hasDepth { - f.funcs.DeleteRenderbuffer(f.depthBuf) + f.backend.funcs.DeleteRenderbuffer(f.depthBuf) } } @@ -626,8 +629,8 @@ func toTexFilter(f gpu.TextureFilter) int { } } -func (t *gpuTexture) Bind(unit int) { - t.backend.bindTexture(unit, t) +func (b *Backend) BindTexture(unit int, t gpu.Texture) { + b.bindTexture(unit, t.(*gpuTexture)) } func (t *gpuTexture) Release() { @@ -635,7 +638,7 @@ func (t *gpuTexture) Release() { } func (t *gpuTexture) Upload(img *image.RGBA) { - t.Bind(0) + t.backend.BindTexture(0, t) var pixels []byte b := img.Bounds() w, h := b.Dx(), b.Dy() @@ -672,8 +675,8 @@ func (t *gpuTimer) Duration() (time.Duration, bool) { return time.Duration(nanos), true } -func (l *gpuInputLayout) Bind() { - l.backend.state.layout = l +func (b *Backend) BindInputLayout(l gpu.InputLayout) { + b.state.layout = l.(*gpuInputLayout) } func (l *gpuInputLayout) Release() {} diff --git a/gpu/gpu.go b/gpu/gpu.go index a8cbad7d..7cf9c935 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -496,7 +496,7 @@ func (r *renderer) stencilClips(pathCache *opCache, ops []*pathOp) { if fbo != p.place.Idx { fbo = p.place.Idx f := r.pather.stenciler.cover(fbo) - f.fbo.Bind() + r.ctx.BindFramebuffer(f.fbo) r.ctx.Clear(BufferAttachmentColor) } data, _ := pathCache.get(p.pathKey) @@ -511,8 +511,8 @@ func (r *renderer) intersect(ops []imageOp) { } fbo := -1 r.pather.stenciler.beginIntersect(r.intersections.sizes) - r.blitter.quadVerts.BindVertex(4*4, 0) - r.pather.stenciler.iprog.layout.Bind() + r.ctx.BindVertexBuffer(r.blitter.quadVerts, 4*4, 0) + r.ctx.BindInputLayout(r.pather.stenciler.iprog.layout) for _, img := range ops { if img.clipType != clipTypeIntersection { continue @@ -520,7 +520,7 @@ func (r *renderer) intersect(ops []imageOp) { if fbo != img.place.Idx { fbo = img.place.Idx f := r.pather.stenciler.intersections.fbos[fbo] - f.fbo.Bind() + r.ctx.BindFramebuffer(f.fbo) r.ctx.Clear(BufferAttachmentColor) } r.ctx.Viewport(img.place.Pos.X, img.place.Pos.Y, img.clip.Dx(), img.clip.Dy()) @@ -542,7 +542,7 @@ func (r *renderer) intersectPath(p *pathOp, clip image.Rectangle) { Max: o.Add(clip.Size()), } fbo := r.pather.stenciler.cover(p.place.Idx) - fbo.tex.Bind(0) + r.ctx.BindTexture(0, fbo.tex) coverScale, coverOff := texSpaceTransform(toRectF(uv), fbo.size) r.pather.stenciler.iprog.uniforms.vert.uvScale = [2]float32{coverScale.X, coverScale.Y} r.pather.stenciler.iprog.uniforms.vert.uvOffset = [2]float32{coverOff.X, coverOff.Y} @@ -819,15 +819,15 @@ func (d *drawState) materialFor(cache *resourceCache, rect f32.Rectangle, off f3 func (r *renderer) drawZOps(ops []imageOp) { r.ctx.SetDepthTest(true) - r.blitter.quadVerts.BindVertex(4*4, 0) - r.blitter.layout.Bind() + r.ctx.BindVertexBuffer(r.blitter.quadVerts, 4*4, 0) + r.ctx.BindInputLayout(r.blitter.layout) // Render front to back. for i := len(ops) - 1; i >= 0; i-- { img := ops[i] m := img.material switch m.material { case materialTexture: - r.texHandle(m.texture).Bind(0) + r.ctx.BindTexture(0, r.texHandle(m.texture)) } drc := img.clip scale, off := clipSpaceTransform(drc, r.blitter.viewport) @@ -840,14 +840,14 @@ func (r *renderer) drawOps(ops []imageOp) { r.ctx.SetDepthTest(true) r.ctx.DepthMask(false) r.ctx.BlendFunc(BlendFactorOne, BlendFactorOneMinusSrcAlpha) - r.blitter.quadVerts.BindVertex(4*4, 0) - r.pather.coverer.layout.Bind() + r.ctx.BindVertexBuffer(r.blitter.quadVerts, 4*4, 0) + r.ctx.BindInputLayout(r.pather.coverer.layout) var coverTex Texture for _, img := range ops { m := img.material switch m.material { case materialTexture: - r.texHandle(m.texture).Bind(0) + r.ctx.BindTexture(0, r.texHandle(m.texture)) } drc := img.clip scale, off := clipSpaceTransform(drc, r.blitter.viewport) @@ -863,7 +863,7 @@ func (r *renderer) drawOps(ops []imageOp) { } if coverTex != fbo.tex { coverTex = fbo.tex - coverTex.Bind(1) + r.ctx.BindTexture(1, coverTex) } uv := image.Rectangle{ Min: img.place.Pos, @@ -894,7 +894,7 @@ func gamma(r, g, b, a uint32) [4]float32 { func (b *blitter) blit(z float32, mat materialType, col [4]float32, scale, off, uvScale, uvOff f32.Point) { p := b.prog[mat] - p.prog.Bind() + b.ctx.BindProgram(p.prog) var uniforms *blitUniforms switch mat { case materialColor: diff --git a/gpu/path.go b/gpu/path.go index 2ca2f892..797836d0 100644 --- a/gpu/path.go +++ b/gpu/path.go @@ -296,17 +296,17 @@ func (s *stenciler) beginIntersect(sizes []image.Point) { // no floating point support is available. s.intersections.resize(s.ctx, sizes) s.ctx.ClearColor(1.0, 0.0, 0.0, 0.0) - s.iprog.prog.prog.Bind() + s.ctx.BindProgram(s.iprog.prog.prog) } func (s *stenciler) endIntersect() { - s.defFBO.Bind() + s.ctx.BindFramebuffer(s.defFBO) } func (s *stenciler) invalidateFBO() { s.intersections.invalidate(s.ctx) s.fbos.invalidate(s.ctx) - s.defFBO.Bind() + s.ctx.BindFramebuffer(s.defFBO) } func (s *stenciler) cover(idx int) stencilFBO { @@ -317,9 +317,9 @@ func (s *stenciler) begin(sizes []image.Point) { s.ctx.BlendFunc(BlendFactorOne, BlendFactorOne) s.fbos.resize(s.ctx, sizes) s.ctx.ClearColor(0.0, 0.0, 0.0, 0.0) - s.prog.prog.prog.Bind() - s.prog.layout.Bind() - s.indexBuf.BindIndex() + s.ctx.BindProgram(s.prog.prog.prog) + s.ctx.BindInputLayout(s.prog.layout) + s.ctx.BindIndexBuffer(s.indexBuf) } func (s *stenciler) stencilPath(bounds image.Rectangle, offset f32.Point, uv image.Point, data *pathData) { @@ -341,14 +341,14 @@ func (s *stenciler) stencilPath(bounds image.Rectangle, offset f32.Point, uv ima batch = max } off := path.VertStride * start * 4 - data.data.BindVertex(path.VertStride, off) + s.ctx.BindVertexBuffer(data.data, path.VertStride, off) s.ctx.DrawElements(DrawModeTriangles, 0, batch*6) start += batch } } func (s *stenciler) end() { - s.defFBO.Bind() + s.ctx.BindFramebuffer(s.defFBO) } func (p *pather) cover(z float32, mat materialType, col [4]float32, scale, off, uvScale, uvOff, coverScale, coverOff f32.Point) { @@ -357,7 +357,7 @@ func (p *pather) cover(z float32, mat materialType, col [4]float32, scale, off, func (c *coverer) cover(z float32, mat materialType, col [4]float32, scale, off, uvScale, uvOff, coverScale, coverOff f32.Point) { p := c.prog[mat] - p.prog.Bind() + c.ctx.BindProgram(p.prog) var uniforms *coverUniforms switch mat { case materialColor: