/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "rsdCore.h"
#include "rsdIntrinsics.h"
#include "rsdAllocation.h"
#include "rsdIntrinsicInlines.h"
using namespace android;
using namespace android::renderscript;
struct ConvolveParams {
float f[4];
};
enum {
BLEND_CLEAR = 0,
BLEND_SRC = 1,
BLEND_DST = 2,
BLEND_SRC_OVER = 3,
BLEND_DST_OVER = 4,
BLEND_SRC_IN = 5,
BLEND_DST_IN = 6,
BLEND_SRC_OUT = 7,
BLEND_DST_OUT = 8,
BLEND_SRC_ATOP = 9,
BLEND_DST_ATOP = 10,
BLEND_XOR = 11,
BLEND_NORMAL = 12,
BLEND_AVERAGE = 13,
BLEND_MULTIPLY = 14,
BLEND_SCREEN = 15,
BLEND_DARKEN = 16,
BLEND_LIGHTEN = 17,
BLEND_OVERLAY = 18,
BLEND_HARDLIGHT = 19,
BLEND_SOFTLIGHT = 20,
BLEND_DIFFERENCE = 21,
BLEND_NEGATION = 22,
BLEND_EXCLUSION = 23,
BLEND_COLOR_DODGE = 24,
BLEND_INVERSE_COLOR_DODGE = 25,
BLEND_SOFT_DODGE = 26,
BLEND_COLOR_BURN = 27,
BLEND_INVERSE_COLOR_BURN = 28,
BLEND_SOFT_BURN = 29,
BLEND_REFLECT = 30,
BLEND_GLOW = 31,
BLEND_FREEZE = 32,
BLEND_HEAT = 33,
BLEND_ADD = 34,
BLEND_SUBTRACT = 35,
BLEND_STAMP = 36,
BLEND_RED = 37,
BLEND_GREEN = 38,
BLEND_BLUE = 39,
BLEND_HUE = 40,
BLEND_SATURATION = 41,
BLEND_COLOR = 42,
BLEND_LUMINOSITY = 43
};
extern "C" void rsdIntrinsicBlendSrcOver_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendDstOver_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendSrcIn_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendDstIn_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendSrcOut_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendDstOut_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendSrcAtop_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendDstAtop_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendXor_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendMultiply_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendAdd_K(void *dst, const void *src, uint32_t count8);
extern "C" void rsdIntrinsicBlendSub_K(void *dst, const void *src, uint32_t count8);
//#undef ARCH_ARM_HAVE_NEON
static void ColorMatrix_uchar4(const RsForEachStubParamStruct *p,
uint32_t xstart, uint32_t xend,
uint32_t instep, uint32_t outstep) {
ConvolveParams *cp = (ConvolveParams *)p->usr;
// instep/outstep can be ignored--sizeof(uchar4) known at compile time
uchar4 *out = (uchar4 *)p->out;
uchar4 *in = (uchar4 *)p->in;
uint32_t x1 = xstart;
uint32_t x2 = xend;
switch (p->slot) {
case BLEND_CLEAR:
for (;x1 < x2; x1++, out++) {
*out = 0;
}
break;
case BLEND_SRC:
for (;x1 < x2; x1++, out++, in++) {
*out = *in;
}
break;
//BLEND_DST is a NOP
case BLEND_DST:
break;
case BLEND_SRC_OVER:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendSrcOver_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
short4 in_s = convert_short4(*in);
short4 out_s = convert_short4(*out);
in_s = in_s + ((out_s * (short4)(255 - in_s.a)) >> (short4)8);
*out = convert_uchar4(in_s);
}
break;
case BLEND_DST_OVER:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendDstOver_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
short4 in_s = convert_short4(*in);
short4 out_s = convert_short4(*out);
in_s = out_s + ((in_s * (short4)(255 - out_s.a)) >> (short4)8);
*out = convert_uchar4(in_s);
}
break;
case BLEND_SRC_IN:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendSrcIn_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
short4 in_s = convert_short4(*in);
in_s = (in_s * out->a) >> (short4)8;
*out = convert_uchar4(in_s);
}
break;
case BLEND_DST_IN:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendDstIn_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
short4 out_s = convert_short4(*out);
out_s = (out_s * in->a) >> (short4)8;
*out = convert_uchar4(out_s);
}
break;
case BLEND_SRC_OUT:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendSrcOut_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
short4 in_s = convert_short4(*in);
in_s = (in_s * (short4)(255 - out->a)) >> (short4)8;
*out = convert_uchar4(in_s);
}
break;
case BLEND_DST_OUT:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendDstOut_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
short4 out_s = convert_short4(*out);
out_s = (out_s * (short4)(255 - in->a)) >> (short4)8;
*out = convert_uchar4(out_s);
}
break;
case BLEND_SRC_ATOP:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendSrcAtop_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
short4 in_s = convert_short4(*in);
short4 out_s = convert_short4(*out);
out_s.rgb = ((in_s.rgb * out_s.a) +
(out_s.rgb * ((short3)255 - (short3)in_s.a))) >> (short3)8;
*out = convert_uchar4(out_s);
}
break;
case BLEND_DST_ATOP:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendDstAtop_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
short4 in_s = convert_short4(*in);
short4 out_s = convert_short4(*out);
out_s.rgb = ((out_s.rgb * in_s.a) +
(in_s.rgb * ((short3)255 - (short3)out_s.a))) >> (short3)8;
*out = convert_uchar4(out_s);
}
break;
case BLEND_XOR:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendXor_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
*out = *in ^ *out;
}
break;
case BLEND_NORMAL:
ALOGE("Called unimplemented blend intrinsic BLEND_NORMAL");
rsAssert(false);
break;
case BLEND_AVERAGE:
ALOGE("Called unimplemented blend intrinsic BLEND_AVERAGE");
rsAssert(false);
break;
case BLEND_MULTIPLY:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendMultiply_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
*out = convert_uchar4((convert_short4(*in) * convert_short4(*out))
>> (short4)8);
}
break;
case BLEND_SCREEN:
ALOGE("Called unimplemented blend intrinsic BLEND_SCREEN");
rsAssert(false);
break;
case BLEND_DARKEN:
ALOGE("Called unimplemented blend intrinsic BLEND_DARKEN");
rsAssert(false);
break;
case BLEND_LIGHTEN:
ALOGE("Called unimplemented blend intrinsic BLEND_LIGHTEN");
rsAssert(false);
break;
case BLEND_OVERLAY:
ALOGE("Called unimplemented blend intrinsic BLEND_OVERLAY");
rsAssert(false);
break;
case BLEND_HARDLIGHT:
ALOGE("Called unimplemented blend intrinsic BLEND_HARDLIGHT");
rsAssert(false);
break;
case BLEND_SOFTLIGHT:
ALOGE("Called unimplemented blend intrinsic BLEND_SOFTLIGHT");
rsAssert(false);
break;
case BLEND_DIFFERENCE:
ALOGE("Called unimplemented blend intrinsic BLEND_DIFFERENCE");
rsAssert(false);
break;
case BLEND_NEGATION:
ALOGE("Called unimplemented blend intrinsic BLEND_NEGATION");
rsAssert(false);
break;
case BLEND_EXCLUSION:
ALOGE("Called unimplemented blend intrinsic BLEND_EXCLUSION");
rsAssert(false);
break;
case BLEND_COLOR_DODGE:
ALOGE("Called unimplemented blend intrinsic BLEND_COLOR_DODGE");
rsAssert(false);
break;
case BLEND_INVERSE_COLOR_DODGE:
ALOGE("Called unimplemented blend intrinsic BLEND_INVERSE_COLOR_DODGE");
rsAssert(false);
break;
case BLEND_SOFT_DODGE:
ALOGE("Called unimplemented blend intrinsic BLEND_SOFT_DODGE");
rsAssert(false);
break;
case BLEND_COLOR_BURN:
ALOGE("Called unimplemented blend intrinsic BLEND_COLOR_BURN");
rsAssert(false);
break;
case BLEND_INVERSE_COLOR_BURN:
ALOGE("Called unimplemented blend intrinsic BLEND_INVERSE_COLOR_BURN");
rsAssert(false);
break;
case BLEND_SOFT_BURN:
ALOGE("Called unimplemented blend intrinsic BLEND_SOFT_BURN");
rsAssert(false);
break;
case BLEND_REFLECT:
ALOGE("Called unimplemented blend intrinsic BLEND_REFLECT");
rsAssert(false);
break;
case BLEND_GLOW:
ALOGE("Called unimplemented blend intrinsic BLEND_GLOW");
rsAssert(false);
break;
case BLEND_FREEZE:
ALOGE("Called unimplemented blend intrinsic BLEND_FREEZE");
rsAssert(false);
break;
case BLEND_HEAT:
ALOGE("Called unimplemented blend intrinsic BLEND_HEAT");
rsAssert(false);
break;
case BLEND_ADD:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendAdd_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
uint32_t iR = in->r, iG = in->g, iB = in->b, iA = in->a,
oR = out->r, oG = out->g, oB = out->b, oA = out->a;
out->r = (oR + iR) > 255 ? 255 : oR + iR;
out->g = (oG + iG) > 255 ? 255 : oG + iG;
out->b = (oB + iB) > 255 ? 255 : oB + iB;
out->a = (oA + iA) > 255 ? 255 : oA + iA;
}
break;
case BLEND_SUBTRACT:
#if defined(ARCH_ARM_HAVE_NEON)
if((x1 + 8) < x2) {
uint32_t len = (x2 - x1) >> 3;
rsdIntrinsicBlendSub_K(out, in, len);
x1 += len << 3;
out += len << 3;
in += len << 3;
}
#endif
for (;x1 < x2; x1++, out++, in++) {
int32_t iR = in->r, iG = in->g, iB = in->b, iA = in->a,
oR = out->r, oG = out->g, oB = out->b, oA = out->a;
out->r = (oR - iR) < 0 ? 0 : oR - iR;
out->g = (oG - iG) < 0 ? 0 : oG - iG;
out->b = (oB - iB) < 0 ? 0 : oB - iB;
out->a = (oA - iA) < 0 ? 0 : oA - iA;
}
break;
case BLEND_STAMP:
ALOGE("Called unimplemented blend intrinsic BLEND_STAMP");
rsAssert(false);
break;
case BLEND_RED:
ALOGE("Called unimplemented blend intrinsic BLEND_RED");
rsAssert(false);
break;
case BLEND_GREEN:
ALOGE("Called unimplemented blend intrinsic BLEND_GREEN");
rsAssert(false);
break;
case BLEND_BLUE:
ALOGE("Called unimplemented blend intrinsic BLEND_BLUE");
rsAssert(false);
break;
case BLEND_HUE:
ALOGE("Called unimplemented blend intrinsic BLEND_HUE");
rsAssert(false);
break;
case BLEND_SATURATION:
ALOGE("Called unimplemented blend intrinsic BLEND_SATURATION");
rsAssert(false);
break;
case BLEND_COLOR:
ALOGE("Called unimplemented blend intrinsic BLEND_COLOR");
rsAssert(false);
break;
case BLEND_LUMINOSITY:
ALOGE("Called unimplemented blend intrinsic BLEND_LUMINOSITY");
rsAssert(false);
break;
default:
ALOGE("Called unimplemented value %d", p->slot);
rsAssert(false);
}
}
void * rsdIntrinsic_InitBlend(const android::renderscript::Context *dc,
android::renderscript::Script *script,
RsdIntriniscFuncs_t *funcs) {
script->mHal.info.exportedVariableCount = 0;
funcs->root = ColorMatrix_uchar4;
ConvolveParams *cp = (ConvolveParams *)calloc(1, sizeof(ConvolveParams));
return cp;
}