fillHits refactor
This commit is contained in:
parent
cdc52f31ab
commit
134b7d246f
1 changed files with 90 additions and 79 deletions
|
@ -1499,6 +1499,25 @@ proc fillCoverage(
|
||||||
mask.clearUnsafe(0, y, startX, y)
|
mask.clearUnsafe(0, y, startX, y)
|
||||||
mask.clearUnsafe(startX + coverages.len, y, mask.width, y)
|
mask.clearUnsafe(startX + coverages.len, y, mask.width, y)
|
||||||
|
|
||||||
|
template walkHits(
|
||||||
|
hits: seq[(int32, int16)],
|
||||||
|
numHits: int,
|
||||||
|
windingRule: WindingRule,
|
||||||
|
y, width: int,
|
||||||
|
inner: untyped
|
||||||
|
) =
|
||||||
|
var filledTo {.inject.}: int
|
||||||
|
for (prevAt, at, count) in hits.walk(numHits, windingRule, y, width):
|
||||||
|
let
|
||||||
|
fillStart {.inject.} = prevAt.integer
|
||||||
|
fillLen {.inject.} = at.integer - fillStart
|
||||||
|
if fillLen <= 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
filledTo = fillStart + fillLen
|
||||||
|
|
||||||
|
inner
|
||||||
|
|
||||||
proc fillHits(
|
proc fillHits(
|
||||||
image: Image,
|
image: Image,
|
||||||
rgbx: ColorRGBX,
|
rgbx: ColorRGBX,
|
||||||
|
@ -1508,58 +1527,58 @@ proc fillHits(
|
||||||
windingRule: WindingRule,
|
windingRule: WindingRule,
|
||||||
blendMode: BlendMode
|
blendMode: BlendMode
|
||||||
) =
|
) =
|
||||||
let blender = blendMode.blender()
|
template simdBlob(image: Image, x: var int, blendProc: untyped) =
|
||||||
var filledTo: int
|
when allowSimd:
|
||||||
for (prevAt, at, count) in hits.walk(numHits, windingRule, y, image.width):
|
when defined(amd64):
|
||||||
let
|
|
||||||
fillStart = prevAt.integer
|
|
||||||
fillLen = at.integer - fillStart
|
|
||||||
if fillLen <= 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
filledTo = fillStart + fillLen
|
|
||||||
|
|
||||||
if blendMode == OverwriteBlend or (blendMode == NormalBlend and rgbx.a == 255):
|
|
||||||
fillUnsafe(image.data, rgbx, image.dataIndex(fillStart, y), fillLen)
|
|
||||||
continue
|
|
||||||
|
|
||||||
var x = fillStart
|
|
||||||
when defined(amd64) and allowSimd:
|
|
||||||
if blendMode.hasSimdBlender():
|
|
||||||
# When supported, SIMD blend as much as possible
|
|
||||||
let colorVec = mm_set1_epi32(cast[int32](rgbx))
|
let colorVec = mm_set1_epi32(cast[int32](rgbx))
|
||||||
if blendMode == NormalBlend:
|
|
||||||
# For path filling, NormalBlend is almost always used.
|
|
||||||
# Inline SIMD is faster here.
|
|
||||||
for _ in 0 ..< fillLen div 4:
|
for _ in 0 ..< fillLen div 4:
|
||||||
let
|
let
|
||||||
index = image.dataIndex(x, y)
|
index = image.dataIndex(x, y)
|
||||||
backdrop = mm_loadu_si128(image.data[index].addr)
|
backdrop = mm_loadu_si128(image.data[index].addr)
|
||||||
mm_storeu_si128(
|
mm_storeu_si128(image.data[index].addr, blendProc(backdrop, colorVec))
|
||||||
image.data[index].addr,
|
|
||||||
blendNormalSimd(backdrop, colorVec)
|
|
||||||
)
|
|
||||||
x += 4
|
|
||||||
else:
|
|
||||||
let blenderSimd = blendMode.blenderSimd()
|
|
||||||
for _ in 0 ..< fillLen div 4:
|
|
||||||
let
|
|
||||||
index = image.dataIndex(x, y)
|
|
||||||
backdrop = mm_loadu_si128(image.data[index].addr)
|
|
||||||
mm_storeu_si128(
|
|
||||||
image.data[index].addr,
|
|
||||||
blenderSimd(backdrop, colorVec)
|
|
||||||
)
|
|
||||||
x += 4
|
x += 4
|
||||||
|
|
||||||
|
case blendMode:
|
||||||
|
of OverwriteBlend:
|
||||||
|
walkHits hits, numHits, windingRule, y, image.width:
|
||||||
|
fillUnsafe(image.data, rgbx, image.dataIndex(fillStart, y), fillLen)
|
||||||
|
|
||||||
|
of NormalBlend:
|
||||||
|
walkHits hits, numHits, windingRule, y, image.width:
|
||||||
|
if rgbx.a == 255:
|
||||||
|
fillUnsafe(image.data, rgbx, image.dataIndex(fillStart, y), fillLen)
|
||||||
|
else:
|
||||||
|
var x = fillStart
|
||||||
|
simdBlob(image, x, blendNormalSimd)
|
||||||
for x in x ..< fillStart + fillLen:
|
for x in x ..< fillStart + fillLen:
|
||||||
let backdrop = image.unsafe[x, y]
|
let backdrop = image.unsafe[x, y]
|
||||||
image.unsafe[x, y] = blender(backdrop, rgbx)
|
image.unsafe[x, y] = blendNormal(backdrop, rgbx)
|
||||||
|
|
||||||
|
of MaskBlend:
|
||||||
|
var prevFilledTo: int
|
||||||
|
walkHits hits, numHits, windingRule, y, image.width:
|
||||||
|
block: # Clear any gap between this fill and the previous fill
|
||||||
|
let gapBetweenHits = fillStart - prevFilledTo
|
||||||
|
if gapBetweenHits > 0:
|
||||||
|
fillUnsafe(image.data, rgbx(0, 0, 0, 0), image.dataIndex(prevFilledTo, y), gapBetweenHits)
|
||||||
|
prevFilledTo = filledTo
|
||||||
|
block: # Handle this fill
|
||||||
|
var x = fillStart
|
||||||
|
simdBlob(image, x, blendMaskSimd)
|
||||||
|
for x in x ..< fillStart + fillLen:
|
||||||
|
let backdrop = image.unsafe[x, y]
|
||||||
|
image.unsafe[x, y] = blendMask(backdrop, rgbx)
|
||||||
|
|
||||||
if blendMode == MaskBlend:
|
|
||||||
image.clearUnsafe(0, y, startX, y)
|
image.clearUnsafe(0, y, startX, y)
|
||||||
image.clearUnsafe(filledTo, y, image.width, y)
|
image.clearUnsafe(filledTo, y, image.width, y)
|
||||||
|
|
||||||
|
else:
|
||||||
|
let blender = blendMode.blender()
|
||||||
|
walkHits hits, numHits, windingRule, y, image.width:
|
||||||
|
for x in fillStart ..< fillStart + fillLen:
|
||||||
|
let backdrop = image.unsafe[x, y]
|
||||||
|
image.unsafe[x, y] = blender(backdrop, rgbx)
|
||||||
|
|
||||||
proc fillHits(
|
proc fillHits(
|
||||||
mask: Mask,
|
mask: Mask,
|
||||||
startX, y: int,
|
startX, y: int,
|
||||||
|
@ -1568,45 +1587,37 @@ proc fillHits(
|
||||||
windingRule: WindingRule,
|
windingRule: WindingRule,
|
||||||
blendMode: BlendMode
|
blendMode: BlendMode
|
||||||
) =
|
) =
|
||||||
let masker = blendMode.masker()
|
case blendMode:
|
||||||
var filledTo: int
|
of NormalBlend, OverwriteBlend:
|
||||||
for (prevAt, at, count) in hits.walk(numHits, windingRule, y, mask.width):
|
walkHits hits, numHits, windingRule, y, mask.width:
|
||||||
let
|
|
||||||
fillStart = prevAt.integer
|
|
||||||
fillLen = at.integer - fillStart
|
|
||||||
if fillLen <= 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
filledTo = fillStart + fillLen
|
|
||||||
|
|
||||||
if blendMode in {NormalBlend, OverwriteBlend}:
|
|
||||||
fillUnsafe(mask.data, 255, mask.dataIndex(fillStart, y), fillLen)
|
fillUnsafe(mask.data, 255, mask.dataIndex(fillStart, y), fillLen)
|
||||||
continue
|
|
||||||
|
|
||||||
var x = fillStart
|
of MaskBlend:
|
||||||
when defined(amd64) and allowSimd:
|
var prevFilledTo: int
|
||||||
if blendMode.hasSimdMasker():
|
walkHits hits, numHits, windingRule,y, mask.width:
|
||||||
let
|
let gapBetweenHits = fillStart - prevFilledTo
|
||||||
maskerSimd = blendMode.maskerSimd()
|
if gapBetweenHits > 0:
|
||||||
valueVec = mm_set1_epi8(cast[int8](255))
|
fillUnsafe(mask.data, 0, mask.dataIndex(prevFilledTo, y), gapBetweenHits)
|
||||||
for _ in 0 ..< fillLen div 16:
|
prevFilledTo = filledTo
|
||||||
let
|
|
||||||
index = mask.dataIndex(x, y)
|
|
||||||
backdrop = mm_loadu_si128(mask.data[index].addr)
|
|
||||||
mm_storeu_si128(
|
|
||||||
mask.data[index].addr,
|
|
||||||
maskerSimd(backdrop, valueVec)
|
|
||||||
)
|
|
||||||
x += 16
|
|
||||||
|
|
||||||
for x in x ..< fillStart + fillLen:
|
|
||||||
let backdrop = mask.unsafe[x, y]
|
|
||||||
mask.unsafe[x, y] = masker(backdrop, 255)
|
|
||||||
|
|
||||||
if blendMode == MaskBlend:
|
|
||||||
mask.clearUnsafe(0, y, startX, y)
|
mask.clearUnsafe(0, y, startX, y)
|
||||||
mask.clearUnsafe(filledTo, y, mask.width, y)
|
mask.clearUnsafe(filledTo, y, mask.width, y)
|
||||||
|
|
||||||
|
of SubtractMaskBlend:
|
||||||
|
walkHits hits, numHits, windingRule, y, mask.width:
|
||||||
|
for x in fillStart ..< fillStart + fillLen:
|
||||||
|
let backdrop = mask.unsafe[x, y]
|
||||||
|
mask.unsafe[x, y] = maskBlendSubtract(backdrop, 255)
|
||||||
|
|
||||||
|
of ExcludeMaskBlend:
|
||||||
|
walkHits hits, numHits, windingRule, y, mask.width:
|
||||||
|
for x in fillStart ..< fillStart + fillLen:
|
||||||
|
let backdrop = mask.unsafe[x, y]
|
||||||
|
mask.unsafe[x, y] = maskBlendExclude(backdrop, 255)
|
||||||
|
|
||||||
|
else:
|
||||||
|
failUnsupportedBlendMode(blendMode)
|
||||||
|
|
||||||
proc fillShapes(
|
proc fillShapes(
|
||||||
image: Image,
|
image: Image,
|
||||||
shapes: seq[Polygon],
|
shapes: seq[Polygon],
|
||||||
|
|
Loading…
Reference in a new issue