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
17package android.support.v8.renderscript;
18
19import android.util.SparseArray;
20
21/**
22 * The parent class for all executable scripts. This should not be used by
23 * applications.
24 **/
25public class Script extends BaseObj {
26    /**
27     * Determine if Incremental Intrinsic Support is needed
28     *
29     */
30    private boolean mUseIncSupp;
31    protected void setIncSupp(boolean useInc) {
32        mUseIncSupp = useInc;
33    }
34    protected boolean isIncSupp() {
35        return mUseIncSupp;
36    }
37    /**
38     * An allocation for the compat context will be created when needed
39     * e.g. foreach(ain, aout), setVar(ain);
40     *
41     */
42    long getDummyAlloc(Allocation ain) {
43        long dInElement = 0;
44        long dInType = 0;
45        long dummyAlloc = 0;
46        if (ain != null) {
47            Type inType = ain.getType();
48            dInElement = inType.getElement().getDummyElement(mRS);
49            dInType = inType.getDummyType(mRS, dInElement);
50            int xBytesSize = inType.getX() * inType.getElement().getBytesSize();
51            dummyAlloc = mRS.nIncAllocationCreateTyped(ain.getID(mRS), dInType, xBytesSize);
52            ain.setIncAllocID(dummyAlloc);
53        }
54
55        return dummyAlloc;
56    }
57    /**
58     * KernelID is an identifier for a Script + root function pair. It is used
59     * as an identifier for ScriptGroup creation.
60     *
61     * This class should not be directly created. Instead use the method in the
62     * reflected or intrinsic code "getKernelID_funcname()".
63     *
64     */
65    public static final class KernelID extends BaseObj {
66        android.renderscript.Script.KernelID mN;
67        Script mScript;
68        int mSlot;
69        int mSig;
70        KernelID(long id, RenderScript rs, Script s, int slot, int sig) {
71            super(id, rs);
72            mScript = s;
73            mSlot = slot;
74            mSig = sig;
75        }
76    }
77
78    private final SparseArray<KernelID> mKIDs = new SparseArray<KernelID>();
79    /**
80     * Only to be used by generated reflected classes.
81     *
82     *
83     * @param slot
84     * @param sig
85     * @param ein
86     * @param eout
87     *
88     * @return KernelID
89     */
90    protected KernelID createKernelID(int slot, int sig, Element ein, Element eout) {
91        KernelID k = mKIDs.get(slot);
92        if (k != null) {
93            return k;
94        }
95
96        long id = mRS.nScriptKernelIDCreate(getID(mRS), slot, sig, mUseIncSupp);
97        if (id == 0) {
98            throw new RSDriverException("Failed to create KernelID");
99        }
100
101        k = new KernelID(id, mRS, this, slot, sig);
102
103        mKIDs.put(slot, k);
104        return k;
105    }
106
107    /**
108     * InvokeID is an identifier for a invoke function. It is used
109     * as an identifier for ScriptGroup creation.
110     *
111     * This class should not be directly created. Instead use the method in the
112     * reflected or intrinsic code "getInvokeID_funcname()".
113     *
114     */
115    public static final class InvokeID extends BaseObj {
116        Script mScript;
117        int mSlot;
118        InvokeID(long id, RenderScript rs, Script s, int slot) {
119            super(id, rs);
120            mScript = s;
121            mSlot = slot;
122        }
123    }
124
125    private final SparseArray<InvokeID> mIIDs = new SparseArray<InvokeID>();
126    /**
127     * Only to be used by generated reflected classes.
128     */
129    protected InvokeID createInvokeID(int slot) {
130        InvokeID i = mIIDs.get(slot);
131        if (i != null) {
132            return i;
133        }
134
135        long id = mRS.nScriptInvokeIDCreate(getID(mRS), slot);
136        if (id == 0) {
137            throw new RSDriverException("Failed to create KernelID");
138        }
139
140        i = new InvokeID(id, mRS, this, slot);
141        mIIDs.put(slot, i);
142        return i;
143    }
144
145    /**
146     * FieldID is an identifier for a Script + exported field pair. It is used
147     * as an identifier for ScriptGroup creation.
148     *
149     * This class should not be directly created. Instead use the method in the
150     * reflected or intrinsic code "getFieldID_funcname()".
151     *
152     */
153    public static final class FieldID extends BaseObj {
154        android.renderscript.Script.FieldID mN;
155        Script mScript;
156        int mSlot;
157        FieldID(long id, RenderScript rs, Script s, int slot) {
158            super(id, rs);
159            mScript = s;
160            mSlot = slot;
161        }
162    }
163
164    private final SparseArray<FieldID> mFIDs = new SparseArray();
165    /**
166     * Only to be used by generated reflected classes.
167     *
168     * @param slot
169     * @param e
170     *
171     * @return FieldID
172     */
173    protected FieldID createFieldID(int slot, Element e) {
174        FieldID f = mFIDs.get(slot);
175        if (f != null) {
176            return f;
177        }
178
179        long id = mRS.nScriptFieldIDCreate(getID(mRS), slot, mUseIncSupp);
180        if (id == 0) {
181            throw new RSDriverException("Failed to create FieldID");
182        }
183
184        f = new FieldID(id, mRS, this, slot);
185        mFIDs.put(slot, f);
186        return f;
187    }
188
189    /**
190     * Only intended for use by generated reflected code.
191     *
192     * @param slot
193     */
194    protected void invoke(int slot) {
195        mRS.nScriptInvoke(getID(mRS), slot, mUseIncSupp);
196    }
197
198    /**
199     * Only intended for use by generated reflected code.
200     *
201     * @param slot
202     * @param v
203     */
204    protected void invoke(int slot, FieldPacker v) {
205        if (v != null) {
206            mRS.nScriptInvokeV(getID(mRS), slot, v.getData(), mUseIncSupp);
207        } else {
208            mRS.nScriptInvoke(getID(mRS), slot, mUseIncSupp);
209        }
210    }
211
212    /**
213     * Only intended for use by generated reflected code.
214     *
215     * @param va
216     * @param slot
217     */
218    public void bindAllocation(Allocation va, int slot) {
219        mRS.validate();
220        if (va != null) {
221            mRS.nScriptBindAllocation(getID(mRS), va.getID(mRS), slot, mUseIncSupp);
222        } else {
223            mRS.nScriptBindAllocation(getID(mRS), 0, slot, mUseIncSupp);
224        }
225    }
226
227    public void setTimeZone(String timeZone) {
228        mRS.validate();
229        try {
230            mRS.nScriptSetTimeZone(getID(mRS), timeZone.getBytes("UTF-8"), mUseIncSupp);
231        } catch (java.io.UnsupportedEncodingException e) {
232            throw new RuntimeException(e);
233        }
234    }
235
236
237    /**
238     * Only intended for use by generated reflected code.
239     *
240     * @param slot
241     * @param ain
242     * @param aout
243     * @param v
244     */
245    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v) {
246        if (ain == null && aout == null) {
247            throw new RSIllegalArgumentException(
248                "At least one of ain or aout is required to be non-null.");
249        }
250        long in_id = 0;
251        long out_id = 0;
252        if (ain != null) {
253            in_id = ain.getID(mRS);
254        }
255        if (aout != null) {
256            out_id = aout.getID(mRS);
257        }
258
259        byte[] params = null;
260        if (v != null) {
261            params = v.getData();
262        }
263
264        if (mUseIncSupp) {
265            long ainInc = getDummyAlloc(ain);
266            long aoutInc = getDummyAlloc(aout);
267            mRS.nScriptForEach(getID(mRS), slot, ainInc, aoutInc, params, mUseIncSupp);
268        } else {
269            mRS.nScriptForEach(getID(mRS), slot, in_id, out_id, params, mUseIncSupp);
270        }
271    }
272
273    /**
274     * Only intended for use by generated reflected code.
275     *
276     * @param slot
277     * @param ain
278     * @param aout
279     * @param v
280     * @param sc
281     */
282    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v, LaunchOptions sc) {
283        if (ain == null && aout == null) {
284            throw new RSIllegalArgumentException(
285                "At least one of ain or aout is required to be non-null.");
286        }
287
288        if (sc == null) {
289            forEach(slot, ain, aout, v);
290            return;
291        }
292        long in_id = 0;
293        long out_id = 0;
294        if (ain != null) {
295            in_id = ain.getID(mRS);
296        }
297        if (aout != null) {
298            out_id = aout.getID(mRS);
299        }
300
301        byte[] params = null;
302        if (v != null) {
303            params = v.getData();
304        }
305        if (mUseIncSupp) {
306            long ainInc = getDummyAlloc(ain);
307            long aoutInc = getDummyAlloc(aout);
308            mRS.nScriptForEachClipped(getID(mRS), slot, ainInc, aoutInc, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend, mUseIncSupp);
309        } else {
310            mRS.nScriptForEachClipped(getID(mRS), slot, in_id, out_id, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend, mUseIncSupp);
311        }
312    }
313
314    Script(long id, RenderScript rs) {
315        super(id, rs);
316        mUseIncSupp = false;
317    }
318
319    /**
320     * Only intended for use by generated reflected code.
321     *
322     * @hide
323     */
324    protected void forEach(int slot, Allocation[] ains, Allocation aout,
325                           FieldPacker v) {
326        forEach(slot, ains, aout, v, null);
327    }
328
329    /**
330     * Only intended for use by generated reflected code.
331     *
332     * @hide
333     */
334    protected void forEach(int slot, Allocation[] ains, Allocation aout,
335                           FieldPacker v, LaunchOptions sc) {
336        // TODO: Is this necessary if nScriptForEach calls validate as well?
337        mRS.validate();
338        if (ains != null) {
339            for (Allocation ain : ains) {
340                mRS.validateObject(ain);
341            }
342        }
343        mRS.validateObject(aout);
344
345        if (ains == null && aout == null) {
346            throw new RSIllegalArgumentException(
347                "At least one of ain or aout is required to be non-null.");
348        }
349
350        long[] in_ids;
351        if (ains != null) {
352            in_ids = new long[ains.length];
353            for (int index = 0; index < ains.length; ++index) {
354                in_ids[index] = ains[index].getID(mRS);
355            }
356        } else {
357            in_ids = null;
358        }
359
360        long out_id = 0;
361        if (aout != null) {
362            out_id = aout.getID(mRS);
363        }
364
365        byte[] params = null;
366        if (v != null) {
367            params = v.getData();
368        }
369
370        int[] limits = null;
371        if (sc != null) {
372            limits = new int[6];
373
374            limits[0] = sc.xstart;
375            limits[1] = sc.xend;
376            limits[2] = sc.ystart;
377            limits[3] = sc.yend;
378            limits[4] = sc.zstart;
379            limits[5] = sc.zend;
380        }
381
382        mRS.nScriptForEach(getID(mRS), slot, in_ids, out_id, params, limits);
383    }
384
385    /**
386     * Only intended for use by generated reflected code.  (General reduction)
387     *
388     * @hide
389     */
390    protected void reduce(int slot, Allocation[] ains, Allocation aout, LaunchOptions sc) {
391        mRS.validate();
392        if (ains == null || ains.length < 1) {
393            throw new RSIllegalArgumentException(
394                "At least one input is required.");
395        }
396        if (aout == null) {
397            throw new RSIllegalArgumentException(
398                "aout is required to be non-null.");
399        }
400        for (Allocation ain : ains) {
401            mRS.validateObject(ain);
402        }
403
404        long[] in_ids = new long[ains.length];
405        for (int index = 0; index < ains.length; ++index) {
406            in_ids[index] = ains[index].getID(mRS);
407        }
408        long out_id = aout.getID(mRS);
409
410        int[] limits = null;
411        if (sc != null) {
412            limits = new int[6];
413
414            limits[0] = sc.xstart;
415            limits[1] = sc.xend;
416            limits[2] = sc.ystart;
417            limits[3] = sc.yend;
418            limits[4] = sc.zstart;
419            limits[5] = sc.zend;
420        }
421
422        mRS.nScriptReduce(getID(mRS), slot, in_ids, out_id, limits);
423    }
424
425    /**
426     * Only intended for use by generated reflected code.
427     *
428     * @param index
429     * @param v
430     */
431    public void setVar(int index, float v) {
432        mRS.nScriptSetVarF(getID(mRS), index, v, mUseIncSupp);
433    }
434
435    /**
436     * Only intended for use by generated reflected code.
437     *
438     * @param index
439     * @param v
440     */
441    public void setVar(int index, double v) {
442        mRS.nScriptSetVarD(getID(mRS), index, v, mUseIncSupp);
443    }
444
445    /**
446     * Only intended for use by generated reflected code.
447     *
448     * @param index
449     * @param v
450     */
451    public void setVar(int index, int v) {
452        mRS.nScriptSetVarI(getID(mRS), index, v, mUseIncSupp);
453    }
454
455    /**
456     * Only intended for use by generated reflected code.
457     *
458     * @param index
459     * @param v
460     */
461    public void setVar(int index, long v) {
462        mRS.nScriptSetVarJ(getID(mRS), index, v, mUseIncSupp);
463    }
464
465    /**
466     * Only intended for use by generated reflected code.
467     *
468     * @param index
469     * @param v
470     */
471    public void setVar(int index, boolean v) {
472        mRS.nScriptSetVarI(getID(mRS), index, v ? 1 : 0, mUseIncSupp);
473    }
474
475    /**
476     * Only intended for use by generated reflected code.
477     *
478     * @param index
479     * @param o
480     */
481    public void setVar(int index, BaseObj o) {
482        if (mUseIncSupp) {
483            long oInc = getDummyAlloc((Allocation)o);
484            mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : oInc, mUseIncSupp);
485        } else {
486            mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : o.getID(mRS), mUseIncSupp);
487        }
488    }
489
490    /**
491     * Only intended for use by generated reflected code.
492     *
493     * @param index
494     * @param v
495     */
496    public void setVar(int index, FieldPacker v) {
497        mRS.nScriptSetVarV(getID(mRS), index, v.getData(), mUseIncSupp);
498    }
499
500    /**
501     * Only intended for use by generated reflected code.
502     *
503     * @param index
504     * @param v
505     * @param e
506     * @param dims
507     */
508    public void setVar(int index, FieldPacker v, Element e, int[] dims) {
509        if (mUseIncSupp) {
510            long dElement = e.getDummyElement(mRS);
511            mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), dElement, dims, mUseIncSupp);
512        } else {
513            mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), e.getID(mRS), dims, mUseIncSupp);
514        }
515    }
516
517    /**
518     * Only intended for use by generated reflected code.
519     *
520     */
521    public static class Builder {
522        RenderScript mRS;
523
524        Builder(RenderScript rs) {
525            mRS = rs;
526        }
527    }
528
529
530    /**
531     * Only intended for use by generated reflected code.
532     *
533     */
534    public static class FieldBase {
535        protected Element mElement;
536        protected Allocation mAllocation;
537
538        protected void init(RenderScript rs, int dimx) {
539            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT);
540        }
541
542        protected void init(RenderScript rs, int dimx, int usages) {
543            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT | usages);
544        }
545
546        protected FieldBase() {
547        }
548
549        public Element getElement() {
550            return mElement;
551        }
552
553        public Type getType() {
554            return mAllocation.getType();
555        }
556
557        public Allocation getAllocation() {
558            return mAllocation;
559        }
560
561        //@Override
562        public void updateAllocation() {
563        }
564    }
565
566
567    /**
568     * Class for specifying the specifics about how a kernel will be
569     * launched.
570     *
571     * This class can specify a potential range of cells on which to
572     * run a kernel.  If no set is called for a dimension then this
573     * class will have no impact on that dimension when the kernel
574     * is executed.
575     *
576     * The forEach kernel launch will operate over the intersection of
577     * the dimensions.
578     *
579     * Example:
580     * LaunchOptions with setX(5, 15)
581     * Allocation with dimension X=10, Y=10
582     * The resulting forEach run would execute over:
583     * x = 5 to 9 (inclusive) and
584     * y = 0 to 9 (inclusive).
585     *
586     */
587    public static final class LaunchOptions {
588        private int xstart = 0;
589        private int ystart = 0;
590        private int xend = 0;
591        private int yend = 0;
592        private int zstart = 0;
593        private int zend = 0;
594        private int strategy;
595
596        /**
597         * Set the X range. xstartArg is the lowest coordinate of the range,
598         * and xendArg-1 is the highest coordinate of the range.
599         *
600         * @param xstartArg Must be >= 0
601         * @param xendArg Must be > xstartArg
602         *
603         * @return LaunchOptions
604         */
605        public LaunchOptions setX(int xstartArg, int xendArg) {
606            if (xstartArg < 0 || xendArg <= xstartArg) {
607                throw new RSIllegalArgumentException("Invalid dimensions");
608            }
609            xstart = xstartArg;
610            xend = xendArg;
611            return this;
612        }
613
614        /**
615         * Set the Y range. ystartArg is the lowest coordinate of the range,
616         * and yendArg-1 is the highest coordinate of the range.
617         *
618         * @param ystartArg Must be >= 0
619         * @param yendArg Must be > ystartArg
620         *
621         * @return LaunchOptions
622         */
623        public LaunchOptions setY(int ystartArg, int yendArg) {
624            if (ystartArg < 0 || yendArg <= ystartArg) {
625                throw new RSIllegalArgumentException("Invalid dimensions");
626            }
627            ystart = ystartArg;
628            yend = yendArg;
629            return this;
630        }
631
632        /**
633         * Set the Z range. zstartArg is the lowest coordinate of the range,
634         * and zendArg-1 is the highest coordinate of the range.
635         *
636         * @param zstartArg Must be >= 0
637         * @param zendArg Must be > zstartArg
638         *
639         * @return LaunchOptions
640         */
641        public LaunchOptions setZ(int zstartArg, int zendArg) {
642            if (zstartArg < 0 || zendArg <= zstartArg) {
643                throw new RSIllegalArgumentException("Invalid dimensions");
644            }
645            zstart = zstartArg;
646            zend = zendArg;
647            return this;
648        }
649
650
651        /**
652         * Returns the current X start
653         *
654         * @return int current value
655         */
656        public int getXStart() {
657            return xstart;
658        }
659        /**
660         * Returns the current X end
661         *
662         * @return int current value
663         */
664        public int getXEnd() {
665            return xend;
666        }
667        /**
668         * Returns the current Y start
669         *
670         * @return int current value
671         */
672        public int getYStart() {
673            return ystart;
674        }
675        /**
676         * Returns the current Y end
677         *
678         * @return int current value
679         */
680        public int getYEnd() {
681            return yend;
682        }
683        /**
684         * Returns the current Z start
685         *
686         * @return int current value
687         */
688        public int getZStart() {
689            return zstart;
690        }
691        /**
692         * Returns the current Z end
693         *
694         * @return int current value
695         */
696        public int getZEnd() {
697            return zend;
698        }
699
700    }
701}
702