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