forked from joejulian/gio
internal/stroke, gpu: reuse slice when splitting cubics
When building GPU vertices from paths, we call stroke.SplitCubic once per OpCubic. Before this change, each call to stroke.SplitCubic would allocate a slice, which we would only use to iterate over. This allocation can be easily avoided by reusing the slice. We can conveniently store it in gpu.quadSplitter. In a real application that renders hundreds of paths with tens of rounded rectangles per path, this saved roughly 4500 allocations (or 1 MB worth) per frame. Signed-off-by: Dominik Honnef <dominik@honnef.co>
This commit is contained in:
committed by
Elias Naur
parent
90e57c2b18
commit
b183774063
@@ -12,6 +12,9 @@ type quadSplitter struct {
|
||||
bounds f32.Rectangle
|
||||
contour uint32
|
||||
d *drawOps
|
||||
|
||||
// scratch space used by calls to stroke.SplitCubic
|
||||
scratch []stroke.QuadSegment
|
||||
}
|
||||
|
||||
func encodeQuadTo(data []byte, meta uint32, from, ctrl, to f32.Point) {
|
||||
|
||||
+3
-1
@@ -1327,7 +1327,9 @@ func decodeToOutlineQuads(qs *quadSplitter, tr f32.Affine2D, pathData []byte) {
|
||||
q = q.Transform(tr)
|
||||
qs.splitAndEncode(q)
|
||||
case scene.OpCubic:
|
||||
for _, q := range stroke.SplitCubic(scene.DecodeCubic(cmd)) {
|
||||
from, ctrl0, ctrl1, to := scene.DecodeCubic(cmd)
|
||||
qs.scratch = stroke.SplitCubic(from, ctrl0, ctrl1, to, qs.scratch[:0])
|
||||
for _, q := range qs.scratch {
|
||||
q = q.Transform(tr)
|
||||
qs.splitAndEncode(q)
|
||||
}
|
||||
|
||||
@@ -621,6 +621,7 @@ func StrokePathCommands(style StrokeStyle, scene []byte) StrokeQuads {
|
||||
// decodeToStrokeQuads decodes scene commands to quads ready to stroke.
|
||||
func decodeToStrokeQuads(pathData []byte) StrokeQuads {
|
||||
quads := make(StrokeQuads, 0, 2*len(pathData)/(scene.CommandSize+4))
|
||||
scratch := make([]QuadSegment, 0, 10)
|
||||
for len(pathData) >= scene.CommandSize+4 {
|
||||
contour := binary.LittleEndian.Uint32(pathData)
|
||||
cmd := ops.DecodeCommand(pathData[4:])
|
||||
@@ -645,7 +646,9 @@ func decodeToStrokeQuads(pathData []byte) StrokeQuads {
|
||||
}
|
||||
quads = append(quads, quad)
|
||||
case scene.OpCubic:
|
||||
for _, q := range SplitCubic(scene.DecodeCubic(cmd)) {
|
||||
from, ctrl0, ctrl1, to := scene.DecodeCubic(cmd)
|
||||
scratch = SplitCubic(from, ctrl0, ctrl1, to, scratch[:0])
|
||||
for _, q := range scratch {
|
||||
quad := StrokeQuad{
|
||||
Contour: contour,
|
||||
Quad: q,
|
||||
@@ -660,8 +663,7 @@ func decodeToStrokeQuads(pathData []byte) StrokeQuads {
|
||||
return quads
|
||||
}
|
||||
|
||||
func SplitCubic(from, ctrl0, ctrl1, to f32.Point) []QuadSegment {
|
||||
quads := make([]QuadSegment, 0, 10)
|
||||
func SplitCubic(from, ctrl0, ctrl1, to f32.Point, quads []QuadSegment) []QuadSegment {
|
||||
// Set the maximum distance proportionally to the longest side
|
||||
// of the bounding rectangle.
|
||||
hull := f32.Rectangle{
|
||||
|
||||
Reference in New Issue
Block a user