diff --git a/experiments/benchmark_cairo_old.nim b/experiments/benchmark_cairo_old.nim deleted file mode 100644 index 52f63b4..0000000 --- a/experiments/benchmark_cairo_old.nim +++ /dev/null @@ -1,397 +0,0 @@ -import benchy, cairo, chroma, math, pixie, pixie/paths {.all.}, strformat - -when defined(amd64) and not defined(pixieNoSimd): - import nimsimd/sse2, pixie/internal - -proc doDiff(a, b: Image, name: string) = - let (diffScore, diffImage) = diff(a, b) - echo &"{name} score: {diffScore}" - diffImage.writeFile(&"{name}_diff.png") - -when defined(release): - {.push checks: off.} - -proc fillMask( - shapes: seq[seq[Vec2]], width, height: int, windingRule = NonZero -): Mask = - result = newMask(width, height) - - let - segments = shapes.shapesToSegments() - bounds = computeBounds(segments).snapToPixels() - startY = max(0, bounds.y.int) - pathHeight = min(height, (bounds.y + bounds.h).int) - partitioning = partitionSegments(segments, startY, pathHeight) - width = width.float32 - - var - hits = newSeq[(float32, int16)](partitioning.maxEntryCount) - numHits: int - aa: bool - for y in startY ..< pathHeight: - computeCoverage( - cast[ptr UncheckedArray[uint8]](result.data[result.dataIndex(0, y)].addr), - hits, - numHits, - aa, - width, - y, - 0, - partitioning, - windingRule - ) - if not aa: - for (prevAt, at, count) in hits.walk(numHits, windingRule, y, width): - let - startIndex = result.dataIndex(prevAt.int, y) - len = at.int - prevAt.int - fillUnsafe(result.data, 255, startIndex, len) - -proc fillMask*( - path: SomePath, width, height: int, windingRule = NonZero -): Mask = - ## Returns a new mask with the path filled. This is a faster alternative - ## to `newMask` + `fillPath`. - let shapes = parseSomePath(path, true, 1) - shapes.fillMask(width, height, windingRule) - -proc fillImage( - shapes: seq[seq[Vec2]], - width, height: int, - color: SomeColor, - windingRule = NonZero -): Image = - result = newImage(width, height) - - let - mask = shapes.fillMask(width, height, windingRule) - rgbx = color.rgbx() - - var i: int - when defined(amd64) and not defined(pixieNoSimd): - let - colorVec = mm_set1_epi32(cast[int32](rgbx)) - oddMask = mm_set1_epi16(cast[int16](0xff00)) - div255 = mm_set1_epi16(cast[int16](0x8081)) - vec255 = mm_set1_epi32(cast[int32](uint32.high)) - vecZero = mm_setzero_si128() - colorVecEven = mm_slli_epi16(colorVec, 8) - colorVecOdd = mm_and_si128(colorVec, oddMask) - iterations = result.data.len div 16 - for _ in 0 ..< iterations: - var coverageVec = mm_loadu_si128(mask.data[i].addr) - if mm_movemask_epi8(mm_cmpeq_epi16(coverageVec, vecZero)) != 0xffff: - if mm_movemask_epi8(mm_cmpeq_epi32(coverageVec, vec255)) == 0xffff: - for q in [0, 4, 8, 12]: - mm_storeu_si128(result.data[i + q].addr, colorVec) - else: - for q in [0, 4, 8, 12]: - var unpacked = unpackAlphaValues(coverageVec) - # Shift the coverages from `a` to `g` and `a` for multiplying - unpacked = mm_or_si128(unpacked, mm_srli_epi32(unpacked, 16)) - - var - sourceEven = mm_mulhi_epu16(colorVecEven, unpacked) - sourceOdd = mm_mulhi_epu16(colorVecOdd, unpacked) - sourceEven = mm_srli_epi16(mm_mulhi_epu16(sourceEven, div255), 7) - sourceOdd = mm_srli_epi16(mm_mulhi_epu16(sourceOdd, div255), 7) - - mm_storeu_si128( - result.data[i + q].addr, - mm_or_si128(sourceEven, mm_slli_epi16(sourceOdd, 8)) - ) - - coverageVec = mm_srli_si128(coverageVec, 4) - - i += 16 - - let channels = [rgbx.r.uint32, rgbx.g.uint32, rgbx.b.uint32, rgbx.a.uint32] - for i in i ..< result.data.len: - let coverage = mask.data[i] - if coverage == 255: - result.data[i] = rgbx - elif coverage != 0: - result.data[i].r = ((channels[0] * coverage) div 255).uint8 - result.data[i].g = ((channels[1] * coverage) div 255).uint8 - result.data[i].b = ((channels[2] * coverage) div 255).uint8 - result.data[i].a = ((channels[3] * coverage) div 255).uint8 - -proc fillImage*( - path: SomePath, width, height: int, color: SomeColor, windingRule = NonZero -): Image = - ## Returns a new image with the path filled. This is a faster alternative - ## to `newImage` + `fillPath`. - let shapes = parseSomePath(path, false, 1) - shapes.fillImage(width, height, color, windingRule) - -proc strokeMask*( - path: SomePath, - width, height: int, - strokeWidth: float32 = 1.0, - lineCap = ButtCap, - lineJoin = MiterJoin, - miterLimit = defaultMiterLimit, - dashes: seq[float32] = @[] -): Mask = - ## Returns a new mask with the path stroked. This is a faster alternative - ## to `newImage` + `strokePath`. - let strokeShapes = strokeShapes( - parseSomePath(path, false, 1), - strokeWidth, - lineCap, - lineJoin, - miterLimit, - dashes, - 1 - ) - result = strokeShapes.fillMask(width, height, NonZero) - -proc strokeImage*( - path: SomePath, - width, height: int, - color: SomeColor, - strokeWidth: float32 = 1.0, - lineCap = ButtCap, - lineJoin = MiterJoin, - miterLimit = defaultMiterLimit, - dashes: seq[float32] = @[] -): Image = - ## Returns a new image with the path stroked. This is a faster alternative - ## to `newImage` + `strokePath`. - let strokeShapes = strokeShapes( - parseSomePath(path, false, 1), - strokeWidth, - lineCap, - lineJoin, - miterLimit, - dashes, - 1 - ) - result = strokeShapes.fillImage(width, height, color, NonZero) - -when defined(release): - {.pop.} - - -block: - let path = newPath() - path.moveTo(0, 0) - path.lineTo(1920, 0) - path.lineTo(1920, 1080) - path.lineTo(0, 1080) - path.closePath() - - let shapes = path.commandsToShapes(true, 1) - - let - surface = imageSurfaceCreate(FORMAT_ARGB32, 1920, 1080) - ctx = surface.create() - ctx.setSourceRgba(0, 0, 1, 1) - - timeIt "cairo1": - ctx.newPath() - ctx.moveTo(shapes[0][0].x, shapes[0][0].y) - for shape in shapes: - for v in shape: - ctx.lineTo(v.x, v.y) - ctx.fill() - surface.flush() - - # discard surface.writeToPng("cairo1.png") - - let a = newImage(1920, 1080) - - timeIt "pixie1": - let p = newPath() - p.moveTo(shapes[0][0]) - for shape in shapes: - for v in shape: - p.lineTo(v) - a.fillPath(p, rgbx(0, 0, 255, 255)) - - # a.writeFile("pixie1.png") - -block: - let path = newPath() - path.moveTo(500, 240) - path.lineTo(1500, 240) - path.lineTo(1920, 600) - path.lineTo(0, 600) - path.closePath() - - let shapes = path.commandsToShapes(true, 1) - - let - surface = imageSurfaceCreate(FORMAT_ARGB32, 1920, 1080) - ctx = surface.create() - - timeIt "cairo2": - ctx.setSourceRgba(1, 1, 1, 1) - let operator = ctx.getOperator() - ctx.setOperator(OperatorSource) - ctx.paint() - ctx.setOperator(operator) - - ctx.setSourceRgba(0, 0, 1, 1) - - ctx.newPath() - ctx.moveTo(shapes[0][0].x, shapes[0][0].y) - for shape in shapes: - for v in shape: - ctx.lineTo(v.x, v.y) - ctx.fill() - surface.flush() - - # discard surface.writeToPng("cairo2.png") - - let a = newImage(1920, 1080) - - timeIt "pixie2": - a.fill(rgbx(255, 255, 255, 255)) - - let p = newPath() - p.moveTo(shapes[0][0]) - for shape in shapes: - for v in shape: - p.lineTo(v) - a.fillPath(p, rgbx(0, 0, 255, 255)) - - # a.writeFile("pixie2.png") - -block: - 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) - - let - surface = imageSurfaceCreate(FORMAT_ARGB32, 1000, 1000) - ctx = surface.create() - - timeIt "cairo3": - ctx.setSourceRgba(1, 1, 1, 1) - let operator = ctx.getOperator() - ctx.setOperator(OperatorSource) - ctx.paint() - ctx.setOperator(operator) - - ctx.setSourceRgba(1, 0, 0, 1) - - ctx.newPath() - ctx.moveTo(shapes[0][0].x, shapes[0][0].y) - for shape in shapes: - for v in shape: - ctx.lineTo(v.x, v.y) - ctx.fill() - surface.flush() - - # discard surface.writeToPng("cairo3.png") - - let a = newImage(1000, 1000) - - timeIt "pixie3": - a.fill(rgbx(255, 255, 255, 255)) - - let p = newPath() - p.moveTo(shapes[0][0]) - for shape in shapes: - for v in shape: - p.lineTo(v) - a.fillPath(p, rgbx(255, 0, 0, 255)) - - # a.writeFile("pixie3.png") - - # doDiff(readImage("cairo3.png"), a, "cairo3") - -block: - let path = newPath() - path.roundedRect(200, 200, 600, 600, 10, 10, 10, 10) - - let shapes = path.commandsToShapes(true, 1) - - # let - # surface = imageSurfaceCreate(FORMAT_ARGB32, 1000, 1000) - # ctx = surface.create() - - # timeIt "cairo4": - # ctx.setSourceRgba(0, 0, 0, 0) - # let operator = ctx.getOperator() - # ctx.setOperator(OperatorSource) - # ctx.paint() - # ctx.setOperator(operator) - - timeIt "cairo4": - let - surface = imageSurfaceCreate(FORMAT_ARGB32, 1000, 1000) - ctx = surface.create() - - ctx.setSourceRgba(1, 0, 0, 0.5) - - ctx.newPath() - ctx.moveTo(shapes[0][0].x, shapes[0][0].y) - for shape in shapes: - for v in shape: - ctx.lineTo(v.x, v.y) - ctx.fill() - surface.flush() - - # discard surface.writeToPng("cairo4.png") - - var a: Image - timeIt "pixie4": - a = newImage(1000, 1000) - - let p = newPath() - p.moveTo(shapes[0][0]) - for shape in shapes: - for v in shape: - p.lineTo(v) - a.fillPath(p, rgbx(127, 0, 0, 127)) - - # a.writeFile("pixie4.png") - - # doDiff(readImage("cairo4.png"), a, "4") - - var b: Image - let paint = newPaint(SolidPaint) - paint.color = color(1, 0, 0, 0.5) - paint.blendMode = OverwriteBlend - - timeIt "pixie4 overwrite": - b = newImage(1000, 1000) - - let p = newPath() - p.moveTo(shapes[0][0]) - for shape in shapes: - for v in shape: - p.lineTo(v) - b.fillPath(p, paint) - - # b.writeFile("b.png") - - timeIt "pixie4 mask": - let mask = newMask(1000, 1000) - - let p = newPath() - p.moveTo(shapes[0][0]) - for shape in shapes: - for v in shape: - p.lineTo(v) - mask.fillPath(p) - - var tmp: Image - timeIt "pixie fillImage": - let p = newPath() - p.moveTo(shapes[0][0]) - for shape in shapes: - for v in shape: - p.lineTo(v) - - tmp = p.fillImage(1000, 1000, rgbx(127, 0, 0, 127)) - - # tmp.writeFile("tmp.png") diff --git a/experiments/test_svg_cairo.nim b/experiments/test_svg_cairo.nim deleted file mode 100644 index ee5b065..0000000 --- a/experiments/test_svg_cairo.nim +++ /dev/null @@ -1,28 +0,0 @@ -import pixie, strformat, svg_cairo - -const files = [ - "line01", - "polyline01", - "polygon01", - "rect01", - "rect02", - "circle01", - "ellipse01", - "triangle01", - "quad01", - "Ghostscript_Tiger", - "scale", - "miterlimit", - "dashes" -] - -proc doDiff(rendered: Image, name: string) = - rendered.writeFile(&"tests/fileformats/svg/rendered/{name}.png") - let - master = readImage(&"tests/fileformats/svg/masters/{name}.png") - (diffScore, diffImage) = diff(master, rendered) - echo &"{name} score: {diffScore}" - diffImage.writeFile(&"tests/fileformats/svg/diffs/{name}.png") - -for file in files: - doDiff(decodeSvg(readFile(&"tests/fileformats/svg/{file}.svg")), file)