From 78e23f83d659c8f62f5d7647b7c144f4e39e6707 Mon Sep 17 00:00:00 2001 From: Ryan Oldenburg Date: Sun, 30 Jan 2022 14:51:42 -0600 Subject: [PATCH] fix and re-enable fill optimization --- src/pixie/images.nim | 19 ++++---- src/pixie/internal.nim | 35 +++++++------- tests/{paths => images}/fillOptimization.png | Bin tests/images/fillOptimization2.png | Bin 0 -> 393 bytes tests/test_images_draw.nim | 46 +++++++++++++++++++ tests/test_paths.nim | 19 -------- 6 files changed, 72 insertions(+), 47 deletions(-) rename tests/{paths => images}/fillOptimization.png (100%) create mode 100644 tests/images/fillOptimization2.png diff --git a/src/pixie/images.nim b/src/pixie/images.nim index 5190c97..22e16e3 100644 --- a/src/pixie/images.nim +++ b/src/pixie/images.nim @@ -792,16 +792,15 @@ proc drawUber( sy = srcPos.y.int var sx = srcPos.x.int - # TODO Fix - # when type(a) is Image and type(b) is Image: - # if blendMode in {bmNormal, bmOverwrite} and - # isOpaque(b.data, b.dataIndex(sx, sy), xStop - sx): - # copyMem( - # a.data[a.dataIndex(x, y)].addr, - # b.data[b.dataIndex(sx, sy)].addr, - # (xStop - xStart) * 4 - # ) - # continue + when type(a) is Image and type(b) is Image: + if blendMode in {bmNormal, bmOverwrite} and + isOpaque(b.data, b.dataIndex(sx, sy), xStop - xStart): + copyMem( + a.data[a.dataIndex(x, y)].addr, + b.data[b.dataIndex(sx, sy)].addr, + (xStop - xStart) * 4 + ) + continue when defined(amd64) and not defined(pixieNoSimd): case blendMode: diff --git a/src/pixie/internal.nim b/src/pixie/internal.nim index 91662b4..eea791f 100644 --- a/src/pixie/internal.nim +++ b/src/pixie/internal.nim @@ -139,24 +139,23 @@ proc toPremultipliedAlpha*(data: var seq[ColorRGBA | ColorRGBX]) {.raises: [].} proc isOpaque*(data: var seq[ColorRGBX], start, len: int): bool = result = true - var i: int = start - # TODO FIX: - # 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 start div 16 ..< (start + 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 + var i = start + 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 start ..< (start + 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 ..< start + len: if data[j].a != 255: diff --git a/tests/paths/fillOptimization.png b/tests/images/fillOptimization.png similarity index 100% rename from tests/paths/fillOptimization.png rename to tests/images/fillOptimization.png diff --git a/tests/images/fillOptimization2.png b/tests/images/fillOptimization2.png new file mode 100644 index 0000000000000000000000000000000000000000..3f1f9ab8c55f277e61ffa8ead9c353ae915c87af GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^DImsN z>*C)%3Wf0Y4crd-`&C}n@wBa?YryAt_xH)oe|-GWF5f$k*OyB@5BT@i_W6Hetx1~``C|RY+vzOZcbxnFZ1%T( zmY)B9?fvzdC0M}6(SY@!2r-N&{^zgvT0Z~tE7*SHHTCfQ?fKh@^QwIB)>Vy@Ckk}~ PgP6h7)z4*}Q$iB}_SBZ@ literal 0 HcmV?d00001 diff --git a/tests/test_images_draw.nim b/tests/test_images_draw.nim index f330598..99f3067 100644 --- a/tests/test_images_draw.nim +++ b/tests/test_images_draw.nim @@ -270,3 +270,49 @@ block: rock = readImage("tests/images/rock.png") minified = rock.minifyBy2(2) doDiff(minified, "rock_minified2") + +block: + let pathStr = """ + M 0 0 + L 20 0 + L 20 20 + L 0 20 + z + """ + let + image = newImage(20, 20) + strokeImage = newImage(20, 20) + image.fillPath(pathStr, color(1.0, 0.5, 0.25, 1.0)) + strokeImage.strokePath(pathStr, color(1, 1, 1, 1), strokeWidth = 4) + image.draw(strokeImage) + + image.writeFile("tests/images/fillOptimization.png") + doAssert image[10, 10] == rgbx(255, 127, 63, 255) + +block: + let a = newImage(100, 100) + a.fill(color(1, 1, 1, 1)) + + + let draws = [ + # Overlaps in bounds + (vec2(-50, -50), color(1, 0, 0, 1)), + (vec2(50, -50), color(1, 0, 0, 1)), + (vec2(50, 50), color(1, 0, 0, 1)), + (vec2(-50, 50), color(1, 0, 0, 1)), + # Out of bounds + (vec2(-100, 00), color(1, 0, 0, 1)), + (vec2(0, -100), color(1, 0, 0, 1)), + (vec2(100, 00), color(1, 0, 0, 1)), + (vec2(0, 100), color(1, 0, 0, 1)) + ] + for (translation, color) in draws: + let + b = newImage(100, 100) + path = newPath() + path.rect(0, 0, b.width.float32, b.height.float32) + b.strokePath(path, color, strokeWidth = 20) + + a.draw(b, translate(translation)) + + a.writeFile("tests/images/fillOptimization2.png") diff --git a/tests/test_paths.nim b/tests/test_paths.nim index e6e9d39..e6ee881 100644 --- a/tests/test_paths.nim +++ b/tests/test_paths.nim @@ -1,24 +1,5 @@ import chroma, pixie, pixie/fileformats/png, strformat - -block: - let pathStr = """ - M 0 0 - L 20 0 - L 20 20 - L 0 20 - z - """ - let - image = newImage(20, 20) - strokeImage = newImage(20, 20) - image.fillPath(pathStr, color(1.0, 0.5, 0.25, 1.0)) - strokeImage.strokePath(pathStr, color(1, 1, 1, 1), strokeWidth = 4) - image.draw(strokeImage) - - image.writeFile("tests/paths/fillOptimization.png") - doAssert image[10, 10] == rgbx(255, 127, 63, 255) - block: let pathStr = """ m 1 2 3 4 5 6