1d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein/* 2d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein * Copyright 2015 Google Inc. 3d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein * 4d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein * Use of this source code is governed by a BSD-style license that can be 5d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein * found in the LICENSE file. 6d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein */ 7d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 8d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein#ifndef Sk4px_DEFINED 9d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein#define Sk4px_DEFINED 10d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 11d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein#include "SkNx.h" 12d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein#include "SkColor.h" 13d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 14d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein// 1, 2 or 4 SkPMColors, generally vectorized. 15d2ffd36eb62e99abe2920369d1e040954cc2044fmtkleinclass Sk4px : public Sk16b { 16d2ffd36eb62e99abe2920369d1e040954cc2044fmtkleinpublic: 172d8d33e9e825f9919875be64a71b746189b385bemtklein Sk4px(SkAlpha a) : INHERITED(a) {} // Duplicate 16x: a -> aaaa aaaa aaaa aaaa 182d8d33e9e825f9919875be64a71b746189b385bemtklein Sk4px(SkPMColor); // Duplicate 4x: argb -> argb argb argb argb 198a90edc2a58a4f8a4b4da73eb08e943be09538c0mtklein Sk4px(const Sk16b& v) : INHERITED(v) {} 208a90edc2a58a4f8a4b4da73eb08e943be09538c0mtklein 212d8d33e9e825f9919875be64a71b746189b385bemtklein Sk4px alphas() const; // ARGB argb XYZW xyzw -> AAAA aaaa XXXX xxxx 222d8d33e9e825f9919875be64a71b746189b385bemtklein 230135a41e095a433414e21e37b277dab7dcbec373mtklein // Mask away color or alpha lanes. 240135a41e095a433414e21e37b277dab7dcbec373mtklein Sk4px zeroColors() const; // ARGB argb XYZW xyzw -> A000 a000 X000 x000 250135a41e095a433414e21e37b277dab7dcbec373mtklein Sk4px zeroAlphas() const; // ARGB argb XYZW xyzw -> 0RGB 0rgb 0YZW 0yzw 260135a41e095a433414e21e37b277dab7dcbec373mtklein 272d8d33e9e825f9919875be64a71b746189b385bemtklein Sk4px inv() const { return Sk16b(255) - *this; } 28d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 29d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein // When loading or storing fewer than 4 SkPMColors, we use the low lanes. 302d8d33e9e825f9919875be64a71b746189b385bemtklein static Sk4px Load4(const SkPMColor[4]); // PMColor[4] -> ARGB argb XYZW xyzw 312d8d33e9e825f9919875be64a71b746189b385bemtklein static Sk4px Load2(const SkPMColor[2]); // PMColor[2] -> ARGB argb ???? ???? 322d8d33e9e825f9919875be64a71b746189b385bemtklein static Sk4px Load1(const SkPMColor[1]); // PMColor[1] -> ARGB ???? ???? ???? 33d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 348a90edc2a58a4f8a4b4da73eb08e943be09538c0mtklein // Ditto for Alphas... Load2Alphas fills the low two lanes of Sk4px. 358a90edc2a58a4f8a4b4da73eb08e943be09538c0mtklein static Sk4px Load4Alphas(const SkAlpha[4]); // AaXx -> AAAA aaaa XXXX xxxx 362d8d33e9e825f9919875be64a71b746189b385bemtklein static Sk4px Load2Alphas(const SkAlpha[2]); // Aa -> AAAA aaaa ???? ???? 378a90edc2a58a4f8a4b4da73eb08e943be09538c0mtklein 38d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein void store4(SkPMColor[4]) const; 39d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein void store2(SkPMColor[2]) const; 40d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein void store1(SkPMColor[1]) const; 41d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 42d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein // 1, 2, or 4 SkPMColors with 16-bit components. 43d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein // This is most useful as the result of a multiply, e.g. from mulWiden(). 44d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein class Wide : public Sk16h { 45d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein public: 46d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein Wide(const Sk16h& v) : Sk16h(v) {} 47d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 48d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein // Pack the top byte of each component back down into 4 SkPMColors. 49d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein Sk4px addNarrowHi(const Sk16h&) const; 506cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein 516cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein Sk4px div255TruncNarrow() const { return this->addNarrowHi(*this >> 8); } 526cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein Sk4px div255RoundNarrow() const { 536cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein return Sk4px::Wide(*this + Sk16h(128)).div255TruncNarrow(); 546cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 556cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein 56d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein private: 57d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein typedef Sk16h INHERITED; 58d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein }; 59d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 60d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein Wide widenLo() const; // ARGB -> 0A 0R 0G 0B 61d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein Wide widenHi() const; // ARGB -> A0 R0 G0 B0 62d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein Wide mulWiden(const Sk16b&) const; // 8-bit x 8-bit -> 16-bit components. 630135a41e095a433414e21e37b277dab7dcbec373mtklein Wide mul255Widen() const { 640135a41e095a433414e21e37b277dab7dcbec373mtklein // TODO: x*255 = x*256-x, so something like this->widenHi() - this->widenLo()? 650135a41e095a433414e21e37b277dab7dcbec373mtklein return this->mulWiden(Sk16b(255)); 660135a41e095a433414e21e37b277dab7dcbec373mtklein } 67d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 68d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein // A generic driver that maps fn over a src array into a dst array. 69d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein // fn should take an Sk4px (4 src pixels) and return an Sk4px (4 dst pixels). 70d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein template <typename Fn> 71d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein static void MapSrc(int count, SkPMColor* dst, const SkPMColor* src, Fn fn) { 72d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein // This looks a bit odd, but it helps loop-invariant hoisting across different calls to fn. 73d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein // Basically, we need to make sure we keep things inside a single loop. 74d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein while (count > 0) { 75d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein if (count >= 8) { 76d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein Sk4px dst0 = fn(Load4(src+0)), 77d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein dst4 = fn(Load4(src+4)); 78d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein dst0.store4(dst+0); 79d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein dst4.store4(dst+4); 80d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein dst += 8; src += 8; count -= 8; 81d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein continue; // Keep our stride at 8 pixels as long as possible. 82d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein } 83d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein SkASSERT(count <= 7); 84d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein if (count >= 4) { 85d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein fn(Load4(src)).store4(dst); 86d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein dst += 4; src += 4; count -= 4; 87d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein } 88d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein if (count >= 2) { 89d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein fn(Load2(src)).store2(dst); 90d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein dst += 2; src += 2; count -= 2; 91d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein } 92d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein if (count >= 1) { 93d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein fn(Load1(src)).store1(dst); 94d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein } 95d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein break; 96d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein } 97d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein } 98d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 996cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein // As above, but with dst4' = fn(dst4, src4). 1006cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein template <typename Fn> 1016cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein static void MapDstSrc(int count, SkPMColor* dst, const SkPMColor* src, Fn fn) { 1026cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein while (count > 0) { 1036cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein if (count >= 8) { 1046cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein Sk4px dst0 = fn(Load4(dst+0), Load4(src+0)), 1056cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst4 = fn(Load4(dst+4), Load4(src+4)); 1066cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst0.store4(dst+0); 1076cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst4.store4(dst+4); 1086cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst += 8; src += 8; count -= 8; 1096cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein continue; // Keep our stride at 8 pixels as long as possible. 1106cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1116cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein SkASSERT(count <= 7); 1126cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein if (count >= 4) { 1136cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein fn(Load4(dst), Load4(src)).store4(dst); 1146cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst += 4; src += 4; count -= 4; 1156cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1166cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein if (count >= 2) { 1176cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein fn(Load2(dst), Load2(src)).store2(dst); 1186cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst += 2; src += 2; count -= 2; 1196cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1206cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein if (count >= 1) { 1216cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein fn(Load1(dst), Load1(src)).store1(dst); 1226cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1236cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein break; 1246cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1256cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1266cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein 1276cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein // As above, but with dst4' = fn(dst4, src4, alpha4). 1286cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein template <typename Fn> 1296cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein static void MapDstSrcAlpha( 1306cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein int count, SkPMColor* dst, const SkPMColor* src, const SkAlpha* a, Fn fn) { 1316cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein while (count > 0) { 1326cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein if (count >= 8) { 1338a90edc2a58a4f8a4b4da73eb08e943be09538c0mtklein Sk4px alpha0 = Load4Alphas(a+0), 1348a90edc2a58a4f8a4b4da73eb08e943be09538c0mtklein alpha4 = Load4Alphas(a+4); 1356cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein Sk4px dst0 = fn(Load4(dst+0), Load4(src+0), alpha0), 1366cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst4 = fn(Load4(dst+4), Load4(src+4), alpha4); 1376cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst0.store4(dst+0); 1386cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst4.store4(dst+4); 1396cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst += 8; src += 8; a += 8; count -= 8; 1406cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein continue; // Keep our stride at 8 pixels as long as possible. 1416cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1426cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein SkASSERT(count <= 7); 1436cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein if (count >= 4) { 1448a90edc2a58a4f8a4b4da73eb08e943be09538c0mtklein Sk4px alpha = Load4Alphas(a); 1456cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein fn(Load4(dst), Load4(src), alpha).store4(dst); 1466cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst += 4; src += 4; a += 4; count -= 4; 1476cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1486cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein if (count >= 2) { 1498a90edc2a58a4f8a4b4da73eb08e943be09538c0mtklein Sk4px alpha = Load2Alphas(a); 1506cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein fn(Load2(dst), Load2(src), alpha).store2(dst); 1516cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein dst += 2; src += 2; a += 2; count -= 2; 1526cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1536cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein if (count >= 1) { 1548a90edc2a58a4f8a4b4da73eb08e943be09538c0mtklein Sk4px alpha(*a); 1556cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein fn(Load1(dst), Load1(src), alpha).store1(dst); 1566cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1576cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein break; 1586cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1596cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein } 1606cbf18c70bf99f58b2bb1c49cdf8d41be561fee4mtklein 161d2ffd36eb62e99abe2920369d1e040954cc2044fmtkleinprivate: 162d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein typedef Sk16b INHERITED; 163d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein}; 164d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 165d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein#ifdef SKNX_NO_SIMD 166d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein #include "../opts/Sk4px_none.h" 167d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein#else 168d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 169d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein #include "../opts/Sk4px_SSE2.h" 170d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein #elif defined(SK_ARM_HAS_NEON) 171d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein #include "../opts/Sk4px_NEON.h" 172d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein #else 173d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein #include "../opts/Sk4px_none.h" 174d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein #endif 175d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein#endif 176d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein 177d2ffd36eb62e99abe2920369d1e040954cc2044fmtklein#endif//Sk4px_DEFINED 178