mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 09:55:40 +00:00
gpu: [compute] use support for simple strokes
In the old renderer, all strokes are converted to filled paths. The new renderer can draw simple strokes natively. Do that, and avoid the costly conversions. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+37
-12
@@ -623,7 +623,7 @@ func (g *compute) encodeOps(trans f32.Affine2D, viewport image.Point, ops []imag
|
|||||||
// clip is the union of all drawing affected by the clipping
|
// clip is the union of all drawing affected by the clipping
|
||||||
// operation. TODO: tighten.
|
// operation. TODO: tighten.
|
||||||
clip := f32.Rect(0, 0, float32(viewport.X), float32(viewport.Y))
|
clip := f32.Rect(0, 0, float32(viewport.X), float32(viewport.Y))
|
||||||
nclips := g.encodeClipStack(clip, bounds, op.path)
|
nclips := g.encodeClipStack(clip, bounds, op.path, false)
|
||||||
m := op.material
|
m := op.material
|
||||||
switch m.material {
|
switch m.material {
|
||||||
case materialTexture:
|
case materialTexture:
|
||||||
@@ -646,6 +646,10 @@ func (g *compute) encodeOps(trans f32.Affine2D, viewport image.Point, ops []imag
|
|||||||
default:
|
default:
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
if op.path != nil && op.path.path {
|
||||||
|
g.enc.fillMode(scene.FillModeNonzero)
|
||||||
|
g.enc.transform(op.path.trans.Invert())
|
||||||
|
}
|
||||||
// Pop the clip stack.
|
// Pop the clip stack.
|
||||||
for i := 0; i < nclips; i++ {
|
for i := 0; i < nclips; i++ {
|
||||||
g.enc.endClip(clip)
|
g.enc.endClip(clip)
|
||||||
@@ -655,40 +659,61 @@ func (g *compute) encodeOps(trans f32.Affine2D, viewport image.Point, ops []imag
|
|||||||
}
|
}
|
||||||
|
|
||||||
// encodeClips encodes a stack of clip paths and return the stack depth.
|
// encodeClips encodes a stack of clip paths and return the stack depth.
|
||||||
func (g *compute) encodeClipStack(clip, bounds f32.Rectangle, p *pathOp) int {
|
func (g *compute) encodeClipStack(clip, bounds f32.Rectangle, p *pathOp, begin bool) int {
|
||||||
nclips := 0
|
nclips := 0
|
||||||
if p != nil && p.parent != nil {
|
if p != nil && p.parent != nil {
|
||||||
nclips += g.encodeClipStack(clip, bounds, p.parent)
|
nclips += g.encodeClipStack(clip, bounds, p.parent, true)
|
||||||
g.enc.beginClip(clip)
|
|
||||||
nclips += 1
|
nclips += 1
|
||||||
}
|
}
|
||||||
|
s := isStroke(p)
|
||||||
if p != nil && p.path {
|
if p != nil && p.path {
|
||||||
|
if s {
|
||||||
|
g.enc.fillMode(scene.FillModeStroke)
|
||||||
|
g.enc.lineWidth(p.stroke.Width)
|
||||||
|
}
|
||||||
pathData, _ := g.drawOps.pathCache.get(p.pathKey)
|
pathData, _ := g.drawOps.pathCache.get(p.pathKey)
|
||||||
g.enc.transform(p.trans)
|
g.enc.transform(p.trans)
|
||||||
g.enc.append(pathData.computePath)
|
g.enc.append(pathData.computePath)
|
||||||
g.enc.transform(p.trans.Invert())
|
|
||||||
} else {
|
} else {
|
||||||
g.enc.rect(bounds)
|
g.enc.rect(bounds)
|
||||||
}
|
}
|
||||||
|
if begin {
|
||||||
|
g.enc.beginClip(clip)
|
||||||
|
if s {
|
||||||
|
g.enc.fillMode(scene.FillModeNonzero)
|
||||||
|
}
|
||||||
|
if p != nil && p.path {
|
||||||
|
g.enc.transform(p.trans.Invert())
|
||||||
|
}
|
||||||
|
}
|
||||||
return nclips
|
return nclips
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodePath(pathData []byte, stroke clip.StrokeStyle, dashes dashOp) encoder {
|
func supportsStroke(p *pathOp) bool {
|
||||||
|
return isSolidLine(p.dashes) && p.stroke.Miter == 0 && p.stroke.Join == clip.RoundJoin && p.stroke.Cap == clip.RoundCap
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStroke(p *pathOp) bool {
|
||||||
|
return p.stroke.Width > 0 && supportsStroke(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodePath(p *pathOp) encoder {
|
||||||
var enc encoder
|
var enc encoder
|
||||||
if stroke.Width > 0 {
|
verts := p.pathVerts
|
||||||
quads := decodeToStrokeQuads(pathData)
|
if p.stroke.Width > 0 && !supportsStroke(p) {
|
||||||
quads = quads.stroke(stroke, dashes)
|
quads := decodeToStrokeQuads(verts)
|
||||||
|
quads = quads.stroke(p.stroke, p.dashes)
|
||||||
for _, quad := range quads {
|
for _, quad := range quads {
|
||||||
q := quad.quad
|
q := quad.quad
|
||||||
enc.quad(q.From, q.Ctrl, q.To)
|
enc.quad(q.From, q.Ctrl, q.To)
|
||||||
}
|
}
|
||||||
return enc
|
return enc
|
||||||
}
|
}
|
||||||
for len(pathData) >= scene.CommandSize+4 {
|
for len(verts) >= scene.CommandSize+4 {
|
||||||
cmd := ops.DecodeCommand(pathData[4:])
|
cmd := ops.DecodeCommand(verts[4:])
|
||||||
enc.scene = append(enc.scene, cmd)
|
enc.scene = append(enc.scene, cmd)
|
||||||
enc.npathseg++
|
enc.npathseg++
|
||||||
pathData = pathData[scene.CommandSize+4:]
|
verts = verts[scene.CommandSize+4:]
|
||||||
}
|
}
|
||||||
return enc
|
return enc
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -835,7 +835,7 @@ func (d *drawOps) collect(ctx driver.Device, cache *resourceCache, root *op.Ops,
|
|||||||
data := buildPath(ctx, p.pathVerts)
|
data := buildPath(ctx, p.pathVerts)
|
||||||
var computePath encoder
|
var computePath encoder
|
||||||
if d.compute {
|
if d.compute {
|
||||||
computePath = encodePath(p.pathVerts, p.stroke, p.dashes)
|
computePath = encodePath(p)
|
||||||
}
|
}
|
||||||
d.pathCache.put(p.pathKey, opCacheValue{
|
d.pathCache.put(p.pathKey, opCacheValue{
|
||||||
data: data,
|
data: data,
|
||||||
|
|||||||
Reference in New Issue
Block a user