Implementations of various blend intrinsics.

Bug: 7190126

Change-Id: I84cd8b861b63489313b9c2827f43aa7391a62607
diff --git a/driver/rsdIntrinsicBlend.cpp b/driver/rsdIntrinsicBlend.cpp
index a5647e4..b427e55 100644
--- a/driver/rsdIntrinsicBlend.cpp
+++ b/driver/rsdIntrinsicBlend.cpp
@@ -111,6 +111,8 @@
                                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;
@@ -127,21 +129,225 @@
         break;
     case BLEND_SRC:
         for (;x1 < x2; x1++, out++, in++) {
-            uchar4 t = *in;
-            t.rgb = (t.rgb * t.a) >> 8;
-            *out = t;
+          *out = *in;
         }
         break;
+    //BLEND_DST is a NOP
     case BLEND_DST:
+        break;
+    case BLEND_SRC_OVER:
         for (;x1 < x2; x1++, out++, in++) {
-            uchar4 t = *in;
-            t.rgb = (t.rgb * t.a) >> 8;
-            *out = t;
+            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:
+        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:
+        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:
+        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:
+        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:
+        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:
+        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) >> (short3)8) +
+              ((out_s.rgb * ((short3)255 - (short3)in_s.a)) >> (short3)8);
+            *out = convert_uchar4(out_s);
+        }
+        break;
+    case BLEND_DST_ATOP:
+        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) >> (short3)8) +
+              ((in_s.rgb * ((short3)255 - (short3)out_s.a)) >> (short3)8);
+            *out = convert_uchar4(out_s);
+        }
+        break;
+    case BLEND_XOR:
+        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:
+        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:
+        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:
+        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);
 
     }
 
diff --git a/driver/rsdIntrinsicInlines.h b/driver/rsdIntrinsicInlines.h
index 9e74c33..ab11b4f 100644
--- a/driver/rsdIntrinsicInlines.h
+++ b/driver/rsdIntrinsicInlines.h
@@ -67,6 +67,11 @@
     return f4;
 }
 
+static inline uchar4 convert_uchar4(short4 i) {
+    uchar4 f4 = {(uchar)i.x, (uchar)i.y, (uchar)i.z, (uchar)i.w};
+    return f4;
+}
+
 static inline uchar4 convert_uchar4(int4 i) {
     uchar4 f4 = {(uchar)i.x, (uchar)i.y, (uchar)i.z, (uchar)i.w};
     return f4;
diff --git a/driver/rsdIntrinsics.cpp b/driver/rsdIntrinsics.cpp
index 84d527f..348bcf1 100644
--- a/driver/rsdIntrinsics.cpp
+++ b/driver/rsdIntrinsics.cpp
@@ -22,13 +22,13 @@
 using namespace android;
 using namespace android::renderscript;
 
-
 void * rsdIntrinsic_InitBlur(const Context *, Script *, RsdIntriniscFuncs_t *);
 void * rsdIntrinsic_InitConvolve3x3(const Context *, Script *, RsdIntriniscFuncs_t *);
 void * rsdIntrinsic_InitConvolve5x5(const Context *, Script *, RsdIntriniscFuncs_t *);
 void * rsdIntrinsic_InitColorMatrix(const Context *, Script *, RsdIntriniscFuncs_t *);
 void * rsdIntrinsic_InitLUT(const Context *, Script *, RsdIntriniscFuncs_t *);
 void * rsdIntrinsic_InitYuvToRGB(const Context *, Script *, RsdIntriniscFuncs_t *);
+void * rsdIntrinsic_InitBlend(const Context *, Script *, RsdIntriniscFuncs_t *);
 
 static void Bind(const Context *, const Script *, void *, uint32_t, Allocation *) {
     rsAssert(!"Intrinsic_Bind unexpectedly called");
@@ -62,8 +62,10 @@
         return rsdIntrinsic_InitLUT(dc, script, funcs);
     case RS_SCRIPT_INTRINSIC_ID_BLUR:
         return rsdIntrinsic_InitBlur(dc, script, funcs);
-    case RS_SCRIPT_INTRINSIC_YUV_TO_RGB:
+    case RS_SCRIPT_INTRINSIC_ID_YUV_TO_RGB:
         return rsdIntrinsic_InitYuvToRGB(dc, script, funcs);
+    case RS_SCRIPT_INTRINSIC_ID_BLEND:
+        return rsdIntrinsic_InitBlend(dc, script, funcs);
 
     default:
         return NULL;
diff --git a/driver/rsdIntrinsics.h b/driver/rsdIntrinsics.h
index a494d76..221a81a 100644
--- a/driver/rsdIntrinsics.h
+++ b/driver/rsdIntrinsics.h
@@ -24,7 +24,5 @@
                          android::renderscript::Script *script,
                          RsScriptIntrinsicID id, RsdIntriniscFuncs_t *funcs);
 
-
-
 #endif // RSD_INTRINSICS_H
 
diff --git a/rsDefines.h b/rsDefines.h
index 3e46d0c..cccff86 100644
--- a/rsDefines.h
+++ b/rsDefines.h
@@ -348,7 +348,8 @@
     RS_SCRIPT_INTRINSIC_ID_LUT = 3,
     RS_SCRIPT_INTRINSIC_ID_CONVOLVE_5x5 = 4,
     RS_SCRIPT_INTRINSIC_ID_BLUR = 5,
-    RS_SCRIPT_INTRINSIC_YUV_TO_RGB = 6
+    RS_SCRIPT_INTRINSIC_ID_YUV_TO_RGB = 6,
+    RS_SCRIPT_INTRINSIC_ID_BLEND = 7
 };
 
 typedef struct {