1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18#include "rsdCore.h"
19#include "rsdIntrinsics.h"
20#include "rsdAllocation.h"
21
22#include "rsdIntrinsicInlines.h"
23
24using namespace android;
25using namespace android::renderscript;
26
27struct ConvolveParams {
28    float fp[16];
29    short ip[16];
30    bool use3x3;
31    bool useDot;
32};
33
34static void ColorMatrix_SetVar(const Context *dc, const Script *script, void * intrinsicData,
35                               uint32_t slot, void *data, size_t dataLength) {
36    ConvolveParams *cp = (ConvolveParams *)intrinsicData;
37
38    rsAssert(slot == 0);
39    memcpy (cp->fp, data, dataLength);
40    for(int ct=0; ct < 16; ct++) {
41        cp->ip[ct] = (short)(cp->fp[ct] * 255.f + 0.5f);
42    }
43
44    if ((cp->ip[3] == 0) && (cp->ip[7] == 0) && (cp->ip[11] == 0) &&
45        (cp->ip[12] == 0) && (cp->ip[13] == 0) && (cp->ip[14] == 0) &&
46        (cp->ip[15] == 255)) {
47        cp->use3x3 = true;
48
49        if ((cp->ip[0] == cp->ip[1]) && (cp->ip[0] == cp->ip[2]) &&
50            (cp->ip[4] == cp->ip[5]) && (cp->ip[4] == cp->ip[6]) &&
51            (cp->ip[8] == cp->ip[9]) && (cp->ip[8] == cp->ip[10])) {
52            cp->useDot = true;
53        }
54    }
55}
56
57extern "C" void rsdIntrinsicColorMatrix4x4_K(void *dst, const void *src, const short *coef, uint32_t count);
58extern "C" void rsdIntrinsicColorMatrix3x3_K(void *dst, const void *src, const short *coef, uint32_t count);
59extern "C" void rsdIntrinsicColorMatrixDot_K(void *dst, const void *src, const short *coef, uint32_t count);
60
61static void One(const RsForEachStubParamStruct *p, uchar4 *out,
62                const uchar4 *py, const float* coeff) {
63    float4 i = convert_float4(py[0]);
64
65    float4 sum;
66    sum.x = i.x * coeff[0] +
67            i.y * coeff[4] +
68            i.z * coeff[8] +
69            i.w * coeff[12];
70    sum.y = i.x * coeff[1] +
71            i.y * coeff[5] +
72            i.z * coeff[9] +
73            i.w * coeff[13];
74    sum.z = i.x * coeff[2] +
75            i.y * coeff[6] +
76            i.z * coeff[10] +
77            i.w * coeff[14];
78    sum.w = i.x * coeff[3] +
79            i.y * coeff[7] +
80            i.z * coeff[11] +
81            i.w * coeff[15];
82
83    sum.x = sum.x < 0 ? 0 : (sum.x > 255 ? 255 : sum.x);
84    sum.y = sum.y < 0 ? 0 : (sum.y > 255 ? 255 : sum.y);
85    sum.z = sum.z < 0 ? 0 : (sum.z > 255 ? 255 : sum.z);
86    sum.w = sum.w < 0 ? 0 : (sum.w > 255 ? 255 : sum.w);
87
88    *out = convert_uchar4(sum);
89}
90
91static void ColorMatrix_uchar4(const RsForEachStubParamStruct *p,
92                                    uint32_t xstart, uint32_t xend,
93                                    uint32_t instep, uint32_t outstep) {
94    ConvolveParams *cp = (ConvolveParams *)p->usr;
95    uchar4 *out = (uchar4 *)p->out;
96    uchar4 *in = (uchar4 *)p->in;
97    uint32_t x1 = xstart;
98    uint32_t x2 = xend;
99
100    in += xstart;
101    out += xstart;
102
103    if(x2 > x1) {
104#if defined(ARCH_ARM_HAVE_NEON)
105        int32_t len = (x2 - x1) >> 2;
106        if(len > 0) {
107            if (cp->use3x3) {
108                if (cp->useDot) {
109                    rsdIntrinsicColorMatrixDot_K(out, in, cp->ip, len);
110                } else {
111                    rsdIntrinsicColorMatrix3x3_K(out, in, cp->ip, len);
112                }
113            } else {
114                rsdIntrinsicColorMatrix4x4_K(out, in, cp->ip, len);
115            }
116            x1 += len << 2;
117            out += len << 2;
118            in += len << 2;
119        }
120#endif
121
122        while(x1 != x2) {
123            One(p, out++, in++, cp->fp);
124            x1++;
125        }
126    }
127}
128
129void * rsdIntrinsic_InitColorMatrix(const android::renderscript::Context *dc,
130                                    android::renderscript::Script *script,
131                                    RsdIntriniscFuncs_t *funcs) {
132
133    script->mHal.info.exportedVariableCount = 1;
134    funcs->setVar = ColorMatrix_SetVar;
135    funcs->root = ColorMatrix_uchar4;
136
137    ConvolveParams *cp = (ConvolveParams *)calloc(1, sizeof(ConvolveParams));
138    cp->fp[0] = 1.f;
139    cp->fp[5] = 1.f;
140    cp->fp[10] = 1.f;
141    cp->fp[15] = 1.f;
142    for(int ct=0; ct < 16; ct++) {
143        cp->ip[ct] = (short)(cp->fp[ct] * 255.f + 0.5f);
144    }
145    return cp;
146}
147
148
149