256 lines
5.9 KiB
Nim
256 lines
5.9 KiB
Nim
import benchy, cairo, pixie, pixie/fileformats/svg {.all.}, pixie/paths {.all.}
|
|
|
|
type
|
|
Fill = object
|
|
shapes: seq[Polygon]
|
|
transform: Mat3
|
|
paint: Paint
|
|
windingRule: WindingRule
|
|
|
|
Benchmark = object
|
|
name: string
|
|
fills: seq[Fill]
|
|
|
|
var benchmarks: seq[Benchmark]
|
|
|
|
let
|
|
opaque = newPaint(SolidPaint)
|
|
notOpaque = newPaint(SolidPaint)
|
|
opaque.color = color(0, 0, 0, 1)
|
|
notOpaque.color = color(0, 0, 0, 0.5)
|
|
|
|
block: # Basic rect
|
|
let path = newPath()
|
|
path.rect(rect(50, 50, 800, 800))
|
|
|
|
let shapes = path.commandsToShapes(true, 1)
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "rect opaque",
|
|
fills: @[Fill(
|
|
shapes: shapes,
|
|
transform: mat3(),
|
|
paint: opaque,
|
|
windingRule: NonZero
|
|
)]))
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "rect not opaque",
|
|
fills: @[Fill(
|
|
shapes: shapes,
|
|
transform: mat3(),
|
|
paint: notOpaque,
|
|
windingRule: NonZero
|
|
)]))
|
|
|
|
block: # Rounded rect
|
|
let path = newPath()
|
|
path.roundedRect(rect(0, 0, 900, 900), 100, 100, 100, 100)
|
|
|
|
let shapes = path.commandsToShapes(true, 1)
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "roundedRect opaque",
|
|
fills: @[Fill(
|
|
shapes: shapes,
|
|
transform: mat3(),
|
|
paint: opaque,
|
|
windingRule: NonZero
|
|
)]))
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "roundedRect not opaque",
|
|
fills: @[Fill(
|
|
shapes: shapes,
|
|
transform: mat3(),
|
|
paint: notOpaque,
|
|
windingRule: NonZero
|
|
)]))
|
|
|
|
block: # Pentagon
|
|
let path = newPath()
|
|
path.polygon(vec2(450, 450), 400, 5)
|
|
|
|
let shapes = path.commandsToShapes(true, 1)
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "pentagon opaque",
|
|
fills: @[Fill(
|
|
shapes: shapes,
|
|
transform: mat3(),
|
|
paint: opaque,
|
|
windingRule: NonZero
|
|
)]))
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "pentagon not opaque",
|
|
fills: @[Fill(
|
|
shapes: shapes,
|
|
transform: mat3(),
|
|
paint: notOpaque,
|
|
windingRule: NonZero
|
|
)]))
|
|
|
|
block: # Circle
|
|
let path = newPath()
|
|
path.circle(circle(vec2(450, 450), 400))
|
|
|
|
let shapes = path.commandsToShapes(true, 1)
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "circle opaque",
|
|
fills: @[Fill(
|
|
shapes: shapes,
|
|
transform: mat3(),
|
|
paint: opaque,
|
|
windingRule: NonZero
|
|
)]))
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "circle not opaque",
|
|
fills: @[Fill(
|
|
shapes: shapes,
|
|
transform: mat3(),
|
|
paint: notOpaque,
|
|
windingRule: NonZero
|
|
)]))
|
|
|
|
block: # Heart
|
|
let path = parsePath("""
|
|
M 100,300
|
|
A 200,200 0,0,1 500,300
|
|
A 200,200 0,0,1 900,300
|
|
Q 900,600 500,900
|
|
Q 100,600 100,300 z
|
|
""")
|
|
|
|
let shapes = path.commandsToShapes(true, 1)
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "heart opaque",
|
|
fills: @[Fill(
|
|
shapes: shapes,
|
|
transform: mat3(),
|
|
paint: opaque,
|
|
windingRule: NonZero
|
|
)]))
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "heart not opaque",
|
|
fills: @[Fill(
|
|
shapes: shapes,
|
|
transform: mat3(),
|
|
paint: notOpaque,
|
|
windingRule: NonZero
|
|
)]))
|
|
|
|
block: # Tiger
|
|
let
|
|
data = readFile("tests/fileformats/svg/Ghostscript_Tiger.svg")
|
|
parsed = parseSvg(data)
|
|
|
|
var fills: seq[Fill]
|
|
|
|
for (path, props) in parsed.elements:
|
|
if props.display and props.opacity > 0:
|
|
if props.fill != "none":
|
|
let
|
|
shapes = path.commandsToShapes(true, 1)
|
|
paint = parseSomePaint(props.fill)
|
|
fills.add(Fill(
|
|
shapes: shapes,
|
|
transform: props.transform,
|
|
paint: paint,
|
|
windingRule: props.fillRule
|
|
))
|
|
|
|
if props.stroke != rgbx(0, 0, 0, 0) and props.strokeWidth > 0:
|
|
let strokeShapes = strokeShapes(
|
|
parseSomePath(path, false, props.transform.pixelScale),
|
|
props.strokeWidth,
|
|
props.strokeLineCap,
|
|
props.strokeLineJoin,
|
|
props.strokeMiterLimit,
|
|
props.strokeDashArray,
|
|
props.transform.pixelScale
|
|
)
|
|
let paint = props.stroke.copy()
|
|
paint.color.a *= (props.opacity * props.strokeOpacity)
|
|
fills.add(Fill(
|
|
shapes: strokeShapes,
|
|
transform: props.transform,
|
|
paint: paint,
|
|
windingRule: NonZero
|
|
))
|
|
|
|
benchmarks.add(Benchmark(
|
|
name: "tiger",
|
|
fills: fills
|
|
))
|
|
|
|
block:
|
|
for benchmark in benchmarks:
|
|
let
|
|
surface = imageSurfaceCreate(FORMAT_ARGB32, 900, 900)
|
|
ctx = surface.create()
|
|
|
|
ctx.setLineWidth(1)
|
|
|
|
timeIt "[cairo] " & benchmark.name:
|
|
for fill in benchmark.fills:
|
|
if fill.shapes.len > 0:
|
|
ctx.newPath()
|
|
for shape in fill.shapes:
|
|
ctx.moveTo(shape[0].x, shape[0].y)
|
|
for v in shape:
|
|
ctx.lineTo(v.x, v.y)
|
|
let
|
|
color = fill.paint.color
|
|
matrix = Matrix(
|
|
xx: fill.transform[0, 0],
|
|
yx: fill.transform[0, 1],
|
|
xy: fill.transform[1, 0],
|
|
yy: fill.transform[1, 1],
|
|
x0: fill.transform[2, 0],
|
|
y0: fill.transform[2, 1],
|
|
)
|
|
ctx.setSourceRgba(color.r, color.g, color.b, color.a)
|
|
ctx.setMatrix(matrix.unsafeAddr)
|
|
ctx.setFillRule(
|
|
if fill.windingRule == NonZero:
|
|
FillRuleWinding
|
|
else:
|
|
FillRuleEvenOdd
|
|
)
|
|
ctx.fill()
|
|
# ctx.stroke()
|
|
|
|
# discard surface.writeToPng(("cairo_" & benchmark.name & ".png").cstring)
|
|
|
|
block:
|
|
for benchmark in benchmarks:
|
|
let image = newImage(900, 900)
|
|
|
|
timeIt "[pixie] " & benchmark.name:
|
|
for fill in benchmark.fills:
|
|
if fill.shapes.len > 0:
|
|
let p = newPath()
|
|
for shape in fill.shapes:
|
|
p.moveTo(shape[0])
|
|
for v in shape:
|
|
p.lineTo(v)
|
|
image.fillPath(
|
|
p,
|
|
fill.paint,
|
|
fill.transform,
|
|
fill.windingRule
|
|
)
|
|
# image.strokePath(
|
|
# p,
|
|
# fill.paint,
|
|
# fill.transform,
|
|
# 1
|
|
# )
|
|
|
|
# image.writeFile("pixie_" & benchmark.name & ".png")
|