From: mtklein Date: Tue, 1 Sep 2015 18:03:11 +0000 (-0700) Subject: Restore old NEON blit_mask_d32_a8 methods. X-Git-Tag: submit/tizen/20180928.044319~1020 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=12d40c18b9f624f3a6b674f10a11504fd3ea5642;p=platform%2Fupstream%2FlibSkiaSharp.git Restore old NEON blit_mask_d32_a8 methods. As you'll see from the BUG line, we have a strong indication that the new Sk4px methods regress some devices. This restores the old code back as literally as possible while still fitting in SkOpts framework. This is ideally temporary breathing room. We should get an early indication of if those bugs will improve by watching https://perf.skia.org/#4004 BUG=skia:4117,525844,519596,524149 Review URL: https://codereview.chromium.org/1312763009 --- diff --git a/src/opts/SkBlitMask_opts.h b/src/opts/SkBlitMask_opts.h index d66323a8b0..2f4fe6ffb8 100644 --- a/src/opts/SkBlitMask_opts.h +++ b/src/opts/SkBlitMask_opts.h @@ -12,62 +12,182 @@ namespace SK_OPTS_NS { -static void blit_mask_d32_a8_general(SkPMColor* dst, size_t dstRB, - const SkAlpha* mask, size_t maskRB, - SkColor color, int w, int h) { - auto s = Sk4px::DupPMColor(SkPreMultiplyColor(color)); - auto fn = [&](const Sk4px& d, const Sk4px& aa) { - // = (s + d(1-sa))aa + d(1-aa) - // = s*aa + d(1-sa*aa) - auto left = s.approxMulDiv255(aa), - right = d.approxMulDiv255(left.alphas().inv()); - return left + right; // This does not overflow (exhaustively checked). - }; - while (h --> 0) { - Sk4px::MapDstAlpha(w, dst, mask, fn); - dst += dstRB / sizeof(*dst); - mask += maskRB / sizeof(*mask); +#if defined(SK_ARM_HAS_NEON) + // The Sk4px versions below will work fine with NEON, but we have had many indications + // that it doesn't perform as well as this NEON-specific code. TODO(mtklein): why? + #include "SkColor_opts_neon.h" + + template + static void D32_A8_Opaque_Color_neon(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; + uint8x8x4_t vpmc; + + maskRB -= width; + dstRB -= (width << 2); + + if (width >= 8) { + vpmc.val[NEON_A] = vdup_n_u8(SkGetPackedA32(pmc)); + vpmc.val[NEON_R] = vdup_n_u8(SkGetPackedR32(pmc)); + vpmc.val[NEON_G] = vdup_n_u8(SkGetPackedG32(pmc)); + vpmc.val[NEON_B] = vdup_n_u8(SkGetPackedB32(pmc)); + } + do { + int w = width; + while (w >= 8) { + uint8x8_t vmask = vld1_u8(mask); + uint16x8_t vscale, vmask256 = SkAlpha255To256_neon8(vmask); + if (isColor) { + vscale = vsubw_u8(vdupq_n_u16(256), + SkAlphaMul_neon8(vpmc.val[NEON_A], vmask256)); + } else { + vscale = vsubw_u8(vdupq_n_u16(256), vmask); + } + uint8x8x4_t vdev = vld4_u8((uint8_t*)device); + + vdev.val[NEON_A] = SkAlphaMul_neon8(vpmc.val[NEON_A], vmask256) + + SkAlphaMul_neon8(vdev.val[NEON_A], vscale); + vdev.val[NEON_R] = SkAlphaMul_neon8(vpmc.val[NEON_R], vmask256) + + SkAlphaMul_neon8(vdev.val[NEON_R], vscale); + vdev.val[NEON_G] = SkAlphaMul_neon8(vpmc.val[NEON_G], vmask256) + + SkAlphaMul_neon8(vdev.val[NEON_G], vscale); + vdev.val[NEON_B] = SkAlphaMul_neon8(vpmc.val[NEON_B], vmask256) + + SkAlphaMul_neon8(vdev.val[NEON_B], vscale); + + vst4_u8((uint8_t*)device, vdev); + + mask += 8; + device += 8; + w -= 8; + } + + while (w--) { + unsigned aa = *mask++; + if (isColor) { + *device = SkBlendARGB32(pmc, *device, aa); + } else { + *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa)) + + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa)); + } + device += 1; + }; + + device = (uint32_t*)((char*)device + dstRB); + mask += maskRB; + + } while (--height != 0); } -} -// As above, but made slightly simpler by requiring that color is opaque. -static void blit_mask_d32_a8_opaque(SkPMColor* dst, size_t dstRB, - const SkAlpha* mask, size_t maskRB, - SkColor color, int w, int h) { - SkASSERT(SkColorGetA(color) == 0xFF); - auto s = Sk4px::DupPMColor(SkPreMultiplyColor(color)); - auto fn = [&](const Sk4px& d, const Sk4px& aa) { - // = (s + d(1-sa))aa + d(1-aa) - // = s*aa + d(1-sa*aa) - // ~~~> - // = s*aa + d(1-aa) - return s.approxMulDiv255(aa) + d.approxMulDiv255(aa.inv()); - }; - while (h --> 0) { - Sk4px::MapDstAlpha(w, dst, mask, fn); - dst += dstRB / sizeof(*dst); - mask += maskRB / sizeof(*mask); + static void blit_mask_d32_a8_general(SkPMColor* dst, size_t dstRB, + const SkAlpha* mask, size_t maskRB, + SkColor color, int w, int h) { + D32_A8_Opaque_Color_neon(dst, dstRB, mask, maskRB, color, w, h); } -} -// Same as _opaque, but assumes color == SK_ColorBLACK, a very common and even simpler case. -static void blit_mask_d32_a8_black(SkPMColor* dst, size_t dstRB, - const SkAlpha* mask, size_t maskRB, - int w, int h) { - auto fn = [](const Sk4px& d, const Sk4px& aa) { - // = (s + d(1-sa))aa + d(1-aa) - // = s*aa + d(1-sa*aa) - // ~~~> - // a = 1*aa + d(1-1*aa) = aa + d(1-aa) - // c = 0*aa + d(1-1*aa) = d(1-aa) - return aa.zeroColors() + d.approxMulDiv255(aa.inv()); - }; - while (h --> 0) { - Sk4px::MapDstAlpha(w, dst, mask, fn); - dst += dstRB / sizeof(*dst); - mask += maskRB / sizeof(*mask); + // As above, but made slightly simpler by requiring that color is opaque. + static void blit_mask_d32_a8_opaque(SkPMColor* dst, size_t dstRB, + const SkAlpha* mask, size_t maskRB, + SkColor color, int w, int h) { + D32_A8_Opaque_Color_neon(dst, dstRB, mask, maskRB, color, w, h); } -} + + // Same as _opaque, but assumes color == SK_ColorBLACK, a very common and even simpler case. + static void blit_mask_d32_a8_black(SkPMColor* dst, size_t dstRB, + const SkAlpha* maskPtr, size_t maskRB, + 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; + while (w >= 8) { + uint8x8_t vmask = vld1_u8(mask); + uint16x8_t vscale = vsubw_u8(vdupq_n_u16(256), vmask); + uint8x8x4_t vdevice = vld4_u8((uint8_t*)device); + + vdevice = SkAlphaMulQ_neon8(vdevice, vscale); + vdevice.val[NEON_A] += vmask; + + vst4_u8((uint8_t*)device, vdevice); + + mask += 8; + device += 8; + w -= 8; + } + while (w-- > 0) { + unsigned aa = *mask++; + *device = (aa << SK_A32_SHIFT) + + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa)); + device += 1; + }; + device = (uint32_t*)((char*)device + dstRB); + mask += maskRB; + } while (--height != 0); + } + +#else + static void blit_mask_d32_a8_general(SkPMColor* dst, size_t dstRB, + const SkAlpha* mask, size_t maskRB, + SkColor color, int w, int h) { + auto s = Sk4px::DupPMColor(SkPreMultiplyColor(color)); + auto fn = [&](const Sk4px& d, const Sk4px& aa) { + // = (s + d(1-sa))aa + d(1-aa) + // = s*aa + d(1-sa*aa) + auto left = s.approxMulDiv255(aa), + right = d.approxMulDiv255(left.alphas().inv()); + return left + right; // This does not overflow (exhaustively checked). + }; + while (h --> 0) { + Sk4px::MapDstAlpha(w, dst, mask, fn); + dst += dstRB / sizeof(*dst); + mask += maskRB / sizeof(*mask); + } + } + + // As above, but made slightly simpler by requiring that color is opaque. + static void blit_mask_d32_a8_opaque(SkPMColor* dst, size_t dstRB, + const SkAlpha* mask, size_t maskRB, + SkColor color, int w, int h) { + SkASSERT(SkColorGetA(color) == 0xFF); + auto s = Sk4px::DupPMColor(SkPreMultiplyColor(color)); + auto fn = [&](const Sk4px& d, const Sk4px& aa) { + // = (s + d(1-sa))aa + d(1-aa) + // = s*aa + d(1-sa*aa) + // ~~~> + // = s*aa + d(1-aa) + return s.approxMulDiv255(aa) + d.approxMulDiv255(aa.inv()); + }; + while (h --> 0) { + Sk4px::MapDstAlpha(w, dst, mask, fn); + dst += dstRB / sizeof(*dst); + mask += maskRB / sizeof(*mask); + } + } + + // Same as _opaque, but assumes color == SK_ColorBLACK, a very common and even simpler case. + static void blit_mask_d32_a8_black(SkPMColor* dst, size_t dstRB, + const SkAlpha* mask, size_t maskRB, + int w, int h) { + auto fn = [](const Sk4px& d, const Sk4px& aa) { + // = (s + d(1-sa))aa + d(1-aa) + // = s*aa + d(1-sa*aa) + // ~~~> + // a = 1*aa + d(1-1*aa) = aa + d(1-aa) + // c = 0*aa + d(1-1*aa) = d(1-aa) + return aa.zeroColors() + d.approxMulDiv255(aa.inv()); + }; + while (h --> 0) { + Sk4px::MapDstAlpha(w, dst, mask, fn); + dst += dstRB / sizeof(*dst); + mask += maskRB / sizeof(*mask); + } + } +#endif static void blit_mask_d32_a8(SkPMColor* dst, size_t dstRB, const SkAlpha* mask, size_t maskRB,