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(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(
|
||||
image: Image,
|
||||
rgbx: ColorRGBX,
|
||||
|
@ -1508,58 +1527,58 @@ proc fillHits(
|
|||
windingRule: WindingRule,
|
||||
blendMode: BlendMode
|
||||
) =
|
||||
let blender = blendMode.blender()
|
||||
var filledTo: int
|
||||
for (prevAt, at, count) in hits.walk(numHits, windingRule, y, image.width):
|
||||
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
|
||||
template simdBlob(image: Image, x: var int, blendProc: untyped) =
|
||||
when allowSimd:
|
||||
when defined(amd64):
|
||||
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:
|
||||
let
|
||||
index = image.dataIndex(x, y)
|
||||
backdrop = mm_loadu_si128(image.data[index].addr)
|
||||
mm_storeu_si128(
|
||||
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
|
||||
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, blendProc(backdrop, colorVec))
|
||||
x += 4
|
||||
|
||||
for x in x ..< fillStart + fillLen:
|
||||
let backdrop = image.unsafe[x, y]
|
||||
image.unsafe[x, y] = blender(backdrop, rgbx)
|
||||
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:
|
||||
let backdrop = image.unsafe[x, y]
|
||||
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(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(
|
||||
mask: Mask,
|
||||
startX, y: int,
|
||||
|
@ -1568,45 +1587,37 @@ proc fillHits(
|
|||
windingRule: WindingRule,
|
||||
blendMode: BlendMode
|
||||
) =
|
||||
let masker = blendMode.masker()
|
||||
var filledTo: int
|
||||
for (prevAt, at, count) in hits.walk(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}:
|
||||
case blendMode:
|
||||
of NormalBlend, OverwriteBlend:
|
||||
walkHits hits, numHits, windingRule, y, mask.width:
|
||||
fillUnsafe(mask.data, 255, mask.dataIndex(fillStart, y), fillLen)
|
||||
continue
|
||||
|
||||
var x = fillStart
|
||||
when defined(amd64) and allowSimd:
|
||||
if blendMode.hasSimdMasker():
|
||||
let
|
||||
maskerSimd = blendMode.maskerSimd()
|
||||
valueVec = mm_set1_epi8(cast[int8](255))
|
||||
for _ in 0 ..< fillLen div 16:
|
||||
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
|
||||
of MaskBlend:
|
||||
var prevFilledTo: int
|
||||
walkHits hits, numHits, windingRule,y, mask.width:
|
||||
let gapBetweenHits = fillStart - prevFilledTo
|
||||
if gapBetweenHits > 0:
|
||||
fillUnsafe(mask.data, 0, mask.dataIndex(prevFilledTo, y), gapBetweenHits)
|
||||
prevFilledTo = filledTo
|
||||
|
||||
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(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(
|
||||
image: Image,
|
||||
shapes: seq[Polygon],
|
||||
|
|
Loading…
Reference in a new issue