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