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            dInElement = ain.getType().getElement().getDummyElement(mRS);
48            dInType = ain.getType().getDummyType(mRS, dInElement);
49            dummyAlloc = mRS.nIncAllocationCreateTyped(ain.getID(mRS), dInType);
50            ain.setIncAllocID(dummyAlloc);
51        }
52
53        return dummyAlloc;
54    }
55    /**
56     * KernelID is an identifier for a Script + root function pair. It is used
57     * as an identifier for ScriptGroup creation.
58     *
59     * This class should not be directly created. Instead use the method in the
60     * reflected or intrinsic code "getKernelID_funcname()".
61     *
62     */
63    public static final class KernelID extends BaseObj {
64        android.renderscript.Script.KernelID mN;
65        Script mScript;
66        int mSlot;
67        int mSig;
68        KernelID(long id, RenderScript rs, Script s, int slot, int sig) {
69            super(id, rs);
70            mScript = s;
71            mSlot = slot;
72            mSig = sig;
73        }
74    }
75
76    private final SparseArray<KernelID> mKIDs = new SparseArray<KernelID>();
77    /**
78     * Only to be used by generated reflected classes.
79     *
80     *
81     * @param slot
82     * @param sig
83     * @param ein
84     * @param eout
85     *
86     * @return KernelID
87     */
88    protected KernelID createKernelID(int slot, int sig, Element ein, Element eout) {
89        KernelID k = mKIDs.get(slot);
90        if (k != null) {
91            return k;
92        }
93
94        long id = mRS.nScriptKernelIDCreate(getID(mRS), slot, sig, mUseIncSupp);
95        if (id == 0) {
96            throw new RSDriverException("Failed to create KernelID");
97        }
98
99        k = new KernelID(id, mRS, this, slot, sig);
100
101        mKIDs.put(slot, k);
102        return k;
103    }
104
105    /**
106     * InvokeID is an identifier for a invoke function. It is used
107     * as an identifier for ScriptGroup creation.
108     *
109     * This class should not be directly created. Instead use the method in the
110     * reflected or intrinsic code "getInvokeID_funcname()".
111     *
112     */
113    public static final class InvokeID extends BaseObj {
114        Script mScript;
115        int mSlot;
116        InvokeID(long id, RenderScript rs, Script s, int slot) {
117            super(id, rs);
118            mScript = s;
119            mSlot = slot;
120        }
121    }
122
123    private final SparseArray<InvokeID> mIIDs = new SparseArray<InvokeID>();
124    /**
125     * Only to be used by generated reflected classes.
126     */
127    protected InvokeID createInvokeID(int slot) {
128        InvokeID i = mIIDs.get(slot);
129        if (i != null) {
130            return i;
131        }
132
133        long id = mRS.nScriptInvokeIDCreate(getID(mRS), slot);
134        if (id == 0) {
135            throw new RSDriverException("Failed to create KernelID");
136        }
137
138        i = new InvokeID(id, mRS, this, slot);
139        mIIDs.put(slot, i);
140        return i;
141    }
142
143    /**
144     * FieldID is an identifier for a Script + exported field pair. It is used
145     * as an identifier for ScriptGroup creation.
146     *
147     * This class should not be directly created. Instead use the method in the
148     * reflected or intrinsic code "getFieldID_funcname()".
149     *
150     */
151    public static final class FieldID extends BaseObj {
152        android.renderscript.Script.FieldID mN;
153        Script mScript;
154        int mSlot;
155        FieldID(long id, RenderScript rs, Script s, int slot) {
156            super(id, rs);
157            mScript = s;
158            mSlot = slot;
159        }
160    }
161
162    private final SparseArray<FieldID> mFIDs = new SparseArray();
163    /**
164     * Only to be used by generated reflected classes.
165     *
166     * @param slot
167     * @param e
168     *
169     * @return FieldID
170     */
171    protected FieldID createFieldID(int slot, Element e) {
172        FieldID f = mFIDs.get(slot);
173        if (f != null) {
174            return f;
175        }
176
177        long id = mRS.nScriptFieldIDCreate(getID(mRS), slot, mUseIncSupp);
178        if (id == 0) {
179            throw new RSDriverException("Failed to create FieldID");
180        }
181
182        f = new FieldID(id, mRS, this, slot);
183        mFIDs.put(slot, f);
184        return f;
185    }
186
187    /**
188     * Only intended for use by generated reflected code.
189     *
190     * @param slot
191     */
192    protected void invoke(int slot) {
193        mRS.nScriptInvoke(getID(mRS), slot, mUseIncSupp);
194    }
195
196    /**
197     * Only intended for use by generated reflected code.
198     *
199     * @param slot
200     * @param v
201     */
202    protected void invoke(int slot, FieldPacker v) {
203        if (v != null) {
204            mRS.nScriptInvokeV(getID(mRS), slot, v.getData(), mUseIncSupp);
205        } else {
206            mRS.nScriptInvoke(getID(mRS), slot, mUseIncSupp);
207        }
208    }
209
210    /**
211     * Only intended for use by generated reflected code.
212     *
213     * @param va
214     * @param slot
215     */
216    public void bindAllocation(Allocation va, int slot) {
217        mRS.validate();
218        if (va != null) {
219            mRS.nScriptBindAllocation(getID(mRS), va.getID(mRS), slot, mUseIncSupp);
220        } else {
221            mRS.nScriptBindAllocation(getID(mRS), 0, slot, mUseIncSupp);
222        }
223    }
224
225    public void setTimeZone(String timeZone) {
226        mRS.validate();
227        try {
228            mRS.nScriptSetTimeZone(getID(mRS), timeZone.getBytes("UTF-8"), mUseIncSupp);
229        } catch (java.io.UnsupportedEncodingException e) {
230            throw new RuntimeException(e);
231        }
232    }
233
234
235    /**
236     * Only intended for use by generated reflected code.
237     *
238     * @param slot
239     * @param ain
240     * @param aout
241     * @param v
242     */
243    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v) {
244        if (ain == null && aout == null) {
245            throw new RSIllegalArgumentException(
246                "At least one of ain or aout is required to be non-null.");
247        }
248        long in_id = 0;
249        long out_id = 0;
250        if (ain != null) {
251            in_id = ain.getID(mRS);
252        }
253        if (aout != null) {
254            out_id = aout.getID(mRS);
255        }
256
257        byte[] params = null;
258        if (v != null) {
259            params = v.getData();
260        }
261
262        if (mUseIncSupp) {
263            long ainInc = getDummyAlloc(ain);
264            long aoutInc = getDummyAlloc(aout);
265            mRS.nScriptForEach(getID(mRS), slot, ainInc, aoutInc, params, mUseIncSupp);
266        } else {
267            mRS.nScriptForEach(getID(mRS), slot, in_id, out_id, params, mUseIncSupp);
268        }
269    }
270
271    /**
272     * Only intended for use by generated reflected code.
273     *
274     * @param slot
275     * @param ain
276     * @param aout
277     * @param v
278     * @param sc
279     */
280    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v, LaunchOptions sc) {
281        if (ain == null && aout == null) {
282            throw new RSIllegalArgumentException(
283                "At least one of ain or aout is required to be non-null.");
284        }
285
286        if (sc == null) {
287            forEach(slot, ain, aout, v);
288            return;
289        }
290        long in_id = 0;
291        long out_id = 0;
292        if (ain != null) {
293            in_id = ain.getID(mRS);
294        }
295        if (aout != null) {
296            out_id = aout.getID(mRS);
297        }
298
299        byte[] params = null;
300        if (v != null) {
301            params = v.getData();
302        }
303        if (mUseIncSupp) {
304            long ainInc = getDummyAlloc(ain);
305            long aoutInc = getDummyAlloc(aout);
306            mRS.nScriptForEachClipped(getID(mRS), slot, ainInc, aoutInc, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend, mUseIncSupp);
307        } else {
308            mRS.nScriptForEachClipped(getID(mRS), slot, in_id, out_id, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend, mUseIncSupp);
309        }
310    }
311
312    Script(long id, RenderScript rs) {
313        super(id, rs);
314        mUseIncSupp = false;
315    }
316
317    /**
318     * Only intended for use by generated reflected code.
319     *
320     * @param index
321     * @param v
322     */
323    public void setVar(int index, float v) {
324        mRS.nScriptSetVarF(getID(mRS), index, v, mUseIncSupp);
325    }
326
327    /**
328     * Only intended for use by generated reflected code.
329     *
330     * @param index
331     * @param v
332     */
333    public void setVar(int index, double v) {
334        mRS.nScriptSetVarD(getID(mRS), index, v, mUseIncSupp);
335    }
336
337    /**
338     * Only intended for use by generated reflected code.
339     *
340     * @param index
341     * @param v
342     */
343    public void setVar(int index, int v) {
344        mRS.nScriptSetVarI(getID(mRS), index, v, mUseIncSupp);
345    }
346
347    /**
348     * Only intended for use by generated reflected code.
349     *
350     * @param index
351     * @param v
352     */
353    public void setVar(int index, long v) {
354        mRS.nScriptSetVarJ(getID(mRS), index, v, mUseIncSupp);
355    }
356
357    /**
358     * Only intended for use by generated reflected code.
359     *
360     * @param index
361     * @param v
362     */
363    public void setVar(int index, boolean v) {
364        mRS.nScriptSetVarI(getID(mRS), index, v ? 1 : 0, mUseIncSupp);
365    }
366
367    /**
368     * Only intended for use by generated reflected code.
369     *
370     * @param index
371     * @param o
372     */
373    public void setVar(int index, BaseObj o) {
374        if (mUseIncSupp) {
375            long oInc = getDummyAlloc((Allocation)o);
376            mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : oInc, mUseIncSupp);
377        } else {
378            mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : o.getID(mRS), mUseIncSupp);
379        }
380    }
381
382    /**
383     * Only intended for use by generated reflected code.
384     *
385     * @param index
386     * @param v
387     */
388    public void setVar(int index, FieldPacker v) {
389        mRS.nScriptSetVarV(getID(mRS), index, v.getData(), mUseIncSupp);
390    }
391
392    /**
393     * Only intended for use by generated reflected code.
394     *
395     * @param index
396     * @param v
397     * @param e
398     * @param dims
399     */
400    public void setVar(int index, FieldPacker v, Element e, int[] dims) {
401        if (mUseIncSupp) {
402            long dElement = e.getDummyElement(mRS);
403            mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), dElement, dims, mUseIncSupp);
404        } else {
405            mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), e.getID(mRS), dims, mUseIncSupp);
406        }
407    }
408
409    /**
410     * Only intended for use by generated reflected code.
411     *
412     */
413    public static class Builder {
414        RenderScript mRS;
415
416        Builder(RenderScript rs) {
417            mRS = rs;
418        }
419    }
420
421
422    /**
423     * Only intended for use by generated reflected code.
424     *
425     */
426    public static class FieldBase {
427        protected Element mElement;
428        protected Allocation mAllocation;
429
430        protected void init(RenderScript rs, int dimx) {
431            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT);
432        }
433
434        protected void init(RenderScript rs, int dimx, int usages) {
435            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT | usages);
436        }
437
438        protected FieldBase() {
439        }
440
441        public Element getElement() {
442            return mElement;
443        }
444
445        public Type getType() {
446            return mAllocation.getType();
447        }
448
449        public Allocation getAllocation() {
450            return mAllocation;
451        }
452
453        //@Override
454        public void updateAllocation() {
455        }
456    }
457
458
459    /**
460     * Class used to specify clipping for a kernel launch.
461     *
462     */
463    public static final class LaunchOptions {
464        private int xstart = 0;
465        private int ystart = 0;
466        private int xend = 0;
467        private int yend = 0;
468        private int zstart = 0;
469        private int zend = 0;
470        private int strategy;
471
472        /**
473         * Set the X range.  If the end value is set to 0 the X dimension is not
474         * clipped.
475         *
476         * @param xstartArg Must be >= 0
477         * @param xendArg Must be >= xstartArg
478         *
479         * @return LaunchOptions
480         */
481        public LaunchOptions setX(int xstartArg, int xendArg) {
482            if (xstartArg < 0 || xendArg <= xstartArg) {
483                throw new RSIllegalArgumentException("Invalid dimensions");
484            }
485            xstart = xstartArg;
486            xend = xendArg;
487            return this;
488        }
489
490        /**
491         * Set the Y range.  If the end value is set to 0 the Y dimension is not
492         * clipped.
493         *
494         * @param ystartArg Must be >= 0
495         * @param yendArg Must be >= ystartArg
496         *
497         * @return LaunchOptions
498         */
499        public LaunchOptions setY(int ystartArg, int yendArg) {
500            if (ystartArg < 0 || yendArg <= ystartArg) {
501                throw new RSIllegalArgumentException("Invalid dimensions");
502            }
503            ystart = ystartArg;
504            yend = yendArg;
505            return this;
506        }
507
508        /**
509         * Set the Z range.  If the end value is set to 0 the Z dimension is not
510         * clipped.
511         *
512         * @param zstartArg Must be >= 0
513         * @param zendArg Must be >= zstartArg
514         *
515         * @return LaunchOptions
516         */
517        public LaunchOptions setZ(int zstartArg, int zendArg) {
518            if (zstartArg < 0 || zendArg <= zstartArg) {
519                throw new RSIllegalArgumentException("Invalid dimensions");
520            }
521            zstart = zstartArg;
522            zend = zendArg;
523            return this;
524        }
525
526
527        /**
528         * Returns the current X start
529         *
530         * @return int current value
531         */
532        public int getXStart() {
533            return xstart;
534        }
535        /**
536         * Returns the current X end
537         *
538         * @return int current value
539         */
540        public int getXEnd() {
541            return xend;
542        }
543        /**
544         * Returns the current Y start
545         *
546         * @return int current value
547         */
548        public int getYStart() {
549            return ystart;
550        }
551        /**
552         * Returns the current Y end
553         *
554         * @return int current value
555         */
556        public int getYEnd() {
557            return yend;
558        }
559        /**
560         * Returns the current Z start
561         *
562         * @return int current value
563         */
564        public int getZStart() {
565            return zstart;
566        }
567        /**
568         * Returns the current Z end
569         *
570         * @return int current value
571         */
572        public int getZEnd() {
573            return zend;
574        }
575
576    }
577}
578