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 <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-09-10 13:37:12 +02:00
parent 3a98f004f9
commit 21ca9d13a8
9 changed files with 99 additions and 224 deletions
+1 -1
View File
@@ -10,5 +10,5 @@ require (
require ( require (
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2
gioui.org/shader v1.0.2 gioui.org/shader v1.0.3
) )
+2 -2
View File
@@ -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-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 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc=
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ= 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.3 h1:xllhh4w2XWej9lfkHMtOtI3ES05T8xZzxrSSWbMZgTw=
gioui.org/shader v1.0.2/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= 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/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/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= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+20 -34
View File
@@ -88,11 +88,8 @@ type compute struct {
pipeline driver.Pipeline pipeline driver.Pipeline
buffer sizedBuffer buffer sizedBuffer
quads []materialVertex quads []materialVertex
vert struct { uniforms struct {
uniforms *materialVertUniforms u *materialUniforms
buf driver.Buffer
}
frag struct {
buf driver.Buffer buf driver.Buffer
} }
} }
@@ -172,13 +169,10 @@ type copyUniforms struct {
_ [8]byte // Pad to 16 bytes. _ [8]byte // Pad to 16 bytes.
} }
type materialVertUniforms struct { type materialUniforms struct {
scale [2]float32 scale [2]float32
pos [2]float32 pos [2]float32
} emulatesRGB float32
type materialFragUniforms struct {
emulateSRGB float32
_ [12]byte // Pad to 16 bytes _ [12]byte // Pad to 16 bytes
} }
@@ -504,25 +498,14 @@ func newCompute(ctx driver.Device) (*compute, error) {
return nil, err return nil, err
} }
g.materials.pipeline = pipe 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 { if err != nil {
g.Release() g.Release()
return nil, err return nil, err
} }
g.materials.vert.buf = buf g.materials.uniforms.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
for _, shader := range shaders { for _, shader := range shaders {
if !g.useCPU { if !g.useCPU {
@@ -874,7 +857,6 @@ func (g *compute) blitLayers(viewport image.Point) {
layers := g.collector.frame.layers layers := g.collector.frame.layers
g.ctx.Viewport(0, 0, viewport.X, viewport.Y) g.ctx.Viewport(0, 0, viewport.X, viewport.Y)
g.ctx.BindPipeline(g.output.blitPipeline) g.ctx.BindPipeline(g.output.blitPipeline)
g.ctx.BindVertexUniforms(g.output.uniBuf)
for len(layers) > 0 { for len(layers) > 0 {
g.output.layerVertices = g.output.layerVertices[:0] g.output.layerVertices = g.output.layerVertices[:0]
atlas := layers[0].alloc.atlas 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.pos = [2]float32{ox, oy}
g.output.uniforms.uvScale = [2]float32{1 / float32(atlas.size.X), 1 / float32(atlas.size.Y)} 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.output.uniBuf.Upload(byteslice.Struct(g.output.uniforms))
g.ctx.BindUniforms(g.output.uniBuf)
vertexData := byteslice.Slice(g.output.layerVertices) vertexData := byteslice.Slice(g.output.layerVertices)
g.output.buffer.ensureCapacity(false, g.ctx, driver.BufferBindingVertices, len(vertexData)) g.output.buffer.ensureCapacity(false, g.ctx, driver.BufferBindingVertices, len(vertexData))
g.output.buffer.buffer.Upload(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 // Transform to clip space: [-1, -1] - [1, 1] and flip Y-axis to cancel the implied transformation
// between framebuffer and texture space. // between framebuffer and texture space.
m.vert.uniforms.scale = [2]float32{2, -2} *m.uniforms.u = materialUniforms{
m.vert.uniforms.pos = [2]float32{-1, +1} scale: [2]float32{2, -2},
m.vert.buf.Upload(byteslice.Struct(m.vert.uniforms)) 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) vertexData := byteslice.Slice(m.quads)
n := pow2Ceil(len(vertexData)) n := pow2Ceil(len(vertexData))
m.buffer.ensureCapacity(false, g.ctx, driver.BufferBindingVertices, n) m.buffer.ensureCapacity(false, g.ctx, driver.BufferBindingVertices, n)
@@ -1013,10 +1001,9 @@ func (g *compute) renderMaterials() error {
d.Action = driver.LoadActionClear d.Action = driver.LoadActionClear
} }
g.ctx.BeginRenderPass(atlas.fbo, d) 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.BindTexture(0, imgAtlas.image)
g.ctx.BindPipeline(m.pipeline) g.ctx.BindPipeline(m.pipeline)
g.ctx.BindUniforms(m.uniforms.buf)
g.ctx.BindVertexBuffer(m.buffer.buffer, 0) g.ctx.BindVertexBuffer(m.buffer.buffer, 0)
newAllocs := atlas.allocs[allocStart:] newAllocs := atlas.allocs[allocStart:]
for i, a := range newAllocs { for i, a := range newAllocs {
@@ -1507,8 +1494,7 @@ func (g *compute) Release() {
&g.buffers.config, &g.buffers.config,
g.materials.pipeline, g.materials.pipeline,
&g.materials.buffer, &g.materials.buffer,
g.materials.vert.buf, g.materials.uniforms.buf,
g.materials.frag.buf,
g.timers.t, g.timers.t,
} }
for _, r := range res { for _, r := range res {
+36 -64
View File
@@ -282,30 +282,20 @@ type blitter struct {
} }
type blitColUniforms struct { type blitColUniforms struct {
vert struct { blitUniforms
blitUniforms _ [128 - unsafe.Sizeof(blitUniforms{}) - unsafe.Sizeof(colorUniforms{})]byte // Padding to 128 bytes.
_ [12]byte // Padding to a multiple of 16. colorUniforms
}
frag struct {
colorUniforms
}
} }
type blitTexUniforms struct { type blitTexUniforms struct {
vert struct { blitUniforms
blitUniforms _ [12]byte // Padding to 16 bytes.
_ [12]byte // Padding to a multiple of 16.
}
} }
type blitLinearGradientUniforms struct { type blitLinearGradientUniforms struct {
vert struct { blitUniforms
blitUniforms _ [128 - unsafe.Sizeof(blitUniforms{}) - unsafe.Sizeof(gradientUniforms{})]byte // Padding to 128 bytes.
_ [12]byte // Padding to a multiple of 16. gradientUniforms
}
frag struct {
gradientUniforms
}
} }
type uniformBuffer struct { type uniformBuffer struct {
@@ -314,9 +304,8 @@ type uniformBuffer struct {
} }
type pipeline struct { type pipeline struct {
pipeline driver.Pipeline pipeline driver.Pipeline
vertUniforms *uniformBuffer uniforms *uniformBuffer
fragUniforms *uniformBuffer
} }
type blitUniforms struct { type blitUniforms struct {
@@ -536,8 +525,7 @@ func newBlitter(ctx driver.Device) *blitter {
b.texUniforms = new(blitTexUniforms) b.texUniforms = new(blitTexUniforms)
b.linearGradientUniforms = new(blitLinearGradientUniforms) b.linearGradientUniforms = new(blitLinearGradientUniforms)
pipelines, err := createColorPrograms(ctx, gio.Shader_blit_vert, gio.Shader_blit_frag, 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, b.linearGradientUniforms, b.texUniforms},
[3]interface{}{&b.colUniforms.frag, &b.linearGradientUniforms.frag, nil},
) )
if err != nil { if err != nil {
panic(err) 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 var pipelines [3]*pipeline
blend := driver.BlendDesc{ blend := driver.BlendDesc{
Enable: true, Enable: true,
@@ -589,17 +577,14 @@ func createColorPrograms(b driver.Device, vsSrc shader.Sources, fsSrc [3]shader.
if err != nil { if err != nil {
return pipelines, err return pipelines, err
} }
var vertBuffer, fragBuffer *uniformBuffer var vertBuffer *uniformBuffer
if u := vertUniforms[materialTexture]; u != nil { if u := uniforms[materialTexture]; u != nil {
vertBuffer = newUniformBuffer(b, u) vertBuffer = newUniformBuffer(b, u)
} }
if u := fragUniforms[materialTexture]; u != nil { pipelines[materialTexture] = &pipeline{pipe, vertBuffer}
fragBuffer = newUniformBuffer(b, u)
}
pipelines[materialTexture] = &pipeline{pipe, vertBuffer, fragBuffer}
} }
{ {
var vertBuffer, fragBuffer *uniformBuffer var vertBuffer *uniformBuffer
fsh, err := b.NewFragmentShader(fsSrc[materialColor]) fsh, err := b.NewFragmentShader(fsSrc[materialColor])
if err != nil { if err != nil {
pipelines[materialTexture].Release() pipelines[materialTexture].Release()
@@ -618,16 +603,13 @@ func createColorPrograms(b driver.Device, vsSrc shader.Sources, fsSrc [3]shader.
pipelines[materialTexture].Release() pipelines[materialTexture].Release()
return pipelines, err return pipelines, err
} }
if u := vertUniforms[materialColor]; u != nil { if u := uniforms[materialColor]; u != nil {
vertBuffer = newUniformBuffer(b, u) vertBuffer = newUniformBuffer(b, u)
} }
if u := fragUniforms[materialColor]; u != nil { pipelines[materialColor] = &pipeline{pipe, vertBuffer}
fragBuffer = newUniformBuffer(b, u)
}
pipelines[materialColor] = &pipeline{pipe, vertBuffer, fragBuffer}
} }
{ {
var vertBuffer, fragBuffer *uniformBuffer var vertBuffer *uniformBuffer
fsh, err := b.NewFragmentShader(fsSrc[materialLinearGradient]) fsh, err := b.NewFragmentShader(fsSrc[materialLinearGradient])
if err != nil { if err != nil {
pipelines[materialTexture].Release() pipelines[materialTexture].Release()
@@ -648,13 +630,10 @@ func createColorPrograms(b driver.Device, vsSrc shader.Sources, fsSrc [3]shader.
pipelines[materialColor].Release() pipelines[materialColor].Release()
return pipelines, err return pipelines, err
} }
if u := vertUniforms[materialLinearGradient]; u != nil { if u := uniforms[materialLinearGradient]; u != nil {
vertBuffer = newUniformBuffer(b, u) vertBuffer = newUniformBuffer(b, u)
} }
if u := fragUniforms[materialLinearGradient]; u != nil { pipelines[materialLinearGradient] = &pipeline{pipe, vertBuffer}
fragBuffer = newUniformBuffer(b, u)
}
pipelines[materialLinearGradient] = &pipeline{pipe, vertBuffer, fragBuffer}
} }
if err != nil { if err != nil {
for _, p := range pipelines { for _, p := range pipelines {
@@ -1151,21 +1130,21 @@ func (b *blitter) blit(mat materialType, col f32color.RGBA, col1, col2 f32color.
var uniforms *blitUniforms var uniforms *blitUniforms
switch mat { switch mat {
case materialColor: case materialColor:
b.colUniforms.frag.color = col b.colUniforms.color = col
uniforms = &b.colUniforms.vert.blitUniforms uniforms = &b.colUniforms.blitUniforms
case materialTexture: case materialTexture:
t1, t2, t3, t4, t5, t6 := uvTrans.Elems() t1, t2, t3, t4, t5, t6 := uvTrans.Elems()
b.texUniforms.vert.blitUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0} b.texUniforms.blitUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0}
b.texUniforms.vert.blitUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0} b.texUniforms.blitUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0}
uniforms = &b.texUniforms.vert.blitUniforms uniforms = &b.texUniforms.blitUniforms
case materialLinearGradient: case materialLinearGradient:
b.linearGradientUniforms.frag.color1 = col1 b.linearGradientUniforms.color1 = col1
b.linearGradientUniforms.frag.color2 = col2 b.linearGradientUniforms.color2 = col2
t1, t2, t3, t4, t5, t6 := uvTrans.Elems() t1, t2, t3, t4, t5, t6 := uvTrans.Elems()
b.linearGradientUniforms.vert.blitUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0} b.linearGradientUniforms.blitUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0}
b.linearGradientUniforms.vert.blitUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0} b.linearGradientUniforms.blitUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0}
uniforms = &b.linearGradientUniforms.vert.blitUniforms uniforms = &b.linearGradientUniforms.blitUniforms
} }
uniforms.transform = [4]float32{scale.X, scale.Y, off.X, off.Y} uniforms.transform = [4]float32{scale.X, scale.Y, off.X, off.Y}
p.UploadUniforms(b.ctx) p.UploadUniforms(b.ctx)
@@ -1197,23 +1176,16 @@ func (u *uniformBuffer) Release() {
} }
func (p *pipeline) UploadUniforms(ctx driver.Device) { func (p *pipeline) UploadUniforms(ctx driver.Device) {
if p.vertUniforms != nil { if p.uniforms != nil {
p.vertUniforms.Upload() p.uniforms.Upload()
ctx.BindVertexUniforms(p.vertUniforms.buf) ctx.BindUniforms(p.uniforms.buf)
}
if p.fragUniforms != nil {
p.fragUniforms.Upload()
ctx.BindFragmentUniforms(p.fragUniforms.buf)
} }
} }
func (p *pipeline) Release() { func (p *pipeline) Release() {
p.pipeline.Release() p.pipeline.Release()
if p.vertUniforms != nil { if p.uniforms != nil {
p.vertUniforms.Release() p.uniforms.Release()
}
if p.fragUniforms != nil {
p.fragUniforms.Release()
} }
*p = pipeline{} *p = pipeline{}
} }
+1 -5
View File
@@ -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) buf := buffer.(*Buffer)
b.ctx.VSSetConstantBuffers(buf.buf) b.ctx.VSSetConstantBuffers(buf.buf)
}
func (b *Backend) BindFragmentUniforms(buffer driver.Buffer) {
buf := buffer.(*Buffer)
b.ctx.PSSetConstantBuffers(buf.buf) b.ctx.PSSetConstantBuffers(buf.buf)
} }
+1 -2
View File
@@ -43,8 +43,7 @@ type Device interface {
BindVertexBuffer(b Buffer, offset int) BindVertexBuffer(b Buffer, offset int)
BindIndexBuffer(b Buffer) BindIndexBuffer(b Buffer)
BindImageTexture(unit int, texture Texture, access AccessBits, format TextureFormat) BindImageTexture(unit int, texture Texture, access AccessBits, format TextureFormat)
BindVertexUniforms(buf Buffer) BindUniforms(buf Buffer)
BindFragmentUniforms(buf Buffer)
BindStorageBuffer(binding int, buf Buffer) BindStorageBuffer(binding int, buf Buffer)
BeginCompute() BeginCompute()
+1 -12
View File
@@ -1005,20 +1005,9 @@ func (b *Backend) BindVertexUniforms(buf driver.Buffer) {
} }
if bf.buffer != 0 { if bf.buffer != 0 {
C.renderEncSetVertexBuffer(enc, bf.buffer, uniformBufferIndex, 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) C.renderEncSetFragmentBuffer(enc, bf.buffer, uniformBufferIndex, 0)
} else if bf.size > 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) C.renderEncSetFragmentBytes(enc, unsafe.Pointer(&bf.store[0]), C.NSUInteger(bf.size), uniformBufferIndex)
} }
} }
+10 -64
View File
@@ -26,17 +26,14 @@ type Backend struct {
glver [2]int glver [2]int
gles bool gles bool
ubo bool
feats driver.Caps feats driver.Caps
// floatTriple holds the settings for floating point // floatTriple holds the settings for floating point
// textures. // textures.
floatTriple textureTriple floatTriple textureTriple
// Single channel alpha textures. // Single channel alpha textures.
alphaTriple textureTriple alphaTriple textureTriple
srgbaTriple textureTriple srgbaTriple textureTriple
vertUniforms *buffer storage [storageBindings]*buffer
fragUniforms *buffer
storage [storageBindings]*buffer
sRGBFBO *SRGBFBO sRGBFBO *SRGBFBO
@@ -190,13 +187,10 @@ func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) {
} }
floatTriple, ffboErr := floatTripleFor(f, ver, exts) floatTriple, ffboErr := floatTripleFor(f, ver, exts)
srgbaTriple, srgbErr := srgbaTripleFor(ver, exts) srgbaTriple, srgbErr := srgbaTripleFor(ver, exts)
gles30 := gles && ver[0] >= 3
gles31 := gles && (ver[0] > 3 || (ver[0] == 3 && ver[1] >= 1)) gles31 := gles && (ver[0] > 3 || (ver[0] == 3 && ver[1] >= 1))
gl40 := !gles && ver[0] >= 4
b := &Backend{ b := &Backend{
glver: ver, glver: ver,
gles: gles, gles: gles,
ubo: gles30 || gl40,
funcs: f, funcs: f,
floatTriple: floatTriple, floatTriple: floatTriple,
alphaTriple: alphaTripleFor(ver), alphaTriple: alphaTripleFor(ver),
@@ -712,12 +706,9 @@ func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer,
if typ != driver.BufferBindingUniforms { if typ != driver.BufferBindingUniforms {
return nil, errors.New("uniforms buffers cannot be bound as anything else") return nil, errors.New("uniforms buffers cannot be bound as anything else")
} }
if !b.ubo { buf.data = make([]byte, size)
// GLES 2 doesn't support uniform buffers.
buf.data = make([]byte, size)
}
} }
if typ&^driver.BufferBindingUniforms != 0 || b.ubo { if typ&^driver.BufferBindingUniforms != 0 {
buf.hasBuffer = true buf.hasBuffer = true
buf.obj = b.funcs.CreateBuffer() buf.obj = b.funcs.CreateBuffer()
if err := glErr(b.funcs); err != nil { if err := glErr(b.funcs); err != nil {
@@ -841,7 +832,6 @@ func (b *Backend) prepareDraw() {
return return
} }
b.setupVertexArrays() b.setupVertexArrays()
p.prog.updateUniforms()
} }
func toGLDrawMode(mode driver.Topology) gl.Enum { 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) b.funcs.Uniform1i(u, tex.Binding)
} }
} }
if b.ubo { prog.vertUniforms.setup(b.funcs, p, vsh.src.Uniforms.Size, vsh.src.Uniforms.Locations)
for _, block := range vsh.src.Uniforms.Blocks { prog.fragUniforms.setup(b.funcs, p, fsh.src.Uniforms.Size, fsh.src.Uniforms.Locations)
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)
}
return prog, nil return prog, nil
} }
@@ -994,38 +965,13 @@ func (b *Backend) BindStorageBuffer(binding int, buf driver.Buffer) {
b.storage[binding] = bf b.storage[binding] = bf
} }
func (b *Backend) BindVertexUniforms(buf driver.Buffer) { func (b *Backend) BindUniforms(buf driver.Buffer) {
bf := buf.(*buffer) bf := buf.(*buffer)
if bf.typ&driver.BufferBindingUniforms == 0 { if bf.typ&driver.BufferBindingUniforms == 0 {
panic("not a uniform buffer") panic("not a uniform buffer")
} }
b.vertUniforms = bf b.state.pipeline.prog.vertUniforms.update(b.funcs, bf)
} b.state.pipeline.prog.fragUniforms.update(b.funcs, 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)
}
}
} }
func (b *Backend) BindProgram(prog driver.Program) { func (b *Backend) BindProgram(prog driver.Program) {
+27 -40
View File
@@ -37,30 +37,20 @@ type coverer struct {
} }
type coverTexUniforms struct { type coverTexUniforms struct {
vert struct { coverUniforms
coverUniforms _ [12]byte // Padding to multiple of 16.
_ [12]byte // Padding to multiple of 16.
}
} }
type coverColUniforms struct { type coverColUniforms struct {
vert struct { coverUniforms
coverUniforms _ [128 - unsafe.Sizeof(coverUniforms{}) - unsafe.Sizeof(colorUniforms{})]byte // Padding to 128 bytes.
_ [12]byte // Padding to multiple of 16. colorUniforms
}
frag struct {
colorUniforms
}
} }
type coverLinearGradientUniforms struct { type coverLinearGradientUniforms struct {
vert struct { coverUniforms
coverUniforms _ [128 - unsafe.Sizeof(coverUniforms{}) - unsafe.Sizeof(gradientUniforms{})]byte // Padding to 128.
_ [12]byte // Padding to multiple of 16. gradientUniforms
}
frag struct {
gradientUniforms
}
} }
type coverUniforms struct { type coverUniforms struct {
@@ -87,11 +77,9 @@ type stenciler struct {
} }
type stencilUniforms struct { type stencilUniforms struct {
vert struct { transform [4]float32
transform [4]float32 pathOffset [2]float32
pathOffset [2]float32 _ [8]byte // Padding to multiple of 16.
_ [8]byte // Padding to multiple of 16.
}
} }
type intersectUniforms struct { type intersectUniforms struct {
@@ -161,8 +149,7 @@ func newCoverer(ctx driver.Device) *coverer {
c.texUniforms = new(coverTexUniforms) c.texUniforms = new(coverTexUniforms)
c.linearGradientUniforms = new(coverLinearGradientUniforms) c.linearGradientUniforms = new(coverLinearGradientUniforms)
pipelines, err := createColorPrograms(ctx, gio.Shader_cover_vert, gio.Shader_cover_frag, 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, c.linearGradientUniforms, c.texUniforms},
[3]interface{}{&c.colUniforms.frag, &c.linearGradientUniforms.frag, nil},
) )
if err != nil { if err != nil {
panic(err) panic(err)
@@ -215,7 +202,7 @@ func newStenciler(ctx driver.Device) *stenciler {
defer vsh.Release() defer vsh.Release()
defer fsh.Release() defer fsh.Release()
st.pipeline.uniforms = new(stencilUniforms) 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{ pipe, err := st.ctx.NewPipeline(driver.PipelineDesc{
VertexShader: vsh, VertexShader: vsh,
FragmentShader: fsh, FragmentShader: fsh,
@@ -228,7 +215,7 @@ func newStenciler(ctx driver.Device) *stenciler {
PixelFormat: driver.TextureFormatFloat, PixelFormat: driver.TextureFormatFloat,
Topology: driver.TopologyTriangles, Topology: driver.TopologyTriangles,
}) })
st.pipeline.pipeline = &pipeline{pipe, vertUniforms, nil} st.pipeline.pipeline = &pipeline{pipe, vertUniforms}
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -252,7 +239,7 @@ func newStenciler(ctx driver.Device) *stenciler {
PixelFormat: driver.TextureFormatFloat, PixelFormat: driver.TextureFormatFloat,
Topology: driver.TopologyTriangleStrip, Topology: driver.TopologyTriangleStrip,
}) })
st.ipipeline.pipeline = &pipeline{ipipe, vertUniforms, nil} st.ipipeline.pipeline = &pipeline{ipipe, vertUniforms}
return st 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())} texSize := f32.Point{X: float32(bounds.Dx()), Y: float32(bounds.Dy())}
scale := f32.Point{X: 2 / texSize.X, Y: 2 / texSize.Y} 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} 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.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.pathOffset = [2]float32{offset.X, offset.Y}
s.pipeline.pipeline.UploadUniforms(s.ctx) s.pipeline.pipeline.UploadUniforms(s.ctx)
// Draw in batches that fit in uint16 indices. // Draw in batches that fit in uint16 indices.
start := 0 start := 0
@@ -390,21 +377,21 @@ func (c *coverer) cover(mat materialType, col f32color.RGBA, col1, col2 f32color
var uniforms *coverUniforms var uniforms *coverUniforms
switch mat { switch mat {
case materialColor: case materialColor:
c.colUniforms.frag.color = col c.colUniforms.color = col
uniforms = &c.colUniforms.vert.coverUniforms uniforms = &c.colUniforms.coverUniforms
case materialLinearGradient: case materialLinearGradient:
c.linearGradientUniforms.frag.color1 = col1 c.linearGradientUniforms.color1 = col1
c.linearGradientUniforms.frag.color2 = col2 c.linearGradientUniforms.color2 = col2
t1, t2, t3, t4, t5, t6 := uvTrans.Elems() t1, t2, t3, t4, t5, t6 := uvTrans.Elems()
c.linearGradientUniforms.vert.uvTransformR1 = [4]float32{t1, t2, t3, 0} c.linearGradientUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0}
c.linearGradientUniforms.vert.uvTransformR2 = [4]float32{t4, t5, t6, 0} c.linearGradientUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0}
uniforms = &c.linearGradientUniforms.vert.coverUniforms uniforms = &c.linearGradientUniforms.coverUniforms
case materialTexture: case materialTexture:
t1, t2, t3, t4, t5, t6 := uvTrans.Elems() t1, t2, t3, t4, t5, t6 := uvTrans.Elems()
c.texUniforms.vert.uvTransformR1 = [4]float32{t1, t2, t3, 0} c.texUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0}
c.texUniforms.vert.uvTransformR2 = [4]float32{t4, t5, t6, 0} c.texUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0}
uniforms = &c.texUniforms.vert.coverUniforms uniforms = &c.texUniforms.coverUniforms
} }
uniforms.transform = [4]float32{scale.X, scale.Y, off.X, off.Y} uniforms.transform = [4]float32{scale.X, scale.Y, off.X, off.Y}
uniforms.uvCoverTransform = [4]float32{coverScale.X, coverScale.Y, coverOff.X, coverOff.Y} uniforms.uvCoverTransform = [4]float32{coverScale.X, coverScale.Y, coverOff.X, coverOff.Y}