aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkBlitMask_D32.cpp
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-18 13:56:50 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-18 13:56:50 +0000
commitedb606cb999887d54629f361bcbf57c5fede1bb0 (patch)
tree60ec20fa1b2814dc1d292b6de9f1f299399e1de5 /src/core/SkBlitMask_D32.cpp
parent095186a466f92b871c8ef8385246405426a67adb (diff)
move LCD blits into opts, so they can have assembly versions
git-svn-id: http://skia.googlecode.com/svn/trunk@2484 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkBlitMask_D32.cpp')
-rw-r--r--src/core/SkBlitMask_D32.cpp384
1 files changed, 384 insertions, 0 deletions
diff --git a/src/core/SkBlitMask_D32.cpp b/src/core/SkBlitMask_D32.cpp
new file mode 100644
index 0000000000..45d2d119a9
--- /dev/null
+++ b/src/core/SkBlitMask_D32.cpp
@@ -0,0 +1,384 @@
+#include "SkBlitMask.h"
+#include "SkColor.h"
+#include "SkColorPriv.h"
+
+static void D32_A8_Color(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT maskPtr, size_t maskRB,
+ SkColor color, int width, int height) {
+ SkPMColor pmc = SkPreMultiplyColor(color);
+ size_t dstOffset = dstRB - (width << 2);
+ size_t maskOffset = maskRB - width;
+ SkPMColor* SK_RESTRICT device = (SkPMColor *)dst;
+ const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
+
+ do {
+ int w = width;
+ do {
+ unsigned aa = *mask++;
+ *device = SkBlendARGB32(pmc, *device, aa);
+ device += 1;
+ } while (--w != 0);
+ device = (uint32_t*)((char*)device + dstOffset);
+ mask += maskOffset;
+ } while (--height != 0);
+}
+
+static void D32_A8_Opaque(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT maskPtr, size_t maskRB,
+ SkColor color, int width, int height) {
+ SkPMColor pmc = SkPreMultiplyColor(color);
+ SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
+ const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
+
+ maskRB -= width;
+ dstRB -= (width << 2);
+ do {
+ int w = width;
+ do {
+ unsigned aa = *mask++;
+ *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
+ device += 1;
+ } while (--w != 0);
+ device = (uint32_t*)((char*)device + dstRB);
+ mask += maskRB;
+ } while (--height != 0);
+}
+
+static void D32_A8_Black(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT maskPtr, size_t maskRB,
+ SkColor, int width, int height) {
+ SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
+ const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
+
+ maskRB -= width;
+ dstRB -= (width << 2);
+ do {
+ int w = width;
+ do {
+ unsigned aa = *mask++;
+ *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
+ device += 1;
+ } while (--w != 0);
+ device = (uint32_t*)((char*)device + dstRB);
+ mask += maskRB;
+ } while (--height != 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static inline int upscale31To32(int value) {
+ SkASSERT((unsigned)value <= 31);
+ return value + (value >> 4);
+}
+
+static inline int blend32(int src, int dst, int scale) {
+ SkASSERT((unsigned)src <= 0xFF);
+ SkASSERT((unsigned)dst <= 0xFF);
+ SkASSERT((unsigned)scale <= 32);
+ return dst + ((src - dst) * scale >> 5);
+}
+
+static void blit_lcd16_row(SkPMColor dst[], const uint16_t src[],
+ SkColor color, int width, SkPMColor) {
+ int srcA = SkColorGetA(color);
+ int srcR = SkColorGetR(color);
+ int srcG = SkColorGetG(color);
+ int srcB = SkColorGetB(color);
+
+ srcA = SkAlpha255To256(srcA);
+
+ for (int i = 0; i < width; i++) {
+ uint16_t mask = src[i];
+ if (0 == mask) {
+ continue;
+ }
+
+ SkPMColor d = dst[i];
+
+ /* We want all of these in 5bits, hence the shifts in case one of them
+ * (green) is 6bits.
+ */
+ int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5);
+ int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5);
+ int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
+
+ // Now upscale them to 0..32, so we can use blend32
+ maskR = upscale31To32(maskR);
+ maskG = upscale31To32(maskG);
+ maskB = upscale31To32(maskB);
+
+ maskR = maskR * srcA >> 8;
+ maskG = maskG * srcA >> 8;
+ maskB = maskB * srcA >> 8;
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required\
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ blend32(srcR, dstR, maskR),
+ blend32(srcG, dstG, maskG),
+ blend32(srcB, dstB, maskB));
+ }
+}
+
+static void blit_lcd16_opaque_row(SkPMColor dst[], const uint16_t src[],
+ SkColor color, int width, SkPMColor opaqueDst) {
+ int srcR = SkColorGetR(color);
+ int srcG = SkColorGetG(color);
+ int srcB = SkColorGetB(color);
+
+ for (int i = 0; i < width; i++) {
+ uint16_t mask = src[i];
+ if (0 == mask) {
+ continue;
+ }
+ if (0xFFFF == mask) {
+ dst[i] = opaqueDst;
+ continue;
+ }
+
+ SkPMColor d = dst[i];
+
+ /* We want all of these in 5bits, hence the shifts in case one of them
+ * (green) is 6bits.
+ */
+ int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5);
+ int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5);
+ int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
+
+ // Now upscale them to 0..32, so we can use blend32
+ maskR = upscale31To32(maskR);
+ maskG = upscale31To32(maskG);
+ maskB = upscale31To32(maskB);
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ blend32(srcR, dstR, maskR),
+ blend32(srcG, dstG, maskG),
+ blend32(srcB, dstB, maskB));
+ }
+}
+
+static void D32_LCD16_Proc(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT mask, size_t maskRB,
+ SkColor color, int width, int height) {
+
+ SkPMColor* dstRow = (SkPMColor*)dst;
+ const uint16_t* srcRow = (const uint16_t*)mask;
+ SkPMColor opaqueDst;
+
+ void (*proc)(SkPMColor dst[], const uint16_t src[],
+ SkColor color, int width, SkPMColor);
+ if (0xFF == SkColorGetA(color)) {
+ proc = blit_lcd16_opaque_row;
+ opaqueDst = SkPreMultiplyColor(color);
+ } else {
+ proc = blit_lcd16_row;
+ opaqueDst = 0; // ignored
+ }
+
+ do {
+ proc(dstRow, srcRow, color, width, opaqueDst);
+ dstRow = (SkPMColor*)((char*)dstRow + dstRB);
+ srcRow = (const uint16_t*)((const char*)srcRow + maskRB);
+ } while (--height != 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void blit_lcd32_opaque_row(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src,
+ SkColor color, int width) {
+ int srcR = SkColorGetR(color);
+ int srcG = SkColorGetG(color);
+ int srcB = SkColorGetB(color);
+
+ for (int i = 0; i < width; i++) {
+ SkPMColor mask = src[i];
+ if (0 == mask) {
+ continue;
+ }
+
+ SkPMColor d = dst[i];
+
+ int maskR = SkGetPackedR32(mask);
+ int maskG = SkGetPackedG32(mask);
+ int maskB = SkGetPackedB32(mask);
+
+ // Now upscale them to 0..256, so we can use SkAlphaBlend
+ maskR = SkAlpha255To256(maskR);
+ maskG = SkAlpha255To256(maskG);
+ maskB = SkAlpha255To256(maskB);
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ SkAlphaBlend(srcR, dstR, maskR),
+ SkAlphaBlend(srcG, dstG, maskG),
+ SkAlphaBlend(srcB, dstB, maskB));
+ }
+}
+
+static void blit_lcd32_row(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src,
+ SkColor color, int width) {
+ int srcA = SkColorGetA(color);
+ int srcR = SkColorGetR(color);
+ int srcG = SkColorGetG(color);
+ int srcB = SkColorGetB(color);
+
+ srcA = SkAlpha255To256(srcA);
+
+ for (int i = 0; i < width; i++) {
+ SkPMColor mask = src[i];
+ if (0 == mask) {
+ continue;
+ }
+
+ SkPMColor d = dst[i];
+
+ int maskR = SkGetPackedR32(mask);
+ int maskG = SkGetPackedG32(mask);
+ int maskB = SkGetPackedB32(mask);
+
+ // Now upscale them to 0..256, so we can use SkAlphaBlend
+ maskR = SkAlpha255To256(maskR);
+ maskG = SkAlpha255To256(maskG);
+ maskB = SkAlpha255To256(maskB);
+
+ maskR = maskR * srcA >> 8;
+ maskG = maskG * srcA >> 8;
+ maskB = maskB * srcA >> 8;
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ SkAlphaBlend(srcR, dstR, maskR),
+ SkAlphaBlend(srcG, dstG, maskG),
+ SkAlphaBlend(srcB, dstB, maskB));
+ }
+}
+
+static void D32_LCD32_Blend(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT mask, size_t maskRB,
+ SkColor color, int width, int height) {
+ SkASSERT(height > 0);
+ SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst;
+ const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask;
+
+ do {
+ blit_lcd32_row(dstRow, srcRow, color, width);
+ dstRow = (SkPMColor*)((char*)dstRow + dstRB);
+ srcRow = (const SkPMColor*)((const char*)srcRow + maskRB);
+ } while (--height != 0);
+}
+
+static void D32_LCD32_Opaque(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT mask, size_t maskRB,
+ SkColor color, int width, int height) {
+ SkASSERT(height > 0);
+ SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst;
+ const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask;
+
+ do {
+ blit_lcd32_opaque_row(dstRow, srcRow, color, width);
+ dstRow = (SkPMColor*)((char*)dstRow + dstRB);
+ srcRow = (const SkPMColor*)((const char*)srcRow + maskRB);
+ } while (--height != 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBlitMask::Proc D32_A8_Factory(SkColor color) {
+ if (SK_ColorBLACK == color) {
+ return D32_A8_Black;
+ } else if (0xFF == SkColorGetA(color)) {
+ return D32_A8_Opaque;
+ } else {
+ return D32_A8_Color;
+ }
+}
+
+static SkBlitMask::Proc D32_LCD32_Factory(SkColor color) {
+ return (0xFF == SkColorGetA(color)) ? D32_LCD32_Opaque : D32_LCD32_Blend;
+}
+
+SkBlitMask::Proc SkBlitMask::Factory(SkBitmap::Config config,
+ SkMask::Format format, SkColor color) {
+ SkBlitMask::Proc proc = PlatformProcs(config, format, color);
+ if (proc) {
+ return proc;
+ }
+
+ switch (config) {
+ case SkBitmap::kARGB_8888_Config:
+ switch (format) {
+ case SkMask::kA8_Format:
+ return D32_A8_Factory(color);
+ case SkMask::kLCD16_Format:
+ return D32_LCD16_Proc;
+ case SkMask::kLCD32_Format:
+ return D32_LCD32_Factory(color);
+ }
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static const int gMaskFormatToShift[] = {
+ ~0, // BW
+ 0, // A8
+ 0, // 3D
+ 2, // ARGB32
+ 1, // LCD16
+ 2 // LCD32
+};
+
+static int maskFormatToShift(SkMask::Format format) {
+ SkASSERT((unsigned)format < SK_ARRAY_COUNT(gMaskFormatToShift));
+ SkASSERT(SkMask::kBW_Format != format);
+ return gMaskFormatToShift[format];
+}
+
+static const void* getAddr(const SkMask& mask, int x, int y) {
+ SkASSERT(mask.fBounds.contains(x, y));
+ SkASSERT(mask.fImage);
+
+ const char* addr = (const char*)mask.fImage;
+ addr += (y - mask.fBounds.fTop) * mask.fRowBytes;
+ addr += (x - mask.fBounds.fLeft) << maskFormatToShift(mask.fFormat);
+ return addr;
+}
+
+bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask,
+ const SkIRect& clip, SkColor color) {
+ Proc proc = Factory(device.config(), mask.fFormat, color);
+ if (proc) {
+ int x = clip.fLeft;
+ int y = clip.fTop;
+ proc(device.getAddr32(x, y), device.rowBytes(), getAddr(mask, x, y),
+ mask.fRowBytes, color, clip.width(), clip.height());
+ return true;
+ }
+ return false;
+}
+
+