blob: db5d5317e3d6f5bbb2b8da170b6d96cdbe2fa3e6 [file] [log] [blame]
#include "SkXfermode.h"
#include "SkXfermode_proccoeff.h"
#include "SkColorPriv.h"
#include "SkUtilsArm.h"
#if !SK_ARM_NEON_IS_NONE
#include <arm_neon.h>
////////////////////////////////////////////////////////////////////////////////
typedef uint8x8x4_t (*SkXfermodeProcSIMD)(uint8x8x4_t src, uint8x8x4_t dst);
class SkNEONProcCoeffXfermode : public SkProcCoeffXfermode {
public:
SkNEONProcCoeffXfermode(const ProcCoeff& rec, SkXfermode::Mode mode,
SkXfermodeProcSIMD procSIMD)
: INHERITED(rec, mode), fProcSIMD(procSIMD) {}
virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
const SkAlpha aa[]) const SK_OVERRIDE;
SK_DEVELOPER_TO_STRING()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkNEONProcCoeffXfermode)
private:
SkNEONProcCoeffXfermode(SkFlattenableReadBuffer& buffer)
: INHERITED(buffer) {
fProcSIMD = NULL;
if (!buffer.isCrossProcess()) {
fProcSIMD = (SkXfermodeProcSIMD)buffer.readFunctionPtr();
}
}
virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
SkXfermodeProcSIMD fProcSIMD;
typedef SkProcCoeffXfermode INHERITED;
};
void SkNEONProcCoeffXfermode::xfer32(SkPMColor dst[], const SkPMColor src[],
int count, const SkAlpha aa[]) const {
SkASSERT(dst && src && count >= 0);
SkXfermodeProc proc = this->getProc();
SkXfermodeProcSIMD procSIMD = fProcSIMD;
if (NULL == aa) {
// Unrolled NEON code
while (count >= 8) {
uint8x8x4_t vsrc, vdst, vres;
asm volatile (
"vld4.u8 %h[vsrc], [%[src]]! \t\n"
"vld4.u8 %h[vdst], [%[dst]] \t\n"
: [vsrc] "=w" (vsrc), [vdst] "=w" (vdst)
: [src] "r" (src), [dst] "r" (dst)
:
);
vres = procSIMD(vsrc, vdst);
vst4_u8((uint8_t*)dst, vres);
count -= 8;
dst += 8;
}
// Leftovers
for (int i = 0; i < count; i++) {
dst[i] = proc(src[i], dst[i]);
}
} else {
for (int i = count - 1; i >= 0; --i) {
unsigned a = aa[i];
if (0 != a) {
SkPMColor dstC = dst[i];
SkPMColor C = proc(src[i], dstC);
if (a != 0xFF) {
C = SkFourByteInterp(C, dstC, a);
}
dst[i] = C;
}
}
}
}
#ifdef SK_DEVELOPER
void SkNEONProcCoeffXfermode::toString(SkString* str) const {
this->INHERITED::toString(str);
}
#endif
void SkNEONProcCoeffXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
if (!buffer.isCrossProcess()) {
buffer.writeFunctionPtr((void*)fProcSIMD);
}
}
////////////////////////////////////////////////////////////////////////////////
SkXfermodeProcSIMD gNEONXfermodeProcs[] = {
[SkXfermode::kClear_Mode] = NULL,
[SkXfermode::kSrc_Mode] = NULL,
[SkXfermode::kDst_Mode] = NULL,
[SkXfermode::kSrcOver_Mode] = NULL,
[SkXfermode::kDstOver_Mode] = NULL,
[SkXfermode::kSrcIn_Mode] = NULL,
[SkXfermode::kDstIn_Mode] = NULL,
[SkXfermode::kSrcOut_Mode] = NULL,
[SkXfermode::kDstOut_Mode] = NULL,
[SkXfermode::kSrcATop_Mode] = NULL,
[SkXfermode::kDstATop_Mode] = NULL,
[SkXfermode::kXor_Mode] = NULL,
[SkXfermode::kPlus_Mode] = NULL,
[SkXfermode::kModulate_Mode]= NULL,
[SkXfermode::kScreen_Mode] = NULL,
[SkXfermode::kOverlay_Mode] = NULL,
[SkXfermode::kDarken_Mode] = NULL,
[SkXfermode::kLighten_Mode] = NULL,
[SkXfermode::kColorDodge_Mode] = NULL,
[SkXfermode::kColorBurn_Mode] = NULL,
[SkXfermode::kHardLight_Mode] = NULL,
[SkXfermode::kSoftLight_Mode] = NULL,
[SkXfermode::kDifference_Mode] = NULL,
[SkXfermode::kExclusion_Mode] = NULL,
[SkXfermode::kMultiply_Mode] = NULL,
[SkXfermode::kHue_Mode] = NULL,
[SkXfermode::kSaturation_Mode] = NULL,
[SkXfermode::kColor_Mode] = NULL,
[SkXfermode::kLuminosity_Mode] = NULL,
};
SK_COMPILE_ASSERT(
SK_ARRAY_COUNT(gNEONXfermodeProcs) == SkXfermode::kLastMode + 1,
mode_count_arm
);
#endif
SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
SkXfermode::Mode mode) {
#if !SK_ARM_NEON_IS_NONE
#if SK_ARM_NEON_IS_DYNAMIC
if ((sk_cpu_arm_has_neon()) && (gNEONXfermodeProcs[mode] != NULL)) {
#elif SK_ARM_NEON_IS_ALWAYS
if (gNEONXfermodeProcs[mode] != NULL) {
#endif
return SkNEW_ARGS(SkNEONProcCoeffXfermode,
(rec, mode, gNEONXfermodeProcs[mode]));
}
#endif
return NULL;
}