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