From 21ca9d13a8bc93217cd8889dc3957b99a097b25b Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 10 Sep 2021 13:37:12 +0200 Subject: [PATCH] gpu: switch from uniform buffers to combined push buffers Vulkan doesn't support changing uniforms during a render pass. However, push constants *can* be changed. The gio-shader repository was changed to use push constants instead of uniforms, this change implements the corresponding driver and renderer change. Signed-off-by: Elias Naur --- go.mod | 2 +- go.sum | 4 +- gpu/compute.go | 54 ++++++--------- gpu/gpu.go | 100 ++++++++++------------------ gpu/internal/d3d11/d3d11_windows.go | 6 +- gpu/internal/driver/driver.go | 3 +- gpu/internal/metal/metal_darwin.go | 13 +--- gpu/internal/opengl/opengl.go | 74 +++----------------- gpu/path.go | 67 ++++++++----------- 9 files changed, 99 insertions(+), 224 deletions(-) diff --git a/go.mod b/go.mod index 5ecbd217..870317fa 100644 --- a/go.mod +++ b/go.mod @@ -10,5 +10,5 @@ require ( require ( gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 - gioui.org/shader v1.0.2 + gioui.org/shader v1.0.3 ) diff --git a/go.sum b/go.sum index 94f4933e..9edf89dd 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7 gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ= gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc= gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ= -gioui.org/shader v1.0.2 h1:5JrtNdOqmY+tQzBKKVFqf0YIziUK38OEw8mxxEbXdc8= -gioui.org/shader v1.0.2/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= +gioui.org/shader v1.0.3 h1:xllhh4w2XWej9lfkHMtOtI3ES05T8xZzxrSSWbMZgTw= +gioui.org/shader v1.0.3/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= diff --git a/gpu/compute.go b/gpu/compute.go index cbd7c753..918c0f9d 100644 --- a/gpu/compute.go +++ b/gpu/compute.go @@ -88,11 +88,8 @@ type compute struct { pipeline driver.Pipeline buffer sizedBuffer quads []materialVertex - vert struct { - uniforms *materialVertUniforms - buf driver.Buffer - } - frag struct { + uniforms struct { + u *materialUniforms buf driver.Buffer } } @@ -172,13 +169,10 @@ type copyUniforms struct { _ [8]byte // Pad to 16 bytes. } -type materialVertUniforms struct { - scale [2]float32 - pos [2]float32 -} - -type materialFragUniforms struct { - emulateSRGB float32 +type materialUniforms struct { + scale [2]float32 + pos [2]float32 + emulatesRGB float32 _ [12]byte // Pad to 16 bytes } @@ -504,25 +498,14 @@ func newCompute(ctx driver.Device) (*compute, error) { return nil, err } g.materials.pipeline = pipe - g.materials.vert.uniforms = new(materialVertUniforms) + g.materials.uniforms.u = new(materialUniforms) - buf, err = ctx.NewBuffer(driver.BufferBindingUniforms, int(unsafe.Sizeof(*g.materials.vert.uniforms))) + buf, err = ctx.NewBuffer(driver.BufferBindingUniforms, int(unsafe.Sizeof(*g.materials.uniforms.u))) if err != nil { g.Release() return nil, err } - g.materials.vert.buf = buf - var emulateSRGB materialFragUniforms - if !g.srgb { - emulateSRGB.emulateSRGB = 1.0 - } - buf, err = ctx.NewBuffer(driver.BufferBindingUniforms, int(unsafe.Sizeof(emulateSRGB))) - if err != nil { - g.Release() - return nil, err - } - buf.Upload(byteslice.Struct(&emulateSRGB)) - g.materials.frag.buf = buf + g.materials.uniforms.buf = buf for _, shader := range shaders { if !g.useCPU { @@ -874,7 +857,6 @@ func (g *compute) blitLayers(viewport image.Point) { layers := g.collector.frame.layers g.ctx.Viewport(0, 0, viewport.X, viewport.Y) g.ctx.BindPipeline(g.output.blitPipeline) - g.ctx.BindVertexUniforms(g.output.uniBuf) for len(layers) > 0 { g.output.layerVertices = g.output.layerVertices[:0] atlas := layers[0].alloc.atlas @@ -906,6 +888,7 @@ func (g *compute) blitLayers(viewport image.Point) { g.output.uniforms.pos = [2]float32{ox, oy} g.output.uniforms.uvScale = [2]float32{1 / float32(atlas.size.X), 1 / float32(atlas.size.Y)} g.output.uniBuf.Upload(byteslice.Struct(g.output.uniforms)) + g.ctx.BindUniforms(g.output.uniBuf) vertexData := byteslice.Slice(g.output.layerVertices) g.output.buffer.ensureCapacity(false, g.ctx, driver.BufferBindingVertices, len(vertexData)) g.output.buffer.buffer.Upload(vertexData) @@ -1001,9 +984,14 @@ func (g *compute) renderMaterials() error { } // Transform to clip space: [-1, -1] - [1, 1] and flip Y-axis to cancel the implied transformation // between framebuffer and texture space. - m.vert.uniforms.scale = [2]float32{2, -2} - m.vert.uniforms.pos = [2]float32{-1, +1} - m.vert.buf.Upload(byteslice.Struct(m.vert.uniforms)) + *m.uniforms.u = materialUniforms{ + scale: [2]float32{2, -2}, + pos: [2]float32{-1, +1}, + } + if !g.srgb { + m.uniforms.u.emulatesRGB = 1.0 + } + m.uniforms.buf.Upload(byteslice.Struct(m.uniforms.u)) vertexData := byteslice.Slice(m.quads) n := pow2Ceil(len(vertexData)) m.buffer.ensureCapacity(false, g.ctx, driver.BufferBindingVertices, n) @@ -1013,10 +1001,9 @@ func (g *compute) renderMaterials() error { d.Action = driver.LoadActionClear } g.ctx.BeginRenderPass(atlas.fbo, d) - g.ctx.BindVertexUniforms(m.vert.buf) - g.ctx.BindFragmentUniforms(m.frag.buf) g.ctx.BindTexture(0, imgAtlas.image) g.ctx.BindPipeline(m.pipeline) + g.ctx.BindUniforms(m.uniforms.buf) g.ctx.BindVertexBuffer(m.buffer.buffer, 0) newAllocs := atlas.allocs[allocStart:] for i, a := range newAllocs { @@ -1507,8 +1494,7 @@ func (g *compute) Release() { &g.buffers.config, g.materials.pipeline, &g.materials.buffer, - g.materials.vert.buf, - g.materials.frag.buf, + g.materials.uniforms.buf, g.timers.t, } for _, r := range res { diff --git a/gpu/gpu.go b/gpu/gpu.go index 10423650..597feabc 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -282,30 +282,20 @@ type blitter struct { } type blitColUniforms struct { - vert struct { - blitUniforms - _ [12]byte // Padding to a multiple of 16. - } - frag struct { - colorUniforms - } + blitUniforms + _ [128 - unsafe.Sizeof(blitUniforms{}) - unsafe.Sizeof(colorUniforms{})]byte // Padding to 128 bytes. + colorUniforms } type blitTexUniforms struct { - vert struct { - blitUniforms - _ [12]byte // Padding to a multiple of 16. - } + blitUniforms + _ [12]byte // Padding to 16 bytes. } type blitLinearGradientUniforms struct { - vert struct { - blitUniforms - _ [12]byte // Padding to a multiple of 16. - } - frag struct { - gradientUniforms - } + blitUniforms + _ [128 - unsafe.Sizeof(blitUniforms{}) - unsafe.Sizeof(gradientUniforms{})]byte // Padding to 128 bytes. + gradientUniforms } type uniformBuffer struct { @@ -314,9 +304,8 @@ type uniformBuffer struct { } type pipeline struct { - pipeline driver.Pipeline - vertUniforms *uniformBuffer - fragUniforms *uniformBuffer + pipeline driver.Pipeline + uniforms *uniformBuffer } type blitUniforms struct { @@ -536,8 +525,7 @@ func newBlitter(ctx driver.Device) *blitter { b.texUniforms = new(blitTexUniforms) b.linearGradientUniforms = new(blitLinearGradientUniforms) pipelines, err := createColorPrograms(ctx, gio.Shader_blit_vert, gio.Shader_blit_frag, - [3]interface{}{&b.colUniforms.vert, &b.linearGradientUniforms.vert, &b.texUniforms.vert}, - [3]interface{}{&b.colUniforms.frag, &b.linearGradientUniforms.frag, nil}, + [3]interface{}{b.colUniforms, b.linearGradientUniforms, b.texUniforms}, ) if err != nil { panic(err) @@ -553,7 +541,7 @@ func (b *blitter) release() { } } -func createColorPrograms(b driver.Device, vsSrc shader.Sources, fsSrc [3]shader.Sources, vertUniforms, fragUniforms [3]interface{}) ([3]*pipeline, error) { +func createColorPrograms(b driver.Device, vsSrc shader.Sources, fsSrc [3]shader.Sources, uniforms [3]interface{}) ([3]*pipeline, error) { var pipelines [3]*pipeline blend := driver.BlendDesc{ Enable: true, @@ -589,17 +577,14 @@ func createColorPrograms(b driver.Device, vsSrc shader.Sources, fsSrc [3]shader. if err != nil { return pipelines, err } - var vertBuffer, fragBuffer *uniformBuffer - if u := vertUniforms[materialTexture]; u != nil { + var vertBuffer *uniformBuffer + if u := uniforms[materialTexture]; u != nil { vertBuffer = newUniformBuffer(b, u) } - if u := fragUniforms[materialTexture]; u != nil { - fragBuffer = newUniformBuffer(b, u) - } - pipelines[materialTexture] = &pipeline{pipe, vertBuffer, fragBuffer} + pipelines[materialTexture] = &pipeline{pipe, vertBuffer} } { - var vertBuffer, fragBuffer *uniformBuffer + var vertBuffer *uniformBuffer fsh, err := b.NewFragmentShader(fsSrc[materialColor]) if err != nil { pipelines[materialTexture].Release() @@ -618,16 +603,13 @@ func createColorPrograms(b driver.Device, vsSrc shader.Sources, fsSrc [3]shader. pipelines[materialTexture].Release() return pipelines, err } - if u := vertUniforms[materialColor]; u != nil { + if u := uniforms[materialColor]; u != nil { vertBuffer = newUniformBuffer(b, u) } - if u := fragUniforms[materialColor]; u != nil { - fragBuffer = newUniformBuffer(b, u) - } - pipelines[materialColor] = &pipeline{pipe, vertBuffer, fragBuffer} + pipelines[materialColor] = &pipeline{pipe, vertBuffer} } { - var vertBuffer, fragBuffer *uniformBuffer + var vertBuffer *uniformBuffer fsh, err := b.NewFragmentShader(fsSrc[materialLinearGradient]) if err != nil { pipelines[materialTexture].Release() @@ -648,13 +630,10 @@ func createColorPrograms(b driver.Device, vsSrc shader.Sources, fsSrc [3]shader. pipelines[materialColor].Release() return pipelines, err } - if u := vertUniforms[materialLinearGradient]; u != nil { + if u := uniforms[materialLinearGradient]; u != nil { vertBuffer = newUniformBuffer(b, u) } - if u := fragUniforms[materialLinearGradient]; u != nil { - fragBuffer = newUniformBuffer(b, u) - } - pipelines[materialLinearGradient] = &pipeline{pipe, vertBuffer, fragBuffer} + pipelines[materialLinearGradient] = &pipeline{pipe, vertBuffer} } if err != nil { for _, p := range pipelines { @@ -1151,21 +1130,21 @@ func (b *blitter) blit(mat materialType, col f32color.RGBA, col1, col2 f32color. var uniforms *blitUniforms switch mat { case materialColor: - b.colUniforms.frag.color = col - uniforms = &b.colUniforms.vert.blitUniforms + b.colUniforms.color = col + uniforms = &b.colUniforms.blitUniforms case materialTexture: t1, t2, t3, t4, t5, t6 := uvTrans.Elems() - b.texUniforms.vert.blitUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0} - b.texUniforms.vert.blitUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0} - uniforms = &b.texUniforms.vert.blitUniforms + b.texUniforms.blitUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0} + b.texUniforms.blitUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0} + uniforms = &b.texUniforms.blitUniforms case materialLinearGradient: - b.linearGradientUniforms.frag.color1 = col1 - b.linearGradientUniforms.frag.color2 = col2 + b.linearGradientUniforms.color1 = col1 + b.linearGradientUniforms.color2 = col2 t1, t2, t3, t4, t5, t6 := uvTrans.Elems() - b.linearGradientUniforms.vert.blitUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0} - b.linearGradientUniforms.vert.blitUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0} - uniforms = &b.linearGradientUniforms.vert.blitUniforms + b.linearGradientUniforms.blitUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0} + b.linearGradientUniforms.blitUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0} + uniforms = &b.linearGradientUniforms.blitUniforms } uniforms.transform = [4]float32{scale.X, scale.Y, off.X, off.Y} p.UploadUniforms(b.ctx) @@ -1197,23 +1176,16 @@ func (u *uniformBuffer) Release() { } func (p *pipeline) UploadUniforms(ctx driver.Device) { - if p.vertUniforms != nil { - p.vertUniforms.Upload() - ctx.BindVertexUniforms(p.vertUniforms.buf) - } - if p.fragUniforms != nil { - p.fragUniforms.Upload() - ctx.BindFragmentUniforms(p.fragUniforms.buf) + if p.uniforms != nil { + p.uniforms.Upload() + ctx.BindUniforms(p.uniforms.buf) } } func (p *pipeline) Release() { p.pipeline.Release() - if p.vertUniforms != nil { - p.vertUniforms.Release() - } - if p.fragUniforms != nil { - p.fragUniforms.Release() + if p.uniforms != nil { + p.uniforms.Release() } *p = pipeline{} } diff --git a/gpu/internal/d3d11/d3d11_windows.go b/gpu/internal/d3d11/d3d11_windows.go index f53fea0f..aada3ca2 100644 --- a/gpu/internal/d3d11/d3d11_windows.go +++ b/gpu/internal/d3d11/d3d11_windows.go @@ -681,13 +681,9 @@ func (b *Backend) BindStorageBuffer(binding int, buffer driver.Buffer) { } } -func (b *Backend) BindVertexUniforms(buffer driver.Buffer) { +func (b *Backend) BindUniforms(buffer driver.Buffer) { buf := buffer.(*Buffer) b.ctx.VSSetConstantBuffers(buf.buf) -} - -func (b *Backend) BindFragmentUniforms(buffer driver.Buffer) { - buf := buffer.(*Buffer) b.ctx.PSSetConstantBuffers(buf.buf) } diff --git a/gpu/internal/driver/driver.go b/gpu/internal/driver/driver.go index 08a1558c..670ca5f0 100644 --- a/gpu/internal/driver/driver.go +++ b/gpu/internal/driver/driver.go @@ -43,8 +43,7 @@ type Device interface { BindVertexBuffer(b Buffer, offset int) BindIndexBuffer(b Buffer) BindImageTexture(unit int, texture Texture, access AccessBits, format TextureFormat) - BindVertexUniforms(buf Buffer) - BindFragmentUniforms(buf Buffer) + BindUniforms(buf Buffer) BindStorageBuffer(binding int, buf Buffer) BeginCompute() diff --git a/gpu/internal/metal/metal_darwin.go b/gpu/internal/metal/metal_darwin.go index 3adb8749..b4f9ef7a 100644 --- a/gpu/internal/metal/metal_darwin.go +++ b/gpu/internal/metal/metal_darwin.go @@ -1005,20 +1005,9 @@ func (b *Backend) BindVertexUniforms(buf driver.Buffer) { } if bf.buffer != 0 { C.renderEncSetVertexBuffer(enc, bf.buffer, uniformBufferIndex, 0) - } else if bf.size > 0 { - C.renderEncSetVertexBytes(enc, unsafe.Pointer(&bf.store[0]), C.NSUInteger(bf.size), uniformBufferIndex) - } -} - -func (b *Backend) BindFragmentUniforms(buf driver.Buffer) { - bf := buf.(*Buffer) - enc := b.renderEnc - if enc == 0 { - panic("no active render pass") - } - if bf.buffer != 0 { C.renderEncSetFragmentBuffer(enc, bf.buffer, uniformBufferIndex, 0) } else if bf.size > 0 { + C.renderEncSetVertexBytes(enc, unsafe.Pointer(&bf.store[0]), C.NSUInteger(bf.size), uniformBufferIndex) C.renderEncSetFragmentBytes(enc, unsafe.Pointer(&bf.store[0]), C.NSUInteger(bf.size), uniformBufferIndex) } } diff --git a/gpu/internal/opengl/opengl.go b/gpu/internal/opengl/opengl.go index 832512bf..37f7c0c6 100644 --- a/gpu/internal/opengl/opengl.go +++ b/gpu/internal/opengl/opengl.go @@ -26,17 +26,14 @@ type Backend struct { glver [2]int gles bool - ubo bool feats driver.Caps // floatTriple holds the settings for floating point // textures. floatTriple textureTriple // Single channel alpha textures. - alphaTriple textureTriple - srgbaTriple textureTriple - vertUniforms *buffer - fragUniforms *buffer - storage [storageBindings]*buffer + alphaTriple textureTriple + srgbaTriple textureTriple + storage [storageBindings]*buffer sRGBFBO *SRGBFBO @@ -190,13 +187,10 @@ func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) { } floatTriple, ffboErr := floatTripleFor(f, ver, exts) srgbaTriple, srgbErr := srgbaTripleFor(ver, exts) - gles30 := gles && ver[0] >= 3 gles31 := gles && (ver[0] > 3 || (ver[0] == 3 && ver[1] >= 1)) - gl40 := !gles && ver[0] >= 4 b := &Backend{ glver: ver, gles: gles, - ubo: gles30 || gl40, funcs: f, floatTriple: floatTriple, alphaTriple: alphaTripleFor(ver), @@ -712,12 +706,9 @@ func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer, if typ != driver.BufferBindingUniforms { return nil, errors.New("uniforms buffers cannot be bound as anything else") } - if !b.ubo { - // GLES 2 doesn't support uniform buffers. - buf.data = make([]byte, size) - } + buf.data = make([]byte, size) } - if typ&^driver.BufferBindingUniforms != 0 || b.ubo { + if typ&^driver.BufferBindingUniforms != 0 { buf.hasBuffer = true buf.obj = b.funcs.CreateBuffer() if err := glErr(b.funcs); err != nil { @@ -841,7 +832,6 @@ func (b *Backend) prepareDraw() { return } b.setupVertexArrays() - p.prog.updateUniforms() } func toGLDrawMode(mode driver.Topology) gl.Enum { @@ -954,27 +944,8 @@ func (b *Backend) newProgram(desc driver.PipelineDesc) (*program, error) { b.funcs.Uniform1i(u, tex.Binding) } } - if b.ubo { - for _, block := range vsh.src.Uniforms.Blocks { - blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name) - if blockIdx != gl.INVALID_INDEX { - b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding)) - } - } - // To match Direct3D 11 with separate vertex and fragment - // shader uniform buffers, offset all fragment blocks to be - // located after the vertex blocks. - off := len(vsh.src.Uniforms.Blocks) - for _, block := range fsh.src.Uniforms.Blocks { - blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name) - if blockIdx != gl.INVALID_INDEX { - b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding+off)) - } - } - } else { - prog.vertUniforms.setup(b.funcs, p, vsh.src.Uniforms.Size, vsh.src.Uniforms.Locations) - prog.fragUniforms.setup(b.funcs, p, fsh.src.Uniforms.Size, fsh.src.Uniforms.Locations) - } + prog.vertUniforms.setup(b.funcs, p, vsh.src.Uniforms.Size, vsh.src.Uniforms.Locations) + prog.fragUniforms.setup(b.funcs, p, fsh.src.Uniforms.Size, fsh.src.Uniforms.Locations) return prog, nil } @@ -994,38 +965,13 @@ func (b *Backend) BindStorageBuffer(binding int, buf driver.Buffer) { b.storage[binding] = bf } -func (b *Backend) BindVertexUniforms(buf driver.Buffer) { +func (b *Backend) BindUniforms(buf driver.Buffer) { bf := buf.(*buffer) if bf.typ&driver.BufferBindingUniforms == 0 { panic("not a uniform buffer") } - b.vertUniforms = bf -} - -func (b *Backend) BindFragmentUniforms(buf driver.Buffer) { - bf := buf.(*buffer) - if bf.typ&driver.BufferBindingUniforms == 0 { - panic("not a uniform buffer") - } - b.fragUniforms = bf -} - -func (p *program) updateUniforms() { - f := p.backend.funcs - if b := p.backend.vertUniforms; b != nil { - if p.backend.ubo { - p.backend.glstate.bindBufferBase(f, gl.UNIFORM_BUFFER, 0, b.obj) - } else { - p.vertUniforms.update(f, b) - } - } - if b := p.backend.fragUniforms; b != nil { - if p.backend.ubo { - p.backend.glstate.bindBufferBase(f, gl.UNIFORM_BUFFER, 1, b.obj) - } else { - p.fragUniforms.update(f, b) - } - } + b.state.pipeline.prog.vertUniforms.update(b.funcs, bf) + b.state.pipeline.prog.fragUniforms.update(b.funcs, bf) } func (b *Backend) BindProgram(prog driver.Program) { diff --git a/gpu/path.go b/gpu/path.go index d28c7c96..1b384d09 100644 --- a/gpu/path.go +++ b/gpu/path.go @@ -37,30 +37,20 @@ type coverer struct { } type coverTexUniforms struct { - vert struct { - coverUniforms - _ [12]byte // Padding to multiple of 16. - } + coverUniforms + _ [12]byte // Padding to multiple of 16. } type coverColUniforms struct { - vert struct { - coverUniforms - _ [12]byte // Padding to multiple of 16. - } - frag struct { - colorUniforms - } + coverUniforms + _ [128 - unsafe.Sizeof(coverUniforms{}) - unsafe.Sizeof(colorUniforms{})]byte // Padding to 128 bytes. + colorUniforms } type coverLinearGradientUniforms struct { - vert struct { - coverUniforms - _ [12]byte // Padding to multiple of 16. - } - frag struct { - gradientUniforms - } + coverUniforms + _ [128 - unsafe.Sizeof(coverUniforms{}) - unsafe.Sizeof(gradientUniforms{})]byte // Padding to 128. + gradientUniforms } type coverUniforms struct { @@ -87,11 +77,9 @@ type stenciler struct { } type stencilUniforms struct { - vert struct { - transform [4]float32 - pathOffset [2]float32 - _ [8]byte // Padding to multiple of 16. - } + transform [4]float32 + pathOffset [2]float32 + _ [8]byte // Padding to multiple of 16. } type intersectUniforms struct { @@ -161,8 +149,7 @@ func newCoverer(ctx driver.Device) *coverer { c.texUniforms = new(coverTexUniforms) c.linearGradientUniforms = new(coverLinearGradientUniforms) pipelines, err := createColorPrograms(ctx, gio.Shader_cover_vert, gio.Shader_cover_frag, - [3]interface{}{&c.colUniforms.vert, &c.linearGradientUniforms.vert, &c.texUniforms.vert}, - [3]interface{}{&c.colUniforms.frag, &c.linearGradientUniforms.frag, nil}, + [3]interface{}{c.colUniforms, c.linearGradientUniforms, c.texUniforms}, ) if err != nil { panic(err) @@ -215,7 +202,7 @@ func newStenciler(ctx driver.Device) *stenciler { defer vsh.Release() defer fsh.Release() st.pipeline.uniforms = new(stencilUniforms) - vertUniforms := newUniformBuffer(ctx, &st.pipeline.uniforms.vert) + vertUniforms := newUniformBuffer(ctx, st.pipeline.uniforms) pipe, err := st.ctx.NewPipeline(driver.PipelineDesc{ VertexShader: vsh, FragmentShader: fsh, @@ -228,7 +215,7 @@ func newStenciler(ctx driver.Device) *stenciler { PixelFormat: driver.TextureFormatFloat, Topology: driver.TopologyTriangles, }) - st.pipeline.pipeline = &pipeline{pipe, vertUniforms, nil} + st.pipeline.pipeline = &pipeline{pipe, vertUniforms} if err != nil { panic(err) } @@ -252,7 +239,7 @@ func newStenciler(ctx driver.Device) *stenciler { PixelFormat: driver.TextureFormatFloat, Topology: driver.TopologyTriangleStrip, }) - st.ipipeline.pipeline = &pipeline{ipipe, vertUniforms, nil} + st.ipipeline.pipeline = &pipeline{ipipe, vertUniforms} return st } @@ -364,8 +351,8 @@ func (s *stenciler) stencilPath(bounds image.Rectangle, offset f32.Point, uv ima texSize := f32.Point{X: float32(bounds.Dx()), Y: float32(bounds.Dy())} scale := f32.Point{X: 2 / texSize.X, Y: 2 / texSize.Y} orig := f32.Point{X: -1 - float32(bounds.Min.X)*2/texSize.X, Y: -1 - float32(bounds.Min.Y)*2/texSize.Y} - s.pipeline.uniforms.vert.transform = [4]float32{scale.X, scale.Y, orig.X, orig.Y} - s.pipeline.uniforms.vert.pathOffset = [2]float32{offset.X, offset.Y} + s.pipeline.uniforms.transform = [4]float32{scale.X, scale.Y, orig.X, orig.Y} + s.pipeline.uniforms.pathOffset = [2]float32{offset.X, offset.Y} s.pipeline.pipeline.UploadUniforms(s.ctx) // Draw in batches that fit in uint16 indices. start := 0 @@ -390,21 +377,21 @@ func (c *coverer) cover(mat materialType, col f32color.RGBA, col1, col2 f32color var uniforms *coverUniforms switch mat { case materialColor: - c.colUniforms.frag.color = col - uniforms = &c.colUniforms.vert.coverUniforms + c.colUniforms.color = col + uniforms = &c.colUniforms.coverUniforms case materialLinearGradient: - c.linearGradientUniforms.frag.color1 = col1 - c.linearGradientUniforms.frag.color2 = col2 + c.linearGradientUniforms.color1 = col1 + c.linearGradientUniforms.color2 = col2 t1, t2, t3, t4, t5, t6 := uvTrans.Elems() - c.linearGradientUniforms.vert.uvTransformR1 = [4]float32{t1, t2, t3, 0} - c.linearGradientUniforms.vert.uvTransformR2 = [4]float32{t4, t5, t6, 0} - uniforms = &c.linearGradientUniforms.vert.coverUniforms + c.linearGradientUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0} + c.linearGradientUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0} + uniforms = &c.linearGradientUniforms.coverUniforms case materialTexture: t1, t2, t3, t4, t5, t6 := uvTrans.Elems() - c.texUniforms.vert.uvTransformR1 = [4]float32{t1, t2, t3, 0} - c.texUniforms.vert.uvTransformR2 = [4]float32{t4, t5, t6, 0} - uniforms = &c.texUniforms.vert.coverUniforms + c.texUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0} + c.texUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0} + uniforms = &c.texUniforms.coverUniforms } uniforms.transform = [4]float32{scale.X, scale.Y, off.X, off.Y} uniforms.uvCoverTransform = [4]float32{coverScale.X, coverScale.Y, coverOff.X, coverOff.Y}