gpu,gpu/internal: move vertex buffer stride to pipeline state

Metal needs the vertex stride at pipeline creation.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-08-11 16:27:25 +02:00
parent 1af910959b
commit 58cc817e5f
7 changed files with 76 additions and 44 deletions
+14 -8
View File
@@ -422,9 +422,12 @@ func newCompute(ctx driver.Device) (*compute, error) {
pipe, err := ctx.NewPipeline(driver.PipelineDesc{ pipe, err := ctx.NewPipeline(driver.PipelineDesc{
VertexShader: copyVert, VertexShader: copyVert,
FragmentShader: copyFrag, FragmentShader: copyFrag,
VertexLayout: []driver.InputDesc{ VertexLayout: driver.VertexLayout{
{Type: shader.DataTypeFloat, Size: 2, Offset: 0}, Inputs: []driver.InputDesc{
{Type: shader.DataTypeFloat, Size: 2, Offset: 4 * 2}, {Type: shader.DataTypeFloat, Size: 2, Offset: 0},
{Type: shader.DataTypeFloat, Size: 2, Offset: 4 * 2},
},
Stride: int(unsafe.Sizeof(g.output.layerVertices[0])),
}, },
PixelFormat: driver.TextureFormatOutput, PixelFormat: driver.TextureFormatOutput,
BlendDesc: driver.BlendDesc{ BlendDesc: driver.BlendDesc{
@@ -457,9 +460,12 @@ func newCompute(ctx driver.Device) (*compute, error) {
pipe, err = ctx.NewPipeline(driver.PipelineDesc{ pipe, err = ctx.NewPipeline(driver.PipelineDesc{
VertexShader: materialVert, VertexShader: materialVert,
FragmentShader: materialFrag, FragmentShader: materialFrag,
VertexLayout: []driver.InputDesc{ VertexLayout: driver.VertexLayout{
{Type: shader.DataTypeFloat, Size: 2, Offset: 0}, Inputs: []driver.InputDesc{
{Type: shader.DataTypeFloat, Size: 2, Offset: 4 * 2}, {Type: shader.DataTypeFloat, Size: 2, Offset: 0},
{Type: shader.DataTypeFloat, Size: 2, Offset: 4 * 2},
},
Stride: int(unsafe.Sizeof(g.materials.quads[0])),
}, },
PixelFormat: driver.TextureFormatRGBA8, PixelFormat: driver.TextureFormatRGBA8,
}) })
@@ -817,7 +823,7 @@ func (g *compute) blitLayers(viewport image.Point) {
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)
g.ctx.BindVertexBuffer(g.output.buffer.buffer, int(unsafe.Sizeof(g.output.layerVertices[0])), 0) g.ctx.BindVertexBuffer(g.output.buffer.buffer, 0)
g.ctx.BindTexture(0, atlas.image) g.ctx.BindTexture(0, atlas.image)
g.ctx.DrawArrays(driver.DrawModeTriangles, 0, len(g.output.layerVertices)) g.ctx.DrawArrays(driver.DrawModeTriangles, 0, len(g.output.layerVertices))
} }
@@ -931,7 +937,7 @@ restart:
g.ctx.BindFramebuffer(m.fbo, d) g.ctx.BindFramebuffer(m.fbo, d)
g.ctx.Viewport(0, 0, texSize, texSize) g.ctx.Viewport(0, 0, texSize, texSize)
g.ctx.BindPipeline(m.pipeline) g.ctx.BindPipeline(m.pipeline)
g.ctx.BindVertexBuffer(m.buffer.buffer, int(unsafe.Sizeof(m.quads[0])), 0) g.ctx.BindVertexBuffer(m.buffer.buffer, 0)
g.ctx.DrawArrays(driver.DrawModeTriangles, 0, len(m.quads)) g.ctx.DrawArrays(driver.DrawModeTriangles, 0, len(m.quads))
return nil return nil
} }
+8 -5
View File
@@ -580,9 +580,12 @@ func createColorPrograms(b driver.Device, vsSrc shader.Sources, fsSrc [3]shader.
SrcFactor: driver.BlendFactorOne, SrcFactor: driver.BlendFactorOne,
DstFactor: driver.BlendFactorOneMinusSrcAlpha, DstFactor: driver.BlendFactorOneMinusSrcAlpha,
} }
layout := []driver.InputDesc{ layout := driver.VertexLayout{
{Type: shader.DataTypeFloat, Size: 2, Offset: 0}, Inputs: []driver.InputDesc{
{Type: shader.DataTypeFloat, Size: 2, Offset: 4 * 2}, {Type: shader.DataTypeFloat, Size: 2, Offset: 0},
{Type: shader.DataTypeFloat, Size: 2, Offset: 4 * 2},
},
Stride: 4 * 4,
} }
vsh, err := b.NewVertexShader(vsSrc) vsh, err := b.NewVertexShader(vsSrc)
if err != nil { if err != nil {
@@ -702,7 +705,7 @@ 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.ctx.BindVertexBuffer(r.blitter.quadVerts, 4*4, 0) r.ctx.BindVertexBuffer(r.blitter.quadVerts, 0)
for _, img := range ops { for _, img := range ops {
if img.clipType != clipTypeIntersection { if img.clipType != clipTypeIntersection {
continue continue
@@ -1093,7 +1096,7 @@ func (d *drawState) materialFor(rect f32.Rectangle, off f32.Point, partTrans f32
} }
func (r *renderer) drawOps(cache *resourceCache, ops []imageOp) { func (r *renderer) drawOps(cache *resourceCache, ops []imageOp) {
r.ctx.BindVertexBuffer(r.blitter.quadVerts, 4*4, 0) r.ctx.BindVertexBuffer(r.blitter.quadVerts, 0)
var coverTex driver.Texture var coverTex driver.Texture
for _, img := range ops { for _, img := range ops {
m := img.material m := img.material
+9 -6
View File
@@ -77,12 +77,15 @@ func TestInputShader(t *testing.T) {
} }
defer vsh.Release() defer vsh.Release()
defer fsh.Release() defer fsh.Release()
layout := []driver.InputDesc{ layout := driver.VertexLayout{
{ Inputs: []driver.InputDesc{
Type: shader.DataTypeFloat, {
Size: 4, Type: shader.DataTypeFloat,
Offset: 0, Size: 4,
Offset: 0,
},
}, },
Stride: 4 * 4,
} }
pipe, err := b.NewPipeline(driver.PipelineDesc{ pipe, err := b.NewPipeline(driver.PipelineDesc{
VertexShader: vsh, VertexShader: vsh,
@@ -106,7 +109,7 @@ func TestInputShader(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer buf.Release() defer buf.Release()
b.BindVertexBuffer(buf, 4*4, 0) b.BindVertexBuffer(buf, 0)
b.DrawArrays(driver.DrawModeTriangles, 0, 3) b.DrawArrays(driver.DrawModeTriangles, 0, 3)
img := screenshot(t, b, fbo, sz) img := screenshot(t, b, fbo, sz)
if got := img.RGBAAt(0, 0); got != clearColExpect { if got := img.RGBAAt(0, 0); got != clearColExpect {
+14 -4
View File
@@ -26,6 +26,10 @@ type Backend struct {
viewport d3d11.VIEWPORT viewport d3d11.VIEWPORT
pipeline *Pipeline pipeline *Pipeline
vert struct {
buffer *Buffer
offset int
}
caps driver.Caps caps driver.Caps
@@ -40,6 +44,7 @@ type Pipeline struct {
frag *d3d11.PixelShader frag *d3d11.PixelShader
layout *d3d11.InputLayout layout *d3d11.InputLayout
blend *d3d11.BlendState blend *d3d11.BlendState
stride int
} }
type Texture struct { type Texture struct {
@@ -375,9 +380,9 @@ func (b *Backend) NewPipeline(desc driver.PipelineDesc) (driver.Pipeline, error)
return nil, err return nil, err
} }
var layout *d3d11.InputLayout var layout *d3d11.InputLayout
if l := desc.VertexLayout; l != nil { if l := desc.VertexLayout; l.Stride > 0 {
var err error var err error
layout, err = b.newInputLayout(vsh.src, l) layout, err = b.newInputLayout(vsh.src, l.Inputs)
if err != nil { if err != nil {
d3d11.IUnknownRelease(unsafe.Pointer(blend), blend.Vtbl.AddRef) d3d11.IUnknownRelease(unsafe.Pointer(blend), blend.Vtbl.AddRef)
return nil, err return nil, err
@@ -394,6 +399,7 @@ func (b *Backend) NewPipeline(desc driver.PipelineDesc) (driver.Pipeline, error)
vert: vshRef, vert: vshRef,
frag: fshRef, frag: fshRef,
layout: layout, layout: layout,
stride: desc.VertexLayout.Stride,
blend: blend, blend: blend,
}, nil }, nil
} }
@@ -460,6 +466,9 @@ func (b *Backend) prepareDraw(mode driver.DrawMode) {
b.ctx.PSSetShader(p.frag) b.ctx.PSSetShader(p.frag)
b.ctx.IASetInputLayout(p.layout) b.ctx.IASetInputLayout(p.layout)
b.ctx.OMSetBlendState(p.blend, nil, 0xffffffff) b.ctx.OMSetBlendState(p.blend, nil, 0xffffffff)
if b.vert.buffer != nil {
b.ctx.IASetVertexBuffers(b.vert.buffer.buf, uint32(p.stride), uint32(b.vert.offset))
}
} }
var topology uint32 var topology uint32
switch mode { switch mode {
@@ -562,8 +571,9 @@ func (b *Backend) BindFragmentUniforms(buffer driver.Buffer) {
b.ctx.PSSetConstantBuffers(buf.buf) b.ctx.PSSetConstantBuffers(buf.buf)
} }
func (b *Backend) BindVertexBuffer(buf driver.Buffer, stride, offset int) { func (b *Backend) BindVertexBuffer(buf driver.Buffer, offset int) {
b.ctx.IASetVertexBuffers(buf.(*Buffer).buf, uint32(stride), uint32(offset)) b.vert.buffer = buf.(*Buffer)
b.vert.offset = offset
} }
func (b *Backend) BindIndexBuffer(buf driver.Buffer) { func (b *Backend) BindIndexBuffer(buf driver.Buffer) {
+7 -2
View File
@@ -38,7 +38,7 @@ type Device interface {
BindPipeline(p Pipeline) BindPipeline(p Pipeline)
BindFramebuffer(f Framebuffer, a LoadDesc) BindFramebuffer(f Framebuffer, a LoadDesc)
BindTexture(unit int, t Texture) BindTexture(unit int, t Texture)
BindVertexBuffer(b Buffer, stride, 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) BindVertexUniforms(buf Buffer)
@@ -69,11 +69,16 @@ type Pipeline interface {
type PipelineDesc struct { type PipelineDesc struct {
VertexShader VertexShader VertexShader VertexShader
FragmentShader FragmentShader FragmentShader FragmentShader
VertexLayout []InputDesc VertexLayout VertexLayout
BlendDesc BlendDesc BlendDesc BlendDesc
PixelFormat TextureFormat PixelFormat TextureFormat
} }
type VertexLayout struct {
Inputs []InputDesc
Stride int
}
// InputDesc describes a vertex attribute as laid out in a Buffer. // InputDesc describes a vertex attribute as laid out in a Buffer.
type InputDesc struct { type InputDesc struct {
Type shader.DataType Type shader.DataType
+8 -9
View File
@@ -90,7 +90,6 @@ type state struct {
type bufferBinding struct { type bufferBinding struct {
obj gl.Buffer obj gl.Buffer
offset int offset int
stride int
} }
type timer struct { type timer struct {
@@ -115,7 +114,7 @@ type framebuffer struct {
type pipeline struct { type pipeline struct {
prog *program prog *program
inputs []shader.InputLocation inputs []shader.InputLocation
layout []driver.InputDesc layout driver.VertexLayout
blend driver.BlendDesc blend driver.BlendDesc
} }
@@ -900,11 +899,11 @@ func (b *Backend) NewPipeline(desc driver.PipelineDesc) (driver.Pipeline, error)
} }
layout := desc.VertexLayout layout := desc.VertexLayout
vsrc := desc.VertexShader.(*glshader).src vsrc := desc.VertexShader.(*glshader).src
if len(vsrc.Inputs) != len(layout) { if len(vsrc.Inputs) != len(layout.Inputs) {
return nil, fmt.Errorf("opengl: got %d inputs, expected %d", len(layout), len(vsrc.Inputs)) return nil, fmt.Errorf("opengl: got %d inputs, expected %d", len(layout.Inputs), len(vsrc.Inputs))
} }
for i, inp := range vsrc.Inputs { for i, inp := range vsrc.Inputs {
if exp, got := inp.Size, layout[i].Size; exp != got { if exp, got := inp.Size, layout.Inputs[i].Size; exp != got {
return nil, fmt.Errorf("opengl: data size mismatch for %q: got %d expected %d", inp.Name, got, exp) return nil, fmt.Errorf("opengl: data size mismatch for %q: got %d expected %d", inp.Name, got, exp)
} }
} }
@@ -1122,12 +1121,12 @@ func (b *buffer) Release() {
} }
} }
func (b *Backend) BindVertexBuffer(buf driver.Buffer, stride, offset int) { func (b *Backend) BindVertexBuffer(buf driver.Buffer, offset int) {
gbuf := buf.(*buffer) gbuf := buf.(*buffer)
if gbuf.typ&driver.BufferBindingVertices == 0 { if gbuf.typ&driver.BufferBindingVertices == 0 {
panic("not a vertex buffer") panic("not a vertex buffer")
} }
b.state.buffer = bufferBinding{obj: gbuf.obj, stride: stride, offset: offset} b.state.buffer = bufferBinding{obj: gbuf.obj, offset: offset}
} }
func (b *Backend) setupVertexArrays() { func (b *Backend) setupVertexArrays() {
@@ -1141,7 +1140,7 @@ func (b *Backend) setupVertexArrays() {
var enabled [max]bool var enabled [max]bool
buf := b.state.buffer buf := b.state.buffer
for i, inp := range inputs { for i, inp := range inputs {
l := layout[i] l := layout.Inputs[i]
var gltyp gl.Enum var gltyp gl.Enum
switch l.Type { switch l.Type {
case shader.DataTypeFloat: case shader.DataTypeFloat:
@@ -1152,7 +1151,7 @@ func (b *Backend) setupVertexArrays() {
panic("unsupported data type") panic("unsupported data type")
} }
enabled[inp.Location] = true enabled[inp.Location] = true
b.glstate.vertexAttribPointer(b.funcs, buf.obj, inp.Location, l.Size, gltyp, false, buf.stride, buf.offset+l.Offset) b.glstate.vertexAttribPointer(b.funcs, buf.obj, inp.Location, l.Size, gltyp, false, p.layout.Stride, buf.offset+l.Offset)
} }
for i := 0; i < max; i++ { for i := 0; i < max; i++ {
b.glstate.setVertexAttribArray(b.funcs, i, enabled[i]) b.glstate.setVertexAttribArray(b.funcs, i, enabled[i])
+16 -10
View File
@@ -187,16 +187,22 @@ func newStenciler(ctx driver.Device) *stenciler {
if err != nil { if err != nil {
panic(err) panic(err)
} }
progLayout := []driver.InputDesc{ progLayout := driver.VertexLayout{
{Type: shader.DataTypeFloat, Size: 1, Offset: int(unsafe.Offsetof((*(*vertex)(nil)).Corner))}, Inputs: []driver.InputDesc{
{Type: shader.DataTypeFloat, Size: 1, Offset: int(unsafe.Offsetof((*(*vertex)(nil)).MaxY))}, {Type: shader.DataTypeFloat, Size: 1, Offset: int(unsafe.Offsetof((*(*vertex)(nil)).Corner))},
{Type: shader.DataTypeFloat, Size: 2, Offset: int(unsafe.Offsetof((*(*vertex)(nil)).FromX))}, {Type: shader.DataTypeFloat, Size: 1, Offset: int(unsafe.Offsetof((*(*vertex)(nil)).MaxY))},
{Type: shader.DataTypeFloat, Size: 2, Offset: int(unsafe.Offsetof((*(*vertex)(nil)).CtrlX))}, {Type: shader.DataTypeFloat, Size: 2, Offset: int(unsafe.Offsetof((*(*vertex)(nil)).FromX))},
{Type: shader.DataTypeFloat, Size: 2, Offset: int(unsafe.Offsetof((*(*vertex)(nil)).ToX))}, {Type: shader.DataTypeFloat, Size: 2, Offset: int(unsafe.Offsetof((*(*vertex)(nil)).CtrlX))},
{Type: shader.DataTypeFloat, Size: 2, Offset: int(unsafe.Offsetof((*(*vertex)(nil)).ToX))},
},
Stride: vertStride,
} }
iprogLayout := []driver.InputDesc{ iprogLayout := driver.VertexLayout{
{Type: shader.DataTypeFloat, Size: 2, Offset: 0}, Inputs: []driver.InputDesc{
{Type: shader.DataTypeFloat, Size: 2, Offset: 4 * 2}, {Type: shader.DataTypeFloat, Size: 2, Offset: 0},
{Type: shader.DataTypeFloat, Size: 2, Offset: 4 * 2},
},
Stride: 4 * 4,
} }
st := &stenciler{ st := &stenciler{
ctx: ctx, ctx: ctx,
@@ -370,7 +376,7 @@ func (s *stenciler) stencilPath(bounds image.Rectangle, offset f32.Point, uv ima
batch = max batch = max
} }
off := vertStride * start * 4 off := vertStride * start * 4
s.ctx.BindVertexBuffer(data.data, vertStride, off) s.ctx.BindVertexBuffer(data.data, off)
s.ctx.DrawElements(driver.DrawModeTriangles, 0, batch*6) s.ctx.DrawElements(driver.DrawModeTriangles, 0, batch*6)
start += batch start += batch
} }