gpu: Move Bind methods to Backend

Having Backend.Bind* methods better matches both opengl and d3d.

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