mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 18:05:35 +00:00
gpu,gpu/gl: introduce InputLayout and use shader reflection data
InputLayout is the abstraction for the mapping between vertex data and shader inputs. The mapping is implicit in OpenGL but explicit in Direct3D. Infer the attribute name location index using shader reflection data, and get rid of a parameter to NewProgram. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+18
-2
@@ -23,8 +23,8 @@ type Backend interface {
|
|||||||
NilTexture() Texture
|
NilTexture() Texture
|
||||||
NewFramebuffer() Framebuffer
|
NewFramebuffer() Framebuffer
|
||||||
NewBuffer(typ BufferType, data []byte) Buffer
|
NewBuffer(typ BufferType, data []byte) Buffer
|
||||||
NewProgram(vertexShader, fragmentShader ShaderSources, attribMap []string) (Program, error)
|
NewProgram(vertexShader, fragmentShader ShaderSources) (Program, error)
|
||||||
SetupVertexArray(slot int, size int, dataType DataType, stride, offset int)
|
NewInputLayout(vertexShader ShaderSources, layout []InputDesc) (InputLayout, error)
|
||||||
|
|
||||||
DepthFunc(f DepthFunc)
|
DepthFunc(f DepthFunc)
|
||||||
ClearColor(r, g, b, a float32)
|
ClearColor(r, g, b, a float32)
|
||||||
@@ -65,6 +65,21 @@ type InputLocation struct {
|
|||||||
Size int
|
Size int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InputDesc describes a vertex attribute as laid out in a Buffer.
|
||||||
|
type InputDesc struct {
|
||||||
|
Type DataType
|
||||||
|
Size int
|
||||||
|
|
||||||
|
Offset int
|
||||||
|
}
|
||||||
|
|
||||||
|
// InputLayout is the backend specific representation of the mapping
|
||||||
|
// between Buffers and shader attributes.
|
||||||
|
type InputLayout interface {
|
||||||
|
Bind()
|
||||||
|
Release()
|
||||||
|
}
|
||||||
|
|
||||||
type BlendFactor uint8
|
type BlendFactor uint8
|
||||||
|
|
||||||
type DrawMode uint8
|
type DrawMode uint8
|
||||||
@@ -100,6 +115,7 @@ type Program interface {
|
|||||||
type Uniform interface{}
|
type Uniform interface{}
|
||||||
|
|
||||||
type Buffer interface {
|
type Buffer interface {
|
||||||
|
BindVertex(stride, offset int)
|
||||||
Bind()
|
Bind()
|
||||||
Release()
|
Release()
|
||||||
}
|
}
|
||||||
|
|||||||
+78
-20
@@ -34,6 +34,14 @@ type glstate struct {
|
|||||||
nattr int
|
nattr int
|
||||||
prog *gpuProgram
|
prog *gpuProgram
|
||||||
texUnits [2]*gpuTexture
|
texUnits [2]*gpuTexture
|
||||||
|
layout *gpuInputLayout
|
||||||
|
buffer bufferBinding
|
||||||
|
}
|
||||||
|
|
||||||
|
type bufferBinding struct {
|
||||||
|
buf *gpuBuffer
|
||||||
|
offset int
|
||||||
|
stride int
|
||||||
}
|
}
|
||||||
|
|
||||||
type gpuTimer struct {
|
type gpuTimer struct {
|
||||||
@@ -52,9 +60,9 @@ type gpuFramebuffer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type gpuBuffer struct {
|
type gpuBuffer struct {
|
||||||
funcs Functions
|
backend *Backend
|
||||||
obj Buffer
|
obj Buffer
|
||||||
typ Enum
|
typ Enum
|
||||||
}
|
}
|
||||||
|
|
||||||
type gpuProgram struct {
|
type gpuProgram struct {
|
||||||
@@ -63,6 +71,12 @@ type gpuProgram struct {
|
|||||||
nattr int
|
nattr int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type gpuInputLayout struct {
|
||||||
|
backend *Backend
|
||||||
|
inputs []gpu.InputLocation
|
||||||
|
layout []gpu.InputDesc
|
||||||
|
}
|
||||||
|
|
||||||
// textureTriple holds the type settings for
|
// textureTriple holds the type settings for
|
||||||
// a TexImage2D call.
|
// a TexImage2D call.
|
||||||
type textureTriple struct {
|
type textureTriple struct {
|
||||||
@@ -159,7 +173,7 @@ func (b *Backend) NewBuffer(typ gpu.BufferType, data []byte) gpu.Buffer {
|
|||||||
default:
|
default:
|
||||||
panic("unsupported buffer type")
|
panic("unsupported buffer type")
|
||||||
}
|
}
|
||||||
buf := &gpuBuffer{funcs: b.funcs, obj: obj, typ: gltyp}
|
buf := &gpuBuffer{backend: b, obj: obj, typ: gltyp}
|
||||||
buf.Bind()
|
buf.Bind()
|
||||||
b.funcs.BufferData(gltyp, data, STATIC_DRAW)
|
b.funcs.BufferData(gltyp, data, STATIC_DRAW)
|
||||||
return buf
|
return buf
|
||||||
@@ -232,10 +246,12 @@ func (b *Backend) SetBlend(enable bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DrawElements(mode gpu.DrawMode, off, count int) {
|
func (b *Backend) DrawElements(mode gpu.DrawMode, off, count int) {
|
||||||
|
b.setupVertexArrays()
|
||||||
b.funcs.DrawElements(toGLDrawMode(mode), count, UNSIGNED_SHORT, off)
|
b.funcs.DrawElements(toGLDrawMode(mode), count, UNSIGNED_SHORT, off)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) DrawArrays(mode gpu.DrawMode, off, count int) {
|
func (b *Backend) DrawArrays(mode gpu.DrawMode, off, count int) {
|
||||||
|
b.setupVertexArrays()
|
||||||
b.funcs.DrawArrays(toGLDrawMode(mode), off, count)
|
b.funcs.DrawArrays(toGLDrawMode(mode), off, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +300,27 @@ func (b *Backend) DepthFunc(f gpu.DepthFunc) {
|
|||||||
b.funcs.DepthFunc(glfunc)
|
b.funcs.DepthFunc(glfunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) NewProgram(vssrc, fssrc gpu.ShaderSources, attr []string) (gpu.Program, error) {
|
func (b *Backend) NewInputLayout(vs gpu.ShaderSources, layout []gpu.InputDesc) (gpu.InputLayout, error) {
|
||||||
|
if len(vs.Inputs) != len(layout) {
|
||||||
|
return nil, fmt.Errorf("NewInputLayout: got %d inputs, expected %d", len(layout), len(vs.Inputs))
|
||||||
|
}
|
||||||
|
for i, inp := range vs.Inputs {
|
||||||
|
if exp, got := inp.Size, layout[i].Size; exp != got {
|
||||||
|
return nil, fmt.Errorf("NewInputLayout: data size mismatch for %q: got %d expected %d", inp.Name, got, exp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &gpuInputLayout{
|
||||||
|
backend: b,
|
||||||
|
inputs: vs.Inputs,
|
||||||
|
layout: layout,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) NewProgram(vssrc, fssrc gpu.ShaderSources) (gpu.Program, error) {
|
||||||
|
attr := make([]string, len(vssrc.Inputs))
|
||||||
|
for _, inp := range vssrc.Inputs {
|
||||||
|
attr[inp.Location] = inp.Name
|
||||||
|
}
|
||||||
p, err := CreateProgram(b.funcs, vssrc.GLES2, fssrc.GLES2, attr)
|
p, err := CreateProgram(b.funcs, vssrc.GLES2, fssrc.GLES2, attr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -322,29 +358,45 @@ func (p *gpuProgram) UniformFor(uniform string) gpu.Uniform {
|
|||||||
return GetUniformLocation(f, p.obj, uniform)
|
return GetUniformLocation(f, p.obj, uniform)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) SetupVertexArray(slot int, size int, dataType gpu.DataType, stride, offset int) {
|
|
||||||
var gltyp Enum
|
|
||||||
switch dataType {
|
|
||||||
case gpu.DataTypeFloat:
|
|
||||||
gltyp = FLOAT
|
|
||||||
case gpu.DataTypeShort:
|
|
||||||
gltyp = SHORT
|
|
||||||
default:
|
|
||||||
panic("unsupported data type")
|
|
||||||
}
|
|
||||||
b.funcs.VertexAttribPointer(Attrib(slot), size, gltyp, false, stride, offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *gpuProgram) Release() {
|
func (p *gpuProgram) Release() {
|
||||||
p.backend.funcs.DeleteProgram(p.obj)
|
p.backend.funcs.DeleteProgram(p.obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *gpuBuffer) Release() {
|
func (b *gpuBuffer) Release() {
|
||||||
b.funcs.DeleteBuffer(b.obj)
|
b.backend.funcs.DeleteBuffer(b.obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *gpuBuffer) BindVertex(stride, offset int) {
|
||||||
|
if b.typ != ARRAY_BUFFER {
|
||||||
|
panic("not a vertex buffer")
|
||||||
|
}
|
||||||
|
b.backend.state.buffer = bufferBinding{buf: b, stride: stride, offset: offset}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) setupVertexArrays() {
|
||||||
|
layout := b.state.layout
|
||||||
|
if layout == nil {
|
||||||
|
panic("no input layout is current")
|
||||||
|
}
|
||||||
|
buf := b.state.buffer
|
||||||
|
b.funcs.BindBuffer(ARRAY_BUFFER, buf.buf.obj)
|
||||||
|
for i, inp := range layout.inputs {
|
||||||
|
l := layout.layout[i]
|
||||||
|
var gltyp Enum
|
||||||
|
switch l.Type {
|
||||||
|
case gpu.DataTypeFloat:
|
||||||
|
gltyp = FLOAT
|
||||||
|
case gpu.DataTypeShort:
|
||||||
|
gltyp = SHORT
|
||||||
|
default:
|
||||||
|
panic("unsupported data type")
|
||||||
|
}
|
||||||
|
b.funcs.VertexAttribPointer(Attrib(inp.Location), l.Size, gltyp, false, buf.stride, buf.offset+l.Offset)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *gpuBuffer) Bind() {
|
func (b *gpuBuffer) Bind() {
|
||||||
b.funcs.BindBuffer(b.typ, b.obj)
|
b.backend.funcs.BindBuffer(b.typ, b.obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *gpuFramebuffer) IsComplete() error {
|
func (f *gpuFramebuffer) IsComplete() error {
|
||||||
@@ -437,6 +489,12 @@ func (t *gpuTimer) Duration() (time.Duration, bool) {
|
|||||||
return time.Duration(nanos), true
|
return time.Duration(nanos), true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *gpuInputLayout) Bind() {
|
||||||
|
l.backend.state.layout = l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *gpuInputLayout) Release() {}
|
||||||
|
|
||||||
// floatTripleFor determines the best texture triple for floating point FBOs.
|
// floatTripleFor determines the best texture triple for floating point FBOs.
|
||||||
func floatTripleFor(f Functions, ver [2]int, exts []string) (textureTriple, error) {
|
func floatTripleFor(f Functions, ver [2]int, exts []string) (textureTriple, error) {
|
||||||
var triples []textureTriple
|
var triples []textureTriple
|
||||||
|
|||||||
+25
-20
@@ -212,6 +212,7 @@ type blitter struct {
|
|||||||
ctx Backend
|
ctx Backend
|
||||||
viewport image.Point
|
viewport image.Point
|
||||||
prog [2]Program
|
prog [2]Program
|
||||||
|
layout InputLayout
|
||||||
vars [2]struct {
|
vars [2]struct {
|
||||||
z Uniform
|
z Uniform
|
||||||
uScale, uOffset Uniform
|
uScale, uOffset Uniform
|
||||||
@@ -234,10 +235,6 @@ const (
|
|||||||
materialTexture
|
materialTexture
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
blitAttribs = []string{"pos", "uv"}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
attribPos = 0
|
attribPos = 0
|
||||||
attribUV = 1
|
attribUV = 1
|
||||||
@@ -375,7 +372,7 @@ func (r *renderer) release() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newBlitter(ctx Backend) *blitter {
|
func newBlitter(ctx Backend) *blitter {
|
||||||
prog, err := createColorPrograms(ctx, shader_blit_vert, shader_blit_frag)
|
prog, layout, err := createColorPrograms(ctx, shader_blit_vert, shader_blit_frag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -390,6 +387,7 @@ func newBlitter(ctx Backend) *blitter {
|
|||||||
b := &blitter{
|
b := &blitter{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
prog: prog,
|
prog: prog,
|
||||||
|
layout: layout,
|
||||||
quadVerts: quadVerts,
|
quadVerts: quadVerts,
|
||||||
}
|
}
|
||||||
for i, prog := range prog {
|
for i, prog := range prog {
|
||||||
@@ -414,21 +412,31 @@ func (b *blitter) release() {
|
|||||||
for _, p := range b.prog {
|
for _, p := range b.prog {
|
||||||
p.Release()
|
p.Release()
|
||||||
}
|
}
|
||||||
|
b.layout.Release()
|
||||||
}
|
}
|
||||||
|
|
||||||
func createColorPrograms(ctx Backend, vsSrc ShaderSources, fsSrc [2]ShaderSources) ([2]Program, error) {
|
func createColorPrograms(ctx Backend, vsSrc ShaderSources, fsSrc [2]ShaderSources) ([2]Program, InputLayout, error) {
|
||||||
var prog [2]Program
|
var prog [2]Program
|
||||||
var err error
|
var err error
|
||||||
prog[materialTexture], err = ctx.NewProgram(vsSrc, fsSrc[materialTexture], blitAttribs)
|
prog[materialTexture], err = ctx.NewProgram(vsSrc, fsSrc[materialTexture])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return prog, err
|
return prog, nil, err
|
||||||
}
|
}
|
||||||
prog[materialColor], err = ctx.NewProgram(vsSrc, fsSrc[materialColor], blitAttribs)
|
prog[materialColor], err = ctx.NewProgram(vsSrc, fsSrc[materialColor])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
prog[materialTexture].Release()
|
prog[materialTexture].Release()
|
||||||
return prog, err
|
return prog, nil, err
|
||||||
}
|
}
|
||||||
return prog, nil
|
layout, err := ctx.NewInputLayout(vsSrc, []InputDesc{
|
||||||
|
{Type: DataTypeFloat, Size: 2, Offset: 0},
|
||||||
|
{Type: DataTypeFloat, Size: 2, Offset: 4 * 2},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
prog[materialTexture].Release()
|
||||||
|
prog[materialColor].Release()
|
||||||
|
return prog, nil, err
|
||||||
|
}
|
||||||
|
return prog, layout, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *renderer) stencilClips(pathCache *opCache, ops []*pathOp) {
|
func (r *renderer) stencilClips(pathCache *opCache, ops []*pathOp) {
|
||||||
@@ -456,9 +464,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.Bind()
|
r.blitter.quadVerts.BindVertex(4*4, 0)
|
||||||
r.ctx.SetupVertexArray(attribPos, 2, DataTypeFloat, 4*4, 0)
|
r.pather.stenciler.iprogLayout.Bind()
|
||||||
r.ctx.SetupVertexArray(attribUV, 2, DataTypeFloat, 4*4, 4*2)
|
|
||||||
for _, img := range ops {
|
for _, img := range ops {
|
||||||
if img.clipType != clipTypeIntersection {
|
if img.clipType != clipTypeIntersection {
|
||||||
continue
|
continue
|
||||||
@@ -764,9 +771,8 @@ 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.Bind()
|
r.blitter.quadVerts.BindVertex(4*4, 0)
|
||||||
r.ctx.SetupVertexArray(attribPos, 2, DataTypeFloat, 4*4, 0)
|
r.blitter.layout.Bind()
|
||||||
r.ctx.SetupVertexArray(attribUV, 2, DataTypeFloat, 4*4, 4*2)
|
|
||||||
// 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]
|
||||||
@@ -786,9 +792,8 @@ 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.Bind()
|
r.blitter.quadVerts.BindVertex(4*4, 0)
|
||||||
r.ctx.SetupVertexArray(attribPos, 2, DataTypeFloat, 4*4, 0)
|
r.pather.coverer.layout.Bind()
|
||||||
r.ctx.SetupVertexArray(attribUV, 2, DataTypeFloat, 4*4, 4*2)
|
|
||||||
var coverTex Texture
|
var coverTex Texture
|
||||||
for _, img := range ops {
|
for _, img := range ops {
|
||||||
m := img.material
|
m := img.material
|
||||||
|
|||||||
+37
-19
@@ -24,9 +24,10 @@ type pather struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type coverer struct {
|
type coverer struct {
|
||||||
ctx Backend
|
ctx Backend
|
||||||
prog [2]Program
|
prog [2]Program
|
||||||
vars [2]struct {
|
layout InputLayout
|
||||||
|
vars [2]struct {
|
||||||
z Uniform
|
z Uniform
|
||||||
uScale, uOffset Uniform
|
uScale, uOffset Uniform
|
||||||
uUVScale, uUVOffset Uniform
|
uUVScale, uUVOffset Uniform
|
||||||
@@ -39,7 +40,9 @@ type stenciler struct {
|
|||||||
ctx Backend
|
ctx Backend
|
||||||
defFBO Framebuffer
|
defFBO Framebuffer
|
||||||
prog Program
|
prog Program
|
||||||
|
progLayout InputLayout
|
||||||
iprog Program
|
iprog Program
|
||||||
|
iprogLayout InputLayout
|
||||||
fbos fboSet
|
fbos fboSet
|
||||||
intersections fboSet
|
intersections fboSet
|
||||||
uScale, uOffset Uniform
|
uScale, uOffset Uniform
|
||||||
@@ -64,11 +67,6 @@ type pathData struct {
|
|||||||
data Buffer
|
data Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
pathAttribs = []string{"corner", "maxy", "from", "ctrl", "to"}
|
|
||||||
intersectAttribs = []string{"pos", "uv"}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Number of path quads per draw batch.
|
// Number of path quads per draw batch.
|
||||||
pathBatchSize = 10000
|
pathBatchSize = 10000
|
||||||
@@ -91,13 +89,14 @@ func newPather(ctx Backend) *pather {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newCoverer(ctx Backend) *coverer {
|
func newCoverer(ctx Backend) *coverer {
|
||||||
prog, err := createColorPrograms(ctx, shader_cover_vert, shader_cover_frag)
|
prog, layout, err := createColorPrograms(ctx, shader_cover_vert, shader_cover_frag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
c := &coverer{
|
c := &coverer{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
prog: prog,
|
prog: prog,
|
||||||
|
layout: layout,
|
||||||
}
|
}
|
||||||
for i, prog := range prog {
|
for i, prog := range prog {
|
||||||
switch materialType(i) {
|
switch materialType(i) {
|
||||||
@@ -122,11 +121,11 @@ func newCoverer(ctx Backend) *coverer {
|
|||||||
|
|
||||||
func newStenciler(ctx Backend) *stenciler {
|
func newStenciler(ctx Backend) *stenciler {
|
||||||
defFBO := ctx.DefaultFramebuffer()
|
defFBO := ctx.DefaultFramebuffer()
|
||||||
prog, err := ctx.NewProgram(shader_stencil_vert, shader_stencil_frag, pathAttribs)
|
prog, err := ctx.NewProgram(shader_stencil_vert, shader_stencil_frag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
iprog, err := ctx.NewProgram(shader_intersect_vert, shader_intersect_frag, intersectAttribs)
|
iprog, err := ctx.NewProgram(shader_intersect_vert, shader_intersect_frag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -144,11 +143,30 @@ func newStenciler(ctx Backend) *stenciler {
|
|||||||
indices[i*6+5] = i*4 + 3
|
indices[i*6+5] = i*4 + 3
|
||||||
}
|
}
|
||||||
indexBuf := ctx.NewBuffer(BufferTypeIndices, gunsafe.BytesView(indices))
|
indexBuf := ctx.NewBuffer(BufferTypeIndices, gunsafe.BytesView(indices))
|
||||||
|
progLayout, err := ctx.NewInputLayout(shader_stencil_vert, []InputDesc{
|
||||||
|
{Type: DataTypeShort, Size: 2, Offset: int(unsafe.Offsetof((*(*path.Vertex)(nil)).CornerX))},
|
||||||
|
{Type: DataTypeFloat, Size: 1, Offset: int(unsafe.Offsetof((*(*path.Vertex)(nil)).MaxY))},
|
||||||
|
{Type: DataTypeFloat, Size: 2, Offset: int(unsafe.Offsetof((*(*path.Vertex)(nil)).FromX))},
|
||||||
|
{Type: DataTypeFloat, Size: 2, Offset: int(unsafe.Offsetof((*(*path.Vertex)(nil)).CtrlX))},
|
||||||
|
{Type: DataTypeFloat, Size: 2, Offset: int(unsafe.Offsetof((*(*path.Vertex)(nil)).ToX))},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
iprogLayout, err := ctx.NewInputLayout(shader_intersect_vert, []InputDesc{
|
||||||
|
{Type: DataTypeFloat, Size: 2, Offset: 0},
|
||||||
|
{Type: DataTypeFloat, Size: 2, Offset: 4 * 2},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
return &stenciler{
|
return &stenciler{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
defFBO: defFBO,
|
defFBO: defFBO,
|
||||||
prog: prog,
|
prog: prog,
|
||||||
|
progLayout: progLayout,
|
||||||
iprog: iprog,
|
iprog: iprog,
|
||||||
|
iprogLayout: iprogLayout,
|
||||||
uScale: prog.UniformFor("uniforms.scale"),
|
uScale: prog.UniformFor("uniforms.scale"),
|
||||||
uOffset: prog.UniformFor("uniforms.offset"),
|
uOffset: prog.UniformFor("uniforms.offset"),
|
||||||
uPathOffset: prog.UniformFor("uniforms.pathOffset"),
|
uPathOffset: prog.UniformFor("uniforms.pathOffset"),
|
||||||
@@ -201,7 +219,10 @@ func (s *fboSet) delete(ctx Backend, idx int) {
|
|||||||
|
|
||||||
func (s *stenciler) release() {
|
func (s *stenciler) release() {
|
||||||
s.fbos.delete(s.ctx, 0)
|
s.fbos.delete(s.ctx, 0)
|
||||||
|
s.progLayout.Release()
|
||||||
s.prog.Release()
|
s.prog.Release()
|
||||||
|
s.iprogLayout.Release()
|
||||||
|
s.iprog.Release()
|
||||||
s.indexBuf.Release()
|
s.indexBuf.Release()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,6 +235,7 @@ func (c *coverer) release() {
|
|||||||
for _, p := range c.prog {
|
for _, p := range c.prog {
|
||||||
p.Release()
|
p.Release()
|
||||||
}
|
}
|
||||||
|
c.layout.Release()
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPath(ctx Backend, p []byte) *pathData {
|
func buildPath(ctx Backend, p []byte) *pathData {
|
||||||
@@ -271,11 +293,11 @@ func (s *stenciler) begin(sizes []image.Point) {
|
|||||||
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.Bind()
|
s.prog.Bind()
|
||||||
|
s.progLayout.Bind()
|
||||||
s.indexBuf.Bind()
|
s.indexBuf.Bind()
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
data.data.Bind()
|
|
||||||
s.ctx.Viewport(uv.X, uv.Y, bounds.Dx(), bounds.Dy())
|
s.ctx.Viewport(uv.X, uv.Y, bounds.Dx(), bounds.Dy())
|
||||||
// Transform UI coordinates to OpenGL coordinates.
|
// Transform UI coordinates to OpenGL coordinates.
|
||||||
texSize := f32.Point{X: float32(bounds.Dx()), Y: float32(bounds.Dy())}
|
texSize := f32.Point{X: float32(bounds.Dx()), Y: float32(bounds.Dy())}
|
||||||
@@ -293,11 +315,7 @@ 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
|
||||||
s.ctx.SetupVertexArray(attribPathCorner, 2, DataTypeShort, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).CornerX)))
|
data.data.BindVertex(path.VertStride, off)
|
||||||
s.ctx.SetupVertexArray(attribPathMaxY, 1, DataTypeFloat, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).MaxY)))
|
|
||||||
s.ctx.SetupVertexArray(attribPathFrom, 2, DataTypeFloat, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).FromX)))
|
|
||||||
s.ctx.SetupVertexArray(attribPathCtrl, 2, DataTypeFloat, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).CtrlX)))
|
|
||||||
s.ctx.SetupVertexArray(attribPathTo, 2, DataTypeFloat, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).ToX)))
|
|
||||||
s.ctx.DrawElements(DrawModeTriangles, 0, batch*6)
|
s.ctx.DrawElements(DrawModeTriangles, 0, batch*6)
|
||||||
start += batch
|
start += batch
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user