avoid unsafe[] in loops

This commit is contained in:
Ryan Oldenburg 2022-06-20 20:00:29 -05:00
parent d2b84e76ca
commit ee442977fa

View file

@ -1336,7 +1336,9 @@ proc fillCoverage(
coverages: seq[uint8], coverages: seq[uint8],
blendMode: BlendMode blendMode: BlendMode
) = ) =
var x = startX var
x = startX
dataIndex = image.dataIndex(x, y)
when allowSimd: when allowSimd:
when defined(amd64): when defined(amd64):
@ -1389,51 +1391,61 @@ proc fillCoverage(
when allowSimd: when allowSimd:
when defined(amd64): when defined(amd64):
for (coverageVec, allZeroes, all255) in simd(coverages, x, startX): for (coverageVec, allZeroes, all255) in simd(coverages, x, startX):
if not allZeroes: if allZeroes:
dataIndex += 16
else:
if all255: if all255:
for i in 0 ..< 4: for i in 0 ..< 4:
mm_storeu_si128(image.unsafe[x + i * 4, y].addr, colorVec) mm_storeu_si128(image.data[dataIndex].addr, colorVec)
dataIndex += 4
else: else:
var coverageVec = coverageVec var coverageVec = coverageVec
for i in 0 ..< 4: for i in 0 ..< 4:
let source = source(colorVec, coverageVec) let source = source(colorVec, coverageVec)
mm_storeu_si128(image.unsafe[x + i * 4, y].addr, source) mm_storeu_si128(image.data[dataIndex].addr, source)
coverageVec = mm_srli_si128(coverageVec, 4) coverageVec = mm_srli_si128(coverageVec, 4)
dataIndex += 4
for x in x ..< startX + coverages.len: for x in x ..< startX + coverages.len:
let coverage = coverages[x - startX] let coverage = coverages[x - startX]
if coverage != 0: if coverage != 0:
image.unsafe[x, y] = source(rgbx, coverage) image.data[dataIndex] = source(rgbx, coverage)
inc dataIndex
of NormalBlend: of NormalBlend:
when allowSimd: when allowSimd:
when defined(amd64): when defined(amd64):
for (coverageVec, allZeroes, all255) in simd(coverages, x, startX): for (coverageVec, allZeroes, all255) in simd(coverages, x, startX):
if not allZeroes: if allZeroes:
dataIndex += 16
else:
if all255 and rgbx.a == 255: if all255 and rgbx.a == 255:
for i in 0 ..< 4: for i in 0 ..< 4:
mm_storeu_si128(image.unsafe[x + i * 4, y].addr, colorVec) mm_storeu_si128(image.data[dataIndex].addr, colorVec)
dataIndex += 4
else: else:
var coverageVec = coverageVec var coverageVec = coverageVec
for i in 0 ..< 4: for i in 0 ..< 4:
let let
backdrop = mm_loadu_si128(image.unsafe[x + i * 4, y].addr) backdrop = mm_loadu_si128(image.data[dataIndex].addr)
source = source(colorVec, coverageVec) source = source(colorVec, coverageVec)
mm_storeu_si128( mm_storeu_si128(
image.unsafe[x + i * 4, y].addr, image.data[dataIndex].addr,
blendNormalSimd(backdrop, source) blendNormalSimd(backdrop, source)
) )
coverageVec = mm_srli_si128(coverageVec, 4) coverageVec = mm_srli_si128(coverageVec, 4)
dataIndex += 4
for x in x ..< startX + coverages.len: for x in x ..< startX + coverages.len:
let coverage = coverages[x - startX] let coverage = coverages[x - startX]
if coverage == 255 and rgbx.a == 255: if coverage == 255 and rgbx.a == 255:
image.unsafe[x, y] = rgbx image.data[dataIndex] = rgbx
elif coverage == 0: elif coverage == 0:
discard discard
else: else:
let backdrop = image.unsafe[x, y] let backdrop = image.data[dataIndex]
image.unsafe[x, y] = blendNormal(backdrop, source(rgbx, coverage)) image.data[dataIndex] = blendNormal(backdrop, source(rgbx, coverage))
inc dataIndex
of MaskBlend: of MaskBlend:
{.linearScanEnd.} {.linearScanEnd.}
@ -1443,31 +1455,34 @@ proc fillCoverage(
for (coverageVec, allZeroes, all255) in simd(coverages, x, startX): for (coverageVec, allZeroes, all255) in simd(coverages, x, startX):
if not allZeroes: if not allZeroes:
if all255: if all255:
discard dataIndex += 16
else: else:
var coverageVec = coverageVec var coverageVec = coverageVec
for i in 0 ..< 4: for i in 0 ..< 4:
let let
backdrop = mm_loadu_si128(image.unsafe[x + i * 4, y].addr) backdrop = mm_loadu_si128(image.data[dataIndex].addr)
source = source(colorVec, coverageVec) source = source(colorVec, coverageVec)
mm_storeu_si128( mm_storeu_si128(
image.unsafe[x + i * 4, y].addr, image.data[dataIndex].addr,
blendMaskSimd(backdrop, source) blendMaskSimd(backdrop, source)
) )
coverageVec = mm_srli_si128(coverageVec, 4) coverageVec = mm_srli_si128(coverageVec, 4)
dataIndex += 4
else: else:
for i in 0 ..< 4: for i in 0 ..< 4:
mm_storeu_si128(image.unsafe[x + i * 4, y].addr, mm_setzero_si128()) mm_storeu_si128(image.data[dataIndex].addr, mm_setzero_si128())
dataIndex += 4
for x in x ..< startX + coverages.len: for x in x ..< startX + coverages.len:
let coverage = coverages[x - startX] let coverage = coverages[x - startX]
if coverage == 0: if coverage == 0:
image.unsafe[x, y] = rgbx(0, 0, 0, 0) image.data[dataIndex] = rgbx(0, 0, 0, 0)
elif coverage == 255: elif coverage == 255:
discard discard
else: else:
let backdrop = image.unsafe[x, y] let backdrop = image.data[dataIndex]
image.unsafe[x, y] = blendMask(backdrop, source(rgbx, coverage)) image.data[dataIndex] = blendMask(backdrop, source(rgbx, coverage))
inc dataIndex
image.clearUnsafe(0, y, startX, y) image.clearUnsafe(0, y, startX, y)
image.clearUnsafe(startX + coverages.len, y, image.width, y) image.clearUnsafe(startX + coverages.len, y, image.width, y)
@ -1476,25 +1491,28 @@ proc fillCoverage(
for x in x ..< startX + coverages.len: for x in x ..< startX + coverages.len:
let coverage = coverages[x - startX] let coverage = coverages[x - startX]
if coverage == 255 and rgbx.a == 255: if coverage == 255 and rgbx.a == 255:
image.unsafe[x, y] = rgbx(0, 0, 0, 0) image.data[dataIndex] = rgbx(0, 0, 0, 0)
elif coverage != 0: elif coverage != 0:
let backdrop = image.unsafe[x, y] let backdrop = image.data[dataIndex]
image.unsafe[x, y] = blendSubtractMask(backdrop, source(rgbx, coverage)) image.data[dataIndex] = blendSubtractMask(backdrop, source(rgbx, coverage))
inc dataIndex
of ExcludeMaskBlend: of ExcludeMaskBlend:
for x in x ..< startX + coverages.len: for x in x ..< startX + coverages.len:
let let
coverage = coverages[x - startX] coverage = coverages[x - startX]
backdrop = image.unsafe[x, y] backdrop = image.data[dataIndex]
image.unsafe[x, y] = blendExcludeMask(backdrop, source(rgbx, coverage)) image.data[dataIndex] = blendExcludeMask(backdrop, source(rgbx, coverage))
inc dataIndex
else: else:
let blender = blendMode.blender() let blender = blendMode.blender()
for x in x ..< startX + coverages.len: for x in x ..< startX + coverages.len:
let coverage = coverages[x - startX] let coverage = coverages[x - startX]
if coverage != 0: if coverage != 0:
let backdrop = image.unsafe[x, y] let backdrop = image.data[dataIndex]
image.unsafe[x, y] = blender(backdrop, source(rgbx, coverage)) image.data[dataIndex] = blender(backdrop, source(rgbx, coverage))
inc dataIndex
proc fillCoverage( proc fillCoverage(
mask: Mask, mask: Mask,
@ -1502,7 +1520,9 @@ proc fillCoverage(
coverages: seq[uint8], coverages: seq[uint8],
blendMode: BlendMode blendMode: BlendMode
) = ) =
var x = startX var
x = startX
dataIndex = mask.dataIndex(x, y)
template simdBlob(blendProc: untyped) = template simdBlob(blendProc: untyped) =
when allowSimd: when allowSimd:
@ -1513,19 +1533,21 @@ proc fillCoverage(
eqZero = mm_cmpeq_epi8(coveragesVec, mm_setzero_si128()) eqZero = mm_cmpeq_epi8(coveragesVec, mm_setzero_si128())
allZeroes = mm_movemask_epi8(eqZero) == 0xffff allZeroes = mm_movemask_epi8(eqZero) == 0xffff
if not allZeroes: if not allZeroes:
let backdrop = mm_loadu_si128(mask.unsafe[x, y].addr) let backdrop = mm_loadu_si128(mask.data[dataIndex].addr)
mm_storeu_si128( mm_storeu_si128(
mask.unsafe[x, y].addr, mask.data[dataIndex].addr,
blendProc(backdrop, coveragesVec) blendProc(backdrop, coveragesVec)
) )
x += 16 x += 16
dataIndex += 16
template blendBlob(blendProc: untyped) = template blendBlob(blendProc: untyped) =
for x in x ..< startX + coverages.len: for x in x ..< startX + coverages.len:
let coverage = coverages[x - startX] let coverage = coverages[x - startX]
if coverage != 0: if coverage != 0:
let backdrop = mask.unsafe[x, y] let backdrop = mask.data[dataIndex]
mask.unsafe[x, y] = blendProc(backdrop, coverage) mask.data[dataIndex] = blendProc(backdrop, coverage)
inc dataIndex
case blendMode: case blendMode:
of OverwriteBlend: of OverwriteBlend:
@ -1550,22 +1572,24 @@ proc fillCoverage(
eqZero = mm_cmpeq_epi8(coveragesVec, mm_setzero_si128()) eqZero = mm_cmpeq_epi8(coveragesVec, mm_setzero_si128())
allZeroes = mm_movemask_epi8(eqZero) == 0xffff allZeroes = mm_movemask_epi8(eqZero) == 0xffff
if not allZeroes: if not allZeroes:
let backdrop = mm_loadu_si128(mask.unsafe[x, y].addr) let backdrop = mm_loadu_si128(mask.data[dataIndex].addr)
mm_storeu_si128( mm_storeu_si128(
mask.unsafe[x, y].addr, mask.data[dataIndex].addr,
maskBlendMaskSimd(backdrop, coveragesVec) maskBlendMaskSimd(backdrop, coveragesVec)
) )
else: else:
mm_storeu_si128(mask.unsafe[x, y].addr, mm_setzero_si128()) mm_storeu_si128(mask.data[dataIndex].addr, mm_setzero_si128())
x += 16 x += 16
dataIndex += 16
for x in x ..< startX + coverages.len: for x in x ..< startX + coverages.len:
let coverage = coverages[x - startX] let coverage = coverages[x - startX]
if coverage != 0: if coverage != 0:
let backdrop = mask.unsafe[x, y] let backdrop = mask.data[dataIndex]
mask.unsafe[x, y] = maskBlendMask(backdrop, coverage) mask.data[dataIndex] = maskBlendMask(backdrop, coverage)
else: else:
mask.unsafe[x, y] = 0 mask.data[dataIndex] = 0
inc dataIndex
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)
@ -1595,10 +1619,15 @@ proc fillHits(
when allowSimd: when allowSimd:
when defined(amd64): when defined(amd64):
let colorVec = mm_set1_epi32(cast[int32](rgbx)) let colorVec = mm_set1_epi32(cast[int32](rgbx))
var dataIndex = image.dataIndex(x, y)
for _ in 0 ..< len div 4: for _ in 0 ..< len div 4:
let backdrop = mm_loadu_si128(image.unsafe[x, y].addr) let backdrop = mm_loadu_si128(image.data[dataIndex].addr)
mm_storeu_si128(image.unsafe[x, y].addr, blendProc(backdrop, colorVec)) mm_storeu_si128(
image.data[dataIndex].addr,
blendProc(backdrop, colorVec)
)
x += 4 x += 4
dataIndex += 4
case blendMode: case blendMode:
of OverwriteBlend: of OverwriteBlend:
@ -1612,9 +1641,11 @@ proc fillHits(
else: else:
var x = start var x = start
simdBlob(image, x, len, blendNormalSimd) simdBlob(image, x, len, blendNormalSimd)
for x in x ..< start + len: var dataIndex = image.dataIndex(x, y)
let backdrop = image.unsafe[x, y] for _ in x ..< start + len:
image.unsafe[x, y] = blendNormal(backdrop, rgbx) let backdrop = image.data[dataIndex]
image.data[dataIndex] = blendNormal(backdrop, rgbx)
inc dataIndex
of MaskBlend: of MaskBlend:
{.linearScanEnd.} {.linearScanEnd.}
@ -1635,34 +1666,41 @@ proc fillHits(
if rgbx.a != 255: if rgbx.a != 255:
var x = start var x = start
simdBlob(image, x, len, blendMaskSimd) simdBlob(image, x, len, blendMaskSimd)
for x in x ..< start + len: var dataIndex = image.dataIndex(x, y)
let backdrop = image.unsafe[x, y] for _ in x ..< start + len:
image.unsafe[x, y] = blendMask(backdrop, rgbx) let backdrop = image.data[dataIndex]
image.data[dataIndex] = blendMask(backdrop, rgbx)
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)
of SubtractMaskBlend: of SubtractMaskBlend:
for (start, len) in hits.walkInteger(numHits, windingRule, y, image.width): for (start, len) in hits.walkInteger(numHits, windingRule, y, image.width):
for x in start ..< start + len: var dataIndex = image.dataIndex(start, y)
for _ in 0 ..< len:
if rgbx.a == 255: if rgbx.a == 255:
image.unsafe[x, y] = rgbx(0, 0, 0, 0) image.data[dataIndex] = rgbx(0, 0, 0, 0)
else: else:
let backdrop = image.unsafe[x, y] let backdrop = image.data[dataIndex]
image.unsafe[x, y] = blendSubtractMask(backdrop, rgbx) image.data[dataIndex] = blendSubtractMask(backdrop, rgbx)
inc dataIndex
of ExcludeMaskBlend: of ExcludeMaskBlend:
for (start, len) in hits.walkInteger(numHits, windingRule, y, image.width): for (start, len) in hits.walkInteger(numHits, windingRule, y, image.width):
for x in start ..< start + len: var dataIndex = image.dataIndex(start, y)
let backdrop = image.unsafe[x, y] for _ in 0 ..< len:
image.unsafe[x, y] = blendExcludeMask(backdrop, rgbx) let backdrop = image.data[dataIndex]
image.data[dataIndex] = blendExcludeMask(backdrop, rgbx)
inc dataIndex
else: else:
let blender = blendMode.blender() let blender = blendMode.blender()
for (start, len) in hits.walkInteger(numHits, windingRule, y, image.width): for (start, len) in hits.walkInteger(numHits, windingRule, y, image.width):
for x in start ..< start + len: var dataIndex = image.dataIndex(start, y)
let backdrop = image.unsafe[x, y] for _ in 0 ..< len:
image.unsafe[x, y] = blender(backdrop, rgbx) let backdrop = image.data[dataIndex]
image.data[dataIndex] = blender(backdrop, rgbx)
inc dataIndex
proc fillHits( proc fillHits(
mask: Mask, mask: Mask,
@ -1676,10 +1714,15 @@ proc fillHits(
when allowSimd: when allowSimd:
when defined(amd64): when defined(amd64):
let vec255 = mm_set1_epi8(255) let vec255 = mm_set1_epi8(255)
var dataIndex = mask.dataIndex(x, y)
for _ in 0 ..< len div 16: for _ in 0 ..< len div 16:
let backdrop = mm_loadu_si128(mask.unsafe[x, y].addr) let backdrop = mm_loadu_si128(mask.data[dataIndex].addr)
mm_storeu_si128(mask.unsafe[x, y].addr, blendProc(backdrop, vec255)) mm_storeu_si128(
mask.data[dataIndex].addr,
blendProc(backdrop, vec255)
)
x += 16 x += 16
dataIndex += 16
case blendMode: case blendMode:
of NormalBlend, OverwriteBlend: of NormalBlend, OverwriteBlend:
@ -1703,17 +1746,21 @@ proc fillHits(
for (start, len) in hits.walkInteger(numHits, windingRule, y, mask.width): for (start, len) in hits.walkInteger(numHits, windingRule, y, mask.width):
var x = start var x = start
simdBlob(mask, x, len, maskBlendSubtractSimd) simdBlob(mask, x, len, maskBlendSubtractSimd)
for x in x ..< start + len: var dataIndex = mask.dataIndex(x, y)
let backdrop = mask.unsafe[x, y] for _ in x ..< start + len:
mask.unsafe[x, y] = maskBlendSubtract(backdrop, 255) let backdrop = mask.data[dataIndex]
mask.data[dataIndex] = maskBlendSubtract(backdrop, 255)
inc dataIndex
of ExcludeMaskBlend: of ExcludeMaskBlend:
for (start, len) in hits.walkInteger(numHits, windingRule, y, mask.width): for (start, len) in hits.walkInteger(numHits, windingRule, y, mask.width):
var x = start var x = start
simdBlob(mask, x, len, maskBlendExcludeSimd) simdBlob(mask, x, len, maskBlendExcludeSimd)
for x in x ..< start + len: var dataIndex = mask.dataIndex(x, y)
let backdrop = mask.unsafe[x, y] for _ in x ..< start + len:
mask.unsafe[x, y] = maskBlendExclude(backdrop, 255) let backdrop = mask.data[dataIndex]
mask.data[dataIndex] = maskBlendExclude(backdrop, 255)
inc dataIndex
else: else:
failUnsupportedBlendMode(blendMode) failUnsupportedBlendMode(blendMode)