1/*
2 * Copyright (C) 2008-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#include <malloc.h>
18
19#include "RenderScript.h"
20#include "rsCppInternal.h"
21
22using android::RSC::ScriptIntrinsic;
23using android::RSC::ScriptIntrinsic3DLUT;
24using android::RSC::ScriptIntrinsicBlend;
25using android::RSC::ScriptIntrinsicBlur;
26using android::RSC::ScriptIntrinsicColorMatrix;
27using android::RSC::ScriptIntrinsicConvolve3x3;
28using android::RSC::ScriptIntrinsicConvolve5x5;
29using android::RSC::ScriptIntrinsicHistogram;
30using android::RSC::ScriptIntrinsicLUT;
31using android::RSC::ScriptIntrinsicResize;
32using android::RSC::ScriptIntrinsicYuvToRGB;
33using android::RSC::sp;
34
35ScriptIntrinsic::ScriptIntrinsic(sp<RS> rs, int id, sp<const Element> e)
36    : Script(nullptr, rs) {
37    mID = createDispatch(rs, RS::dispatch->ScriptIntrinsicCreate(rs->getContext(), id,
38                         e != nullptr ? e->getID() : 0));
39    mElement = e;
40}
41
42ScriptIntrinsic::~ScriptIntrinsic() {
43
44}
45
46sp<ScriptIntrinsic3DLUT> ScriptIntrinsic3DLUT::create(const sp<RS>& rs, const sp<const Element>& e) {
47    if (e->isCompatible(Element::U8_4(rs)) == false) {
48        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Element not supported for intrinsic");
49        return nullptr;
50    }
51    return new ScriptIntrinsic3DLUT(rs, e);
52}
53
54ScriptIntrinsic3DLUT::ScriptIntrinsic3DLUT(sp<RS> rs, sp<const Element> e)
55    : ScriptIntrinsic(rs, RS_SCRIPT_INTRINSIC_ID_3DLUT, e) {
56
57}
58void ScriptIntrinsic3DLUT::forEach(const sp<Allocation>& ain, const sp<Allocation>& aout) {
59    if (ain->getType()->getElement()->isCompatible(mElement) == false ||
60        aout->getType()->getElement()->isCompatible(mElement) == false) {
61        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "3DLUT forEach element mismatch");
62        return;
63    }
64    Script::forEach(0, ain, aout, nullptr, 0);
65}
66void ScriptIntrinsic3DLUT::setLUT(const sp<Allocation>& lut) {
67    sp<const Type> t = lut->getType();
68    if (!t->getElement()->isCompatible(mElement)) {
69        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "setLUT element does not match");
70        return;
71    }
72    if (t->getZ() == 0) {
73        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "setLUT Allocation must be 3D");
74        return;
75    }
76
77    Script::setVar(0, lut);
78}
79
80sp<ScriptIntrinsicBlend> ScriptIntrinsicBlend::create(const sp<RS>& rs, const sp<const Element>& e) {
81    if (e->isCompatible(Element::U8_4(rs)) == false) {
82        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Element not supported for intrinsic");
83        return nullptr;
84    }
85    return new ScriptIntrinsicBlend(rs, e);
86}
87
88ScriptIntrinsicBlend::ScriptIntrinsicBlend(sp<RS> rs, sp<const Element> e)
89    : ScriptIntrinsic(rs, RS_SCRIPT_INTRINSIC_ID_BLEND, e) {
90}
91
92void ScriptIntrinsicBlend::forEachClear(const sp<Allocation>& in, const sp<Allocation>& out) {
93    if (in->getType()->getElement()->isCompatible(mElement) == false ||
94        out->getType()->getElement()->isCompatible(mElement) == false) {
95        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
96    }
97    Script::forEach(0, in, out, nullptr, 0);
98}
99
100void ScriptIntrinsicBlend::forEachSrc(const sp<Allocation>& in, const sp<Allocation>& out) {
101    if (in->getType()->getElement()->isCompatible(mElement) == false ||
102        out->getType()->getElement()->isCompatible(mElement) == false) {
103        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
104    }
105    Script::forEach(1, in, out, nullptr, 0);
106}
107
108void ScriptIntrinsicBlend::forEachDst(const sp<Allocation>& in, const sp<Allocation>& out) {
109    if (in->getType()->getElement()->isCompatible(mElement) == false ||
110        out->getType()->getElement()->isCompatible(mElement) == false) {
111        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
112    }
113    Script::forEach(2, in, out, nullptr, 0);
114}
115
116void ScriptIntrinsicBlend::forEachSrcOver(const sp<Allocation>& in, const sp<Allocation>& out) {
117    if (in->getType()->getElement()->isCompatible(mElement) == false ||
118        out->getType()->getElement()->isCompatible(mElement) == false) {
119        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
120    }
121    Script::forEach(3, in, out, nullptr, 0);
122}
123
124void ScriptIntrinsicBlend::forEachDstOver(const sp<Allocation>& in, const sp<Allocation>& out) {
125    if (in->getType()->getElement()->isCompatible(mElement) == false ||
126        out->getType()->getElement()->isCompatible(mElement) == false) {
127        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
128    }
129    Script::forEach(4, in, out, nullptr, 0);
130}
131
132void ScriptIntrinsicBlend::forEachSrcIn(const sp<Allocation>& in, const sp<Allocation>& out) {
133    if (in->getType()->getElement()->isCompatible(mElement) == false ||
134        out->getType()->getElement()->isCompatible(mElement) == false) {
135        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
136    }
137    Script::forEach(5, in, out, nullptr, 0);
138}
139
140void ScriptIntrinsicBlend::forEachDstIn(const sp<Allocation>& in, const sp<Allocation>& out) {
141    if (in->getType()->getElement()->isCompatible(mElement) == false ||
142        out->getType()->getElement()->isCompatible(mElement) == false) {
143        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
144    }
145    Script::forEach(6, in, out, nullptr, 0);
146}
147
148void ScriptIntrinsicBlend::forEachSrcOut(const sp<Allocation>& in, const sp<Allocation>& out) {
149    if (in->getType()->getElement()->isCompatible(mElement) == false ||
150        out->getType()->getElement()->isCompatible(mElement) == false) {
151        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
152    }
153    Script::forEach(7, in, out, nullptr, 0);
154}
155
156void ScriptIntrinsicBlend::forEachDstOut(const sp<Allocation>& in, const sp<Allocation>& out) {
157    if (in->getType()->getElement()->isCompatible(mElement) == false ||
158        out->getType()->getElement()->isCompatible(mElement) == false) {
159        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
160    }
161    Script::forEach(8, in, out, nullptr, 0);
162}
163
164void ScriptIntrinsicBlend::forEachSrcAtop(const sp<Allocation>& in, const sp<Allocation>& out) {
165    if (in->getType()->getElement()->isCompatible(mElement) == false ||
166        out->getType()->getElement()->isCompatible(mElement) == false) {
167        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
168    }
169    Script::forEach(9, in, out, nullptr, 0);
170}
171
172void ScriptIntrinsicBlend::forEachDstAtop(const sp<Allocation>& in, const sp<Allocation>& out) {
173    if (in->getType()->getElement()->isCompatible(mElement) == false ||
174        out->getType()->getElement()->isCompatible(mElement) == false) {
175        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
176    }
177    Script::forEach(10, in, out, nullptr, 0);
178}
179
180void ScriptIntrinsicBlend::forEachXor(const sp<Allocation>& in, const sp<Allocation>& out) {
181    if (in->getType()->getElement()->isCompatible(mElement) == false ||
182        out->getType()->getElement()->isCompatible(mElement) == false) {
183        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
184    }
185    Script::forEach(11, in, out, nullptr, 0);
186}
187
188void ScriptIntrinsicBlend::forEachMultiply(const sp<Allocation>& in, const sp<Allocation>& out) {
189    if (in->getType()->getElement()->isCompatible(mElement) == false ||
190        out->getType()->getElement()->isCompatible(mElement) == false) {
191        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
192    }
193    Script::forEach(14, in, out, nullptr, 0);
194}
195
196void ScriptIntrinsicBlend::forEachAdd(const sp<Allocation>& in, const sp<Allocation>& out) {
197    if (in->getType()->getElement()->isCompatible(mElement) == false ||
198        out->getType()->getElement()->isCompatible(mElement) == false) {
199        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
200    }
201    Script::forEach(34, in, out, nullptr, 0);
202}
203
204void ScriptIntrinsicBlend::forEachSubtract(const sp<Allocation>& in, const sp<Allocation>& out) {
205    if (in->getType()->getElement()->isCompatible(mElement) == false ||
206        out->getType()->getElement()->isCompatible(mElement) == false) {
207        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
208    }
209    Script::forEach(35, in, out, nullptr, 0);
210}
211
212
213
214
215sp<ScriptIntrinsicBlur> ScriptIntrinsicBlur::create(const sp<RS>& rs, const sp<const Element>& e) {
216    if ((e->isCompatible(Element::U8_4(rs)) == false) &&
217        (e->isCompatible(Element::U8(rs)) == false)) {
218        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blur");
219        return nullptr;
220    }
221    return new ScriptIntrinsicBlur(rs, e);
222}
223
224ScriptIntrinsicBlur::ScriptIntrinsicBlur(sp<RS> rs, sp<const Element> e)
225    : ScriptIntrinsic(rs, RS_SCRIPT_INTRINSIC_ID_BLUR, e) {
226
227}
228
229void ScriptIntrinsicBlur::setInput(const sp<Allocation>& in) {
230    if (in->getType()->getElement()->isCompatible(mElement) == false) {
231        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blur input");
232        return;
233    }
234    Script::setVar(1, in);
235}
236
237void ScriptIntrinsicBlur::forEach(const sp<Allocation>& out) {
238    if (out->getType()->getElement()->isCompatible(mElement) == false) {
239        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blur output");
240        return;
241    }
242    Script::forEach(0, nullptr, out, nullptr, 0);
243}
244
245void ScriptIntrinsicBlur::setRadius(float radius) {
246    if (radius > 0.f && radius <= 25.f) {
247        Script::setVar(0, &radius, sizeof(float));
248    } else {
249        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Blur radius out of 0-25 pixel bound");
250    }
251}
252
253
254
255sp<ScriptIntrinsicColorMatrix> ScriptIntrinsicColorMatrix::create(const sp<RS>& rs) {
256    return new ScriptIntrinsicColorMatrix(rs, Element::RGBA_8888(rs));
257}
258
259ScriptIntrinsicColorMatrix::ScriptIntrinsicColorMatrix(sp<RS> rs, sp<const Element> e)
260    : ScriptIntrinsic(rs, RS_SCRIPT_INTRINSIC_ID_COLOR_MATRIX, e) {
261    float add[4] = {0.f, 0.f, 0.f, 0.f};
262    setAdd(add);
263
264}
265
266void ScriptIntrinsicColorMatrix::forEach(const sp<Allocation>& in, const sp<Allocation>& out) {
267    if (!(in->getType()->getElement()->isCompatible(Element::U8(mRS))) &&
268        !(in->getType()->getElement()->isCompatible(Element::U8_2(mRS))) &&
269        !(in->getType()->getElement()->isCompatible(Element::U8_3(mRS))) &&
270        !(in->getType()->getElement()->isCompatible(Element::U8_4(mRS))) &&
271        !(in->getType()->getElement()->isCompatible(Element::F32(mRS))) &&
272        !(in->getType()->getElement()->isCompatible(Element::F32_2(mRS))) &&
273        !(in->getType()->getElement()->isCompatible(Element::F32_3(mRS))) &&
274        !(in->getType()->getElement()->isCompatible(Element::F32_4(mRS)))) {
275        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for ColorMatrix");
276        return;
277    }
278
279    if (!(out->getType()->getElement()->isCompatible(Element::U8(mRS))) &&
280        !(out->getType()->getElement()->isCompatible(Element::U8_2(mRS))) &&
281        !(out->getType()->getElement()->isCompatible(Element::U8_3(mRS))) &&
282        !(out->getType()->getElement()->isCompatible(Element::U8_4(mRS))) &&
283        !(out->getType()->getElement()->isCompatible(Element::F32(mRS))) &&
284        !(out->getType()->getElement()->isCompatible(Element::F32_2(mRS))) &&
285        !(out->getType()->getElement()->isCompatible(Element::F32_3(mRS))) &&
286        !(out->getType()->getElement()->isCompatible(Element::F32_4(mRS)))) {
287        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for ColorMatrix");
288        return;
289    }
290
291    Script::forEach(0, in, out, nullptr, 0);
292}
293
294void ScriptIntrinsicColorMatrix::setAdd(float* add) {
295    Script::setVar(1, (void*)add, sizeof(float) * 4);
296}
297
298void ScriptIntrinsicColorMatrix::setColorMatrix3(float* m) {
299    float temp[16];
300    temp[0] = m[0];
301    temp[1] = m[1];
302    temp[2] = m[2];
303    temp[3] = 0.f;
304
305    temp[4] = m[3];
306    temp[5] = m[4];
307    temp[6] = m[5];
308    temp[7] = 0.f;
309
310    temp[8] = m[6];
311    temp[9] = m[7];
312    temp[10] = m[8];
313    temp[11] = 0.f;
314
315    temp[12] = 0.f;
316    temp[13] = 0.f;
317    temp[14] = 0.f;
318    temp[15] = 1.f;
319
320    setColorMatrix4(temp);
321}
322
323
324void ScriptIntrinsicColorMatrix::setColorMatrix4(float* m) {
325    Script::setVar(0, (void*)m, sizeof(float) * 16);
326}
327
328
329void ScriptIntrinsicColorMatrix::setGreyscale() {
330    float matrix[] = {0.299f, 0.299f, 0.299f,0.587f,0.587f,0.587f,0.114f,0.114f, 0.114f};
331    setColorMatrix3(matrix);
332}
333
334
335void ScriptIntrinsicColorMatrix::setRGBtoYUV() {
336    float matrix[] = { 0.299f, -0.14713f, 0.615f, 0.587f, -0.28886f, -0.51499f, 0.114f, 0.436f, -0.10001f};
337    setColorMatrix3(matrix);
338}
339
340
341void ScriptIntrinsicColorMatrix::setYUVtoRGB() {
342    float matrix[] = {1.f, 1.f, 1.f, 0.f, -0.39465f, 2.03211f, 1.13983f, -0.5806f, 0.f};
343    setColorMatrix3(matrix);
344}
345
346
347
348sp<ScriptIntrinsicConvolve3x3> ScriptIntrinsicConvolve3x3::create(const sp<RS>& rs, const sp<const Element>& e) {
349    if (!(e->isCompatible(Element::U8(rs))) &&
350        !(e->isCompatible(Element::U8_2(rs))) &&
351        !(e->isCompatible(Element::U8_3(rs))) &&
352        !(e->isCompatible(Element::U8_4(rs))) &&
353        !(e->isCompatible(Element::F32(rs))) &&
354        !(e->isCompatible(Element::F32_2(rs))) &&
355        !(e->isCompatible(Element::F32_3(rs))) &&
356        !(e->isCompatible(Element::F32_4(rs)))) {
357        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for Convolve3x3");
358        return nullptr;
359    }
360
361    return new ScriptIntrinsicConvolve3x3(rs, e);
362}
363
364ScriptIntrinsicConvolve3x3::ScriptIntrinsicConvolve3x3(sp<RS> rs, sp<const Element> e)
365    : ScriptIntrinsic(rs, RS_SCRIPT_INTRINSIC_ID_CONVOLVE_3x3, e) {
366
367}
368
369void ScriptIntrinsicConvolve3x3::setInput(const sp<Allocation>& in) {
370    if (!(in->getType()->getElement()->isCompatible(mElement))) {
371        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Element mismatch in Convolve3x3");
372        return;
373    }
374    Script::setVar(1, in);
375}
376
377void ScriptIntrinsicConvolve3x3::forEach(const sp<Allocation>& out) {
378    if (!(out->getType()->getElement()->isCompatible(mElement))) {
379        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Element mismatch in Convolve3x3");
380        return;
381    }
382    Script::forEach(0, nullptr, out, nullptr, 0);
383}
384
385void ScriptIntrinsicConvolve3x3::setCoefficients(float* v) {
386    Script::setVar(0, (void*)v, sizeof(float) * 9);
387}
388
389sp<ScriptIntrinsicConvolve5x5> ScriptIntrinsicConvolve5x5::create(const sp<RS>& rs, const sp<const Element>& e) {
390    if (!(e->isCompatible(Element::U8(rs))) &&
391        !(e->isCompatible(Element::U8_2(rs))) &&
392        !(e->isCompatible(Element::U8_3(rs))) &&
393        !(e->isCompatible(Element::U8_4(rs))) &&
394        !(e->isCompatible(Element::F32(rs))) &&
395        !(e->isCompatible(Element::F32_2(rs))) &&
396        !(e->isCompatible(Element::F32_3(rs))) &&
397        !(e->isCompatible(Element::F32_4(rs)))) {
398        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for Convolve5x5");
399        return nullptr;
400    }
401
402    return new ScriptIntrinsicConvolve5x5(rs, e);
403}
404
405ScriptIntrinsicConvolve5x5::ScriptIntrinsicConvolve5x5(sp<RS> rs, sp<const Element> e)
406    : ScriptIntrinsic(rs, RS_SCRIPT_INTRINSIC_ID_CONVOLVE_5x5, e) {
407
408}
409
410void ScriptIntrinsicConvolve5x5::setInput(const sp<Allocation>& in) {
411    if (!(in->getType()->getElement()->isCompatible(mElement))) {
412        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Element mismatch in Convolve5x5 input");
413        return;
414    }
415    Script::setVar(1, in);
416}
417
418void ScriptIntrinsicConvolve5x5::forEach(const sp<Allocation>& out) {
419    if (!(out->getType()->getElement()->isCompatible(mElement))) {
420        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Element mismatch in Convolve5x5 output");
421        return;
422    }
423
424    Script::forEach(0, nullptr, out, nullptr, 0);
425}
426
427void ScriptIntrinsicConvolve5x5::setCoefficients(float* v) {
428    Script::setVar(0, (void*)v, sizeof(float) * 25);
429}
430
431sp<ScriptIntrinsicHistogram> ScriptIntrinsicHistogram::create(const sp<RS>& rs, const sp<const Element>& e) {
432    return new ScriptIntrinsicHistogram(rs, e);
433}
434
435ScriptIntrinsicHistogram::ScriptIntrinsicHistogram(sp<RS> rs, sp<const Element> e)
436    : ScriptIntrinsic(rs, RS_SCRIPT_INTRINSIC_ID_HISTOGRAM, e) {
437
438}
439
440void ScriptIntrinsicHistogram::setOutput(const sp<Allocation>& out) {
441    if (!(out->getType()->getElement()->isCompatible(Element::U32(mRS))) &&
442        !(out->getType()->getElement()->isCompatible(Element::U32_2(mRS))) &&
443        !(out->getType()->getElement()->isCompatible(Element::U32_3(mRS))) &&
444        !(out->getType()->getElement()->isCompatible(Element::U32_4(mRS))) &&
445        !(out->getType()->getElement()->isCompatible(Element::I32(mRS))) &&
446        !(out->getType()->getElement()->isCompatible(Element::I32_2(mRS))) &&
447        !(out->getType()->getElement()->isCompatible(Element::I32_3(mRS))) &&
448        !(out->getType()->getElement()->isCompatible(Element::I32_4(mRS)))) {
449        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for Histogram output");
450        return;
451    }
452
453    if (out->getType()->getX() != 256 ||
454        out->getType()->getY() != 0 ||
455        out->getType()->hasMipmaps()) {
456        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid Allocation type for Histogram output");
457        return;
458    }
459    mOut = out;
460    Script::setVar(1, out);
461}
462
463void ScriptIntrinsicHistogram::setDotCoefficients(float r, float g, float b, float a) {
464    if ((r < 0.f) || (g < 0.f) || (b < 0.f) || (a < 0.f)) {
465        return;
466    }
467    if ((r + g + b + a) > 1.f) {
468        return;
469    }
470
471    FieldPacker fp(16);
472    fp.add(r);
473    fp.add(g);
474    fp.add(b);
475    fp.add(a);
476    Script::setVar(0, fp.getData(), fp.getLength());
477
478}
479
480void ScriptIntrinsicHistogram::forEach(const sp<Allocation>& ain) {
481    if (ain->getType()->getElement()->getVectorSize() <
482        mOut->getType()->getElement()->getVectorSize()) {
483        mRS->throwError(RS_ERROR_INVALID_PARAMETER,
484                        "Input vector size must be >= output vector size");
485        return;
486    }
487
488    if (!(ain->getType()->getElement()->isCompatible(Element::U8(mRS))) &&
489        !(ain->getType()->getElement()->isCompatible(Element::U8_4(mRS)))) {
490        mRS->throwError(RS_ERROR_INVALID_ELEMENT,
491                        "Input allocation to Histogram must be U8 or U8_4");
492        return;
493    }
494
495    Script::forEach(0, ain, nullptr, nullptr, 0);
496}
497
498
499void ScriptIntrinsicHistogram::forEach_dot(const sp<Allocation>& ain) {
500    if (mOut->getType()->getElement()->getVectorSize() != 1) {
501        mRS->throwError(RS_ERROR_INVALID_PARAMETER,
502                        "Output Histogram allocation must have vector size of 1 " \
503                        "when used with forEach_dot");
504        return;
505    }
506    if (!(ain->getType()->getElement()->isCompatible(Element::U8(mRS))) &&
507        !(ain->getType()->getElement()->isCompatible(Element::U8_4(mRS)))) {
508        mRS->throwError(RS_ERROR_INVALID_ELEMENT,
509                        "Input allocation to Histogram must be U8 or U8_4");
510        return;
511    }
512
513    Script::forEach(1, ain, nullptr, nullptr, 0);
514}
515
516sp<ScriptIntrinsicLUT> ScriptIntrinsicLUT::create(const sp<RS>& rs, const sp<const Element>& e) {
517    if (!(e->isCompatible(Element::U8_4(rs)))) {
518        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for LUT");
519        return nullptr;
520    }
521    return new ScriptIntrinsicLUT(rs, e);
522}
523
524ScriptIntrinsicLUT::ScriptIntrinsicLUT(sp<RS> rs, sp<const Element> e)
525    : ScriptIntrinsic(rs, RS_SCRIPT_INTRINSIC_ID_LUT, e), mDirty(true) {
526    LUT = Allocation::createSized(rs, Element::U8(rs), 1024);
527    for (int i = 0; i < 256; i++) {
528        mCache[i] = i;
529        mCache[i+256] = i;
530        mCache[i+512] = i;
531        mCache[i+768] = i;
532    }
533    setVar(0, LUT);
534}
535
536void ScriptIntrinsicLUT::forEach(const sp<Allocation>& ain, const sp<Allocation>& aout) {
537    if (mDirty) {
538        LUT->copy1DFrom((void*)mCache);
539        mDirty = false;
540    }
541    if (!(ain->getType()->getElement()->isCompatible(Element::U8_4(mRS))) ||
542        !(aout->getType()->getElement()->isCompatible(Element::U8_4(mRS)))) {
543        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for LUT");
544        return;
545    }
546    Script::forEach(0, ain, aout, nullptr, 0);
547
548}
549
550void ScriptIntrinsicLUT::setTable(unsigned int offset, unsigned char base, unsigned int length, unsigned char* lutValues) {
551    if ((base + length) > 256 || length == 0) {
552        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "LUT out of range");
553        return;
554    }
555    mDirty = true;
556    for (unsigned int i = 0; i < length; i++) {
557        mCache[offset + base + i] = lutValues[i];
558    }
559}
560
561void ScriptIntrinsicLUT::setRed(unsigned char base, unsigned int length, unsigned char* lutValues) {
562    setTable(0, base, length, lutValues);
563}
564
565void ScriptIntrinsicLUT::setGreen(unsigned char base, unsigned int length, unsigned char* lutValues) {
566    setTable(256, base, length, lutValues);
567}
568
569void ScriptIntrinsicLUT::setBlue(unsigned char base, unsigned int length, unsigned char* lutValues) {
570    setTable(512, base, length, lutValues);
571}
572
573void ScriptIntrinsicLUT::setAlpha(unsigned char base, unsigned int length, unsigned char* lutValues) {
574    setTable(768, base, length, lutValues);
575}
576
577ScriptIntrinsicLUT::~ScriptIntrinsicLUT() {
578
579}
580
581sp<ScriptIntrinsicResize> ScriptIntrinsicResize::create(const sp<RS>& rs) {
582    return new ScriptIntrinsicResize(rs, nullptr);
583}
584
585ScriptIntrinsicResize::ScriptIntrinsicResize(sp<RS> rs, sp<const Element> e)
586    : ScriptIntrinsic(rs, RS_SCRIPT_INTRINSIC_ID_RESIZE, e) {
587
588}
589void ScriptIntrinsicResize::forEach_bicubic(const sp<Allocation>& aout) {
590    if (aout == mInput) {
591        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Resize Input and Ouput cannot be the same");
592    }
593
594    if (!(mInput->getType()->getElement()->isCompatible(aout->getType()->getElement()))) {
595        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Resize forEach element mismatch");
596        return;
597    }
598    Script::forEach(0, nullptr, aout, nullptr, 0);
599}
600void ScriptIntrinsicResize::setInput(const sp<Allocation>& ain) {
601    if (!(ain->getType()->getElement()->isCompatible(Element::U8(mRS))) &&
602        !(ain->getType()->getElement()->isCompatible(Element::U8_2(mRS))) &&
603        !(ain->getType()->getElement()->isCompatible(Element::U8_3(mRS))) &&
604        !(ain->getType()->getElement()->isCompatible(Element::U8_4(mRS))) &&
605        !(ain->getType()->getElement()->isCompatible(Element::F32(mRS))) &&
606        !(ain->getType()->getElement()->isCompatible(Element::F32_2(mRS))) &&
607        !(ain->getType()->getElement()->isCompatible(Element::F32_3(mRS))) &&
608        !(ain->getType()->getElement()->isCompatible(Element::F32_4(mRS)))) {
609        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for Resize Input");
610        return;
611    }
612
613    mInput = ain;
614    Script::setVar(0, ain);
615}
616
617
618sp<ScriptIntrinsicYuvToRGB> ScriptIntrinsicYuvToRGB::create(const sp<RS>& rs, const sp<const Element>& e) {
619    if (!(e->isCompatible(Element::U8_4(rs)))) {
620        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for YuvToRGB");
621        return nullptr;
622    }
623    return new ScriptIntrinsicYuvToRGB(rs, e);
624}
625
626ScriptIntrinsicYuvToRGB::ScriptIntrinsicYuvToRGB(sp<RS> rs, sp<const Element> e)
627    : ScriptIntrinsic(rs, RS_SCRIPT_INTRINSIC_ID_YUV_TO_RGB, e) {
628
629}
630
631void ScriptIntrinsicYuvToRGB::setInput(const sp<Allocation>& in) {
632    if (!(in->getType()->getElement()->isCompatible(Element::YUV(mRS)))) {
633        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for input in YuvToRGB");
634        return;
635    }
636    Script::setVar(0, in);
637}
638
639void ScriptIntrinsicYuvToRGB::forEach(const sp<Allocation>& out) {
640    if (!(out->getType()->getElement()->isCompatible(mElement))) {
641        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for output in YuvToRGB");
642        return;
643    }
644
645    Script::forEach(0, nullptr, out, nullptr, 0);
646}
647