per-row opaque check

This commit is contained in:
Ryan Oldenburg 2021-12-14 14:46:49 -06:00
parent 69f73f709f
commit f7ed8e7842
3 changed files with 30 additions and 31 deletions

View file

@ -1,4 +1,4 @@
import benchy, cairo, pixie, pixie/blends
import benchy, cairo, pixie, pixie/blends, pixie/internal
when defined(amd64) and not defined(pixieNoSimd):
import nimsimd/sse2
@ -7,10 +7,8 @@ when defined(release):
{.push checks: off.}
proc drawBasic(backdrop, source: Image) =
let sourceIsOpaque = source.isOpaque()
for y in 0 ..< min(backdrop.height, source.height):
if sourceIsOpaque:
if isOpaque(source.data, source.dataIndex(0, y), source.width):
copyMem(
backdrop.data[backdrop.dataIndex(0, y)].addr,
source.data[source.dataIndex(0, y)].addr,

View file

@ -182,29 +182,7 @@ proc isTransparent*(image: Image): bool {.raises: [].} =
proc isOpaque*(image: Image): bool {.raises: [].} =
## Checks if the entire image is opaque (alpha values are all 255).
result = true
var i: int
when defined(amd64) and not defined(pixieNoSimd):
let
vec255 = mm_set1_epi32(cast[int32](uint32.high))
colorMask = mm_set1_epi32(cast[int32]([255.uint8, 255, 255, 0]))
for _ in 0 ..< image.data.len div 16:
let
values0 = mm_loadu_si128(image.data[i + 0].addr)
values1 = mm_loadu_si128(image.data[i + 4].addr)
values2 = mm_loadu_si128(image.data[i + 8].addr)
values3 = mm_loadu_si128(image.data[i + 12].addr)
values01 = mm_and_si128(values0, values1)
values23 = mm_and_si128(values2, values3)
values = mm_or_si128(mm_and_si128(values01, values23), colorMask)
if mm_movemask_epi8(mm_cmpeq_epi8(values, vec255)) != 0xffff:
return false
i += 16
for j in i ..< image.data.len:
if image.data[j].a != 255:
return false
isOpaque(image.data, 0, image.data.len)
proc flipHorizontal*(image: Image) {.raises: [].} =
## Flips the image around the Y axis.
@ -789,9 +767,6 @@ proc drawUber(
if yMin > 0 and yMin < a.height:
zeroMem(a.data[0].addr, 4 * yMin * a.width)
when type(a) is Image and type(b) is Image:
let opaqueFastPath = blendMode in {bmNormal, bmOverwrite} and b.isOpaque()
for y in yMin ..< yMax:
# Determine where we should start and stop drawing in the x dimension
var
@ -852,7 +827,8 @@ proc drawUber(
var x = xStart
if not hasRotation:
when type(a) is Image and type(b) is Image:
if opaqueFastPath:
if blendMode in {bmNormal, bmOverwrite} and
isOpaque(b.data, b.dataIndex(xStart, y), xStop - xStart):
let
srcPos = p + dx * x.float32 + dy * y.float32
sx = srcPos.x.int

View file

@ -96,6 +96,31 @@ proc toPremultipliedAlpha*(data: var seq[ColorRGBA | ColorRGBX]) {.raises: [].}
c.b = ((c.b.uint32 * c.a.uint32) div 255).uint8
data[j] = c
proc isOpaque*(data: var seq[ColorRGBX], start, len: int): bool =
result = true
var i: int
when defined(amd64) and not defined(pixieNoSimd):
let
vec255 = mm_set1_epi32(cast[int32](uint32.high))
colorMask = mm_set1_epi32(cast[int32]([255.uint8, 255, 255, 0]))
for _ in 0 ..< len div 16:
let
values0 = mm_loadu_si128(data[i + 0].addr)
values1 = mm_loadu_si128(data[i + 4].addr)
values2 = mm_loadu_si128(data[i + 8].addr)
values3 = mm_loadu_si128(data[i + 12].addr)
values01 = mm_and_si128(values0, values1)
values23 = mm_and_si128(values2, values3)
values = mm_or_si128(mm_and_si128(values01, values23), colorMask)
if mm_movemask_epi8(mm_cmpeq_epi8(values, vec255)) != 0xffff:
return false
i += 16
for j in i ..< len:
if data[j].a != 255:
return false
when defined(amd64) and not defined(pixieNoSimd):
proc packAlphaValues*(v: M128i): M128i {.inline, raises: [].} =
## Shuffle the alpha values for these 4 colors to the first 4 bytes