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