From 48c7db719e1968092aac4e40415de026e5319f17 Mon Sep 17 00:00:00 2001 From: Ryan Oldenburg Date: Thu, 23 Jun 2022 20:50:22 -0500 Subject: [PATCH 1/3] handle partition index differently --- src/pixie/paths.nim | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/pixie/paths.nim b/src/pixie/paths.nim index 527016c..88d8ecc 100644 --- a/src/pixie/paths.nim +++ b/src/pixie/paths.nim @@ -44,7 +44,7 @@ type Partition = object entries: seq[PartitionEntry] requiresAntiAliasing: bool - bottom: int + top, bottom: int Fixed32 = int32 ## 24.8 fixed point @@ -1131,6 +1131,18 @@ proc partitionSegments( startY = top.uint32 partitionHeight = height.uint32 div numPartitions + # Set the bottom values for the partitions (y value where this partition ends) + result[0].top = top + result[0].bottom = top + partitionHeight.int + for i in 1 ..< result.len: + result[i].top = result[i - 1].bottom + result[i].bottom = result[i - 1].bottom + partitionHeight.int + + # Ensure the final partition goes to the actual bottom + # This is needed since the final partition includes + # height - (height div numPartitions) * numPartitions + result[^1].bottom = top + height + var entries = newSeq[PartitionEntry](segments.len) for i, (segment, winding) in segments: entries[i] = initPartitionEntry(segment, winding) @@ -1166,18 +1178,8 @@ proc partitionSegments( result[partitionIndex].entries[indexes[partitionIndex]] = entries[i] inc indexes[partitionIndex] - # Set the bottom values for the partitions (y value where this partition ends) - var partitionBottom = top + partitionHeight.int for partition in result.mitems: - partition.bottom = partitionBottom - partition.requiresAntiAliasing = - requiresAntiAliasing(partition.entries) - partitionBottom += partitionHeight.int - - # Ensure the final partition goes to the actual bottom - # This is needed since the final partition includes - # height - (height div numPartitions) * numPartitions - result[^1].bottom = top + height + partition.requiresAntiAliasing = requiresAntiAliasing(partition.entries) proc maxEntryCount(partitions: var seq[Partition]): int = for i in 0 ..< partitions.len: @@ -1273,12 +1275,9 @@ proc computeCoverage( width: int, y, startX: int, partitions: var seq[Partition], - partitionIndex: var int, + partitionIndex: int, windingRule: WindingRule ) {.inline.} = - if y >= partitions[partitionIndex].bottom: - inc partitionIndex - aa = partitions[partitionIndex].requiresAntiAliasing let @@ -1823,7 +1822,11 @@ proc fillShapes( numHits: int aa: bool - for y in startY ..< pathHeight: + var y = startY + while y < pathHeight: + if y >= partitions[partitionIndex].bottom: + inc partitionIndex + computeCoverage( cast[ptr UncheckedArray[uint8]](coverages[0].addr), hits, @@ -1836,6 +1839,7 @@ proc fillShapes( partitionIndex, windingRule ) + if aa: image.fillCoverage( rgbx, @@ -1856,6 +1860,8 @@ proc fillShapes( blendMode ) + inc y + if blendMode == MaskBlend: image.clearUnsafe(0, 0, 0, startY) image.clearUnsafe(0, pathHeight, 0, image.height) @@ -1895,6 +1901,9 @@ proc fillShapes( aa: bool for y in startY ..< pathHeight: + if y >= partitions[partitionIndex].bottom: + inc partitionIndex + computeCoverage( cast[ptr UncheckedArray[uint8]](coverages[0].addr), hits, From bec700d6b9390218403a5c6a4f886254542c4c02 Mon Sep 17 00:00:00 2001 From: Ryan Oldenburg Date: Thu, 23 Jun 2022 20:58:51 -0500 Subject: [PATCH 2/3] 2 vertical pixel-aligned lines shortcut --- src/pixie/paths.nim | 63 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/pixie/paths.nim b/src/pixie/paths.nim index 88d8ecc..008a806 100644 --- a/src/pixie/paths.nim +++ b/src/pixie/paths.nim @@ -43,7 +43,7 @@ type Partition = object entries: seq[PartitionEntry] - requiresAntiAliasing: bool + requiresAntiAliasing, twoNonintersectingSpanningSegments: bool top, bottom: int Fixed32 = int32 ## 24.8 fixed point @@ -1181,6 +1181,33 @@ proc partitionSegments( for partition in result.mitems: partition.requiresAntiAliasing = requiresAntiAliasing(partition.entries) + let + top = partition.top.float32 + bottom = partition.bottom.float32 + if partition.entries.len == 2: + # Clip the entries to the parition bounds + let + topLine = line(vec2(0, top), vec2(1000, top)) + bottomLine = line(vec2(0, bottom), vec2(1000, bottom)) + for entry in partition.entries.mitems: + if entry.segment.at.y <= top and entry.segment.to.y >= bottom: + var at: Vec2 + discard intersects(entry.segment, topLine, at) + entry.segment.at = at + discard intersects(entry.segment, bottomLine, at) + entry.segment.to = at + + let + entry0 = partition.entries[0].segment + entry1 = partition.entries[1].segment + var at: Vec2 + if not intersects(entry0, entry1, at): + # These two segments do not intersect, enable shortcut + partition.twoNonintersectingSpanningSegments = true + # Ensure entry[0] is on the left + if entry1.at.x < entry0.at.x: + swap partition.entries[1], partition.entries[0] + proc maxEntryCount(partitions: var seq[Partition]): int = for i in 0 ..< partitions.len: result = max(result, partitions[i].entries.len) @@ -1827,6 +1854,40 @@ proc fillShapes( if y >= partitions[partitionIndex].bottom: inc partitionIndex + let + partitionTop = partitions[partitionIndex].top + partitionBottom = partitions[partitionIndex].bottom + partitionHeight = partitionBottom - partitionTop + if partitionHeight == 0: + continue + + if partitions[partitionIndex].twoNonintersectingSpanningSegments: + if partitions[partitionIndex].requiresAntiAliasing: + discard + else: # No AA required, must be 2 vertical pixel-aligned lines + let + left = partitions[partitionIndex].entries[0].segment.at.x.int + right = partitions[partitionIndex].entries[1].segment.at.x.int + minX = left.clamp(0, image.width) + maxX = right.clamp(0, image.width) + skipBlending = + blendMode == OverwriteBlend or + (blendMode == NormalBlend and rgbx.a == 255) + if skipBlending and minX == 0 and maxX == image.width: + # We can be greedy, just do one big mult-row fill + let + start = image.dataIndex(0, y) + len = image.dataIndex(0, y + partitionHeight) - start + fillUnsafe(image.data, rgbx, start, len) + else: + for r in 0 ..< partitionHeight: + hits[0] = (cast[Fixed32](minX * 256), 1.int16) + hits[1] = (cast[Fixed32](maxX * 256), -1.int16) + image.fillHits(rgbx, 0, y + r, hits, 2, NonZero, blendMode) + + y += partitionHeight + continue + computeCoverage( cast[ptr UncheckedArray[uint8]](coverages[0].addr), hits, From 9a9f8d114fa26f21d1830e1aad80562c4b535216 Mon Sep 17 00:00:00 2001 From: Ryan Oldenburg Date: Thu, 23 Jun 2022 21:26:44 -0500 Subject: [PATCH 3/3] f --- src/pixie/paths.nim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pixie/paths.nim b/src/pixie/paths.nim index 008a806..346ee0c 100644 --- a/src/pixie/paths.nim +++ b/src/pixie/paths.nim @@ -1180,13 +1180,11 @@ proc partitionSegments( for partition in result.mitems: partition.requiresAntiAliasing = requiresAntiAliasing(partition.entries) - - let - top = partition.top.float32 - bottom = partition.bottom.float32 if partition.entries.len == 2: # Clip the entries to the parition bounds let + top = partition.top.float32 + bottom = partition.bottom.float32 topLine = line(vec2(0, top), vec2(1000, top)) bottomLine = line(vec2(0, bottom), vec2(1000, bottom)) for entry in partition.entries.mitems: