1/*
2 * Copyright (C) 2013 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 java.lang.reflect.Field;
20import android.util.Log;
21
22/**
23 * <p>An Element represents one item within an {@link
24 * android.renderscript.Allocation}.  An Element is roughly equivalent to a C
25 * type in a RenderScript kernel. Elements may be basic or complex. Some basic
26 * elements are</p> <ul> <li>A single float value (equivalent to a float in a
27 * kernel)</li> <li>A four-element float vector (equivalent to a float4 in a
28 * kernel)</li> <li>An unsigned 32-bit integer (equivalent to an unsigned int in
29 * a kernel)</li> <li>A single signed 8-bit integer (equivalent to a char in a
30 * kernel)</li> </ul> <p>A complex element is roughly equivalent to a C struct
31 * and contains a number of basic or complex Elements. From Java code, a complex
32 * element contains a list of sub-elements and names that represents a
33 * particular data structure. Structs used in RS scripts are available to Java
34 * code by using the {@code ScriptField_structname} class that is reflected from
35 * a particular script.</p>
36 *
37 * <p>Basic Elements are comprised of a {@link
38 * android.renderscript.Element.DataType} and a {@link
39 * android.renderscript.Element.DataKind}. The DataType encodes C type
40 * information of an Element, while the DataKind encodes how that Element should
41 * be interpreted by a {@link android.renderscript.Sampler}. Note that {@link
42 * android.renderscript.Allocation} objects with DataKind {@link
43 * android.renderscript.Element.DataKind#USER} cannot be used as input for a
44 * {@link android.renderscript.Sampler}. In general, {@link
45 * android.renderscript.Allocation} objects that are intended for use with a
46 * {@link android.renderscript.Sampler} should use bitmap-derived Elements such
47 * as {@link android.renderscript.Element#RGBA_8888} or {@link
48 * android.renderscript#Element.A_8}.</p>
49 *
50 * <div class="special reference">
51 * <h3>Developer Guides</h3>
52 * <p>For more information about creating an application that uses RenderScript, read the
53 * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p>
54 * </div>
55 **/
56public class Element extends BaseObj {
57    int mSize;
58    Element[] mElements;
59    String[] mElementNames;
60    int[] mArraySizes;
61    int[] mOffsetInBytes;
62
63    int[] mVisibleElementMap;
64
65    DataType mType;
66    DataKind mKind;
67    boolean mNormalized;
68    int mVectorSize;
69
70    private void updateVisibleSubElements() {
71        if (mElements == null) {
72            return;
73        }
74
75        int noPaddingFieldCount = 0;
76        int fieldCount = mElementNames.length;
77        // Find out how many elements are not padding
78        for (int ct = 0; ct < fieldCount; ct ++) {
79            if (mElementNames[ct].charAt(0) != '#') {
80                noPaddingFieldCount ++;
81            }
82        }
83        mVisibleElementMap = new int[noPaddingFieldCount];
84
85        // Make a map that points us at non-padding elements
86        for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) {
87            if (mElementNames[ct].charAt(0) != '#') {
88                mVisibleElementMap[ctNoPadding ++] = ct;
89            }
90        }
91    }
92
93    /**
94    * @return element size in bytes
95    */
96    public int getBytesSize() {return mSize;}
97
98    /**
99    * Returns the number of vector components. 2 for float2, 4 for
100    * float4, etc.
101    * @return element vector size
102    */
103    public int getVectorSize() {return mVectorSize;}
104
105
106    /**
107     * DataType represents the basic type information for a basic element.  The
108     * naming convention follows.  For numeric types it is FLOAT,
109     * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
110     * size of the data.  BOOLEAN is a true / false (1,0)
111     * represented in an 8 bit container.  The UNSIGNED variants
112     * with multiple bit definitions are for packed graphical data
113     * formats and represent vectors with per vector member sizes
114     * which are treated as a single unit for packing and alignment
115     * purposes.
116     *
117     * MATRIX the three matrix types contain FLOAT_32 elements and are treated
118     * as 32 bits for alignment purposes.
119     *
120     * RS_* objects.  32 bit opaque handles.
121     */
122    public enum DataType {
123        NONE (0, 0),
124        //FLOAT_16 (1, 2),
125        FLOAT_32 (2, 4),
126        FLOAT_64 (3, 8),
127        SIGNED_8 (4, 1),
128        SIGNED_16 (5, 2),
129        SIGNED_32 (6, 4),
130        SIGNED_64 (7, 8),
131        UNSIGNED_8 (8, 1),
132        UNSIGNED_16 (9, 2),
133        UNSIGNED_32 (10, 4),
134        UNSIGNED_64 (11, 8),
135
136        BOOLEAN(12, 1),
137
138        UNSIGNED_5_6_5 (13, 2),
139        UNSIGNED_5_5_5_1 (14, 2),
140        UNSIGNED_4_4_4_4 (15, 2),
141
142        MATRIX_4X4 (16, 64),
143        MATRIX_3X3 (17, 36),
144        MATRIX_2X2 (18, 16),
145
146        RS_ELEMENT (1000, 4),
147        RS_TYPE (1001, 4),
148        RS_ALLOCATION (1002, 4),
149        RS_SAMPLER (1003, 4),
150        RS_SCRIPT (1004, 4),
151        RS_MESH (1005, 4),
152        RS_PROGRAM_FRAGMENT (1006, 4),
153        RS_PROGRAM_VERTEX (1007, 4),
154        RS_PROGRAM_RASTER (1008, 4),
155        RS_PROGRAM_STORE (1009, 4),
156        RS_FONT (1010, 4);
157
158        int mID;
159        int mSize;
160        DataType(int id, int size) {
161            mID = id;
162            mSize = size;
163        }
164    }
165
166    /**
167     * The special interpretation of the data if required.  This is primarly
168     * useful for graphical data.  USER indicates no special interpretation is
169     * expected.  PIXEL is used in conjunction with the standard data types for
170     * representing texture formats.
171     */
172    public enum DataKind {
173        USER (0),
174
175        PIXEL_L (7),
176        PIXEL_A (8),
177        PIXEL_LA (9),
178        PIXEL_RGB (10),
179        PIXEL_RGBA (11),
180        PIXEL_DEPTH (12),
181        PIXEL_YUV(13);
182
183        int mID;
184        DataKind(int id) {
185            mID = id;
186        }
187    }
188
189    /**
190     * Return if a element is too complex for use as a data source for a Mesh or
191     * a Program.
192     *
193     * @return boolean
194     */
195    public boolean isComplex() {
196        if (mElements == null) {
197            return false;
198        }
199        for (int ct=0; ct < mElements.length; ct++) {
200            if (mElements[ct].mElements != null) {
201                return true;
202            }
203        }
204        return false;
205    }
206
207    /**
208    * Elements could be simple, such as an int or a float, or a
209    * structure with multiple sub elements, such as a collection of
210    * floats, float2, float4. This function returns zero for simple
211    * elements or the number of sub-elements otherwise.
212    * @return number of sub-elements in this element
213    */
214    public int getSubElementCount() {
215        if (mVisibleElementMap == null) {
216            return 0;
217        }
218        return mVisibleElementMap.length;
219    }
220
221    /**
222    * For complex elements, this function will return the
223    * sub-element at index
224    * @param index index of the sub-element to return
225    * @return sub-element in this element at given index
226    */
227    public Element getSubElement(int index) {
228        if (mVisibleElementMap == null) {
229            throw new RSIllegalArgumentException("Element contains no sub-elements");
230        }
231        if (index < 0 || index >= mVisibleElementMap.length) {
232            throw new RSIllegalArgumentException("Illegal sub-element index");
233        }
234        return mElements[mVisibleElementMap[index]];
235    }
236
237    /**
238    * For complex elements, this function will return the
239    * sub-element name at index
240    * @param index index of the sub-element
241    * @return sub-element in this element at given index
242    */
243    public String getSubElementName(int index) {
244        if (mVisibleElementMap == null) {
245            throw new RSIllegalArgumentException("Element contains no sub-elements");
246        }
247        if (index < 0 || index >= mVisibleElementMap.length) {
248            throw new RSIllegalArgumentException("Illegal sub-element index");
249        }
250        return mElementNames[mVisibleElementMap[index]];
251    }
252
253    /**
254    * For complex elements, some sub-elements could be statically
255    * sized arrays. This function will return the array size for
256    * sub-element at index
257    * @param index index of the sub-element
258    * @return array size of sub-element in this element at given index
259    */
260    public int getSubElementArraySize(int index) {
261        if (mVisibleElementMap == null) {
262            throw new RSIllegalArgumentException("Element contains no sub-elements");
263        }
264        if (index < 0 || index >= mVisibleElementMap.length) {
265            throw new RSIllegalArgumentException("Illegal sub-element index");
266        }
267        return mArraySizes[mVisibleElementMap[index]];
268    }
269
270    /**
271    * This function specifies the location of a sub-element within
272    * the element
273    * @param index index of the sub-element
274    * @return offset in bytes of sub-element in this element at given index
275    */
276    public int getSubElementOffsetBytes(int index) {
277        if (mVisibleElementMap == null) {
278            throw new RSIllegalArgumentException("Element contains no sub-elements");
279        }
280        if (index < 0 || index >= mVisibleElementMap.length) {
281            throw new RSIllegalArgumentException("Illegal sub-element index");
282        }
283        return mOffsetInBytes[mVisibleElementMap[index]];
284    }
285
286    /**
287    * @return element data type
288    */
289    public DataType getDataType() {
290        return mType;
291    }
292
293    /**
294    * @return element data kind
295    */
296    public DataKind getDataKind() {
297        return mKind;
298    }
299
300    /**
301     * Utility function for returning an Element containing a single Boolean.
302     *
303     * @param rs Context to which the element will belong.
304     *
305     * @return Element
306     */
307    public static Element BOOLEAN(RenderScript rs) {
308        if(rs.mElement_BOOLEAN == null) {
309            rs.mElement_BOOLEAN = createUser(rs, DataType.BOOLEAN);
310        }
311        return rs.mElement_BOOLEAN;
312    }
313
314    /**
315     * Utility function for returning an Element containing a single UNSIGNED_8.
316     *
317     * @param rs Context to which the element will belong.
318     *
319     * @return Element
320     */
321    public static Element U8(RenderScript rs) {
322        if(rs.mElement_U8 == null) {
323            rs.mElement_U8 = createUser(rs, DataType.UNSIGNED_8);
324        }
325        return rs.mElement_U8;
326    }
327
328    /**
329     * Utility function for returning an Element containing a single SIGNED_8.
330     *
331     * @param rs Context to which the element will belong.
332     *
333     * @return Element
334     */
335    public static Element I8(RenderScript rs) {
336        if(rs.mElement_I8 == null) {
337            rs.mElement_I8 = createUser(rs, DataType.SIGNED_8);
338        }
339        return rs.mElement_I8;
340    }
341
342    public static Element U16(RenderScript rs) {
343        if(rs.mElement_U16 == null) {
344            rs.mElement_U16 = createUser(rs, DataType.UNSIGNED_16);
345        }
346        return rs.mElement_U16;
347    }
348
349    public static Element I16(RenderScript rs) {
350        if(rs.mElement_I16 == null) {
351            rs.mElement_I16 = createUser(rs, DataType.SIGNED_16);
352        }
353        return rs.mElement_I16;
354    }
355
356    public static Element U32(RenderScript rs) {
357        if(rs.mElement_U32 == null) {
358            rs.mElement_U32 = createUser(rs, DataType.UNSIGNED_32);
359        }
360        return rs.mElement_U32;
361    }
362
363    public static Element I32(RenderScript rs) {
364        if(rs.mElement_I32 == null) {
365            rs.mElement_I32 = createUser(rs, DataType.SIGNED_32);
366        }
367        return rs.mElement_I32;
368    }
369
370    public static Element U64(RenderScript rs) {
371        if(rs.mElement_U64 == null) {
372            rs.mElement_U64 = createUser(rs, DataType.UNSIGNED_64);
373        }
374        return rs.mElement_U64;
375    }
376
377    public static Element I64(RenderScript rs) {
378        if(rs.mElement_I64 == null) {
379            rs.mElement_I64 = createUser(rs, DataType.SIGNED_64);
380        }
381        return rs.mElement_I64;
382    }
383
384    public static Element F32(RenderScript rs) {
385        if(rs.mElement_F32 == null) {
386            rs.mElement_F32 = createUser(rs, DataType.FLOAT_32);
387        }
388        return rs.mElement_F32;
389    }
390
391    public static Element F64(RenderScript rs) {
392        if(rs.mElement_F64 == null) {
393            rs.mElement_F64 = createUser(rs, DataType.FLOAT_64);
394        }
395        return rs.mElement_F64;
396    }
397
398    public static Element ELEMENT(RenderScript rs) {
399        if(rs.mElement_ELEMENT == null) {
400            rs.mElement_ELEMENT = createUser(rs, DataType.RS_ELEMENT);
401        }
402        return rs.mElement_ELEMENT;
403    }
404
405    public static Element TYPE(RenderScript rs) {
406        if(rs.mElement_TYPE == null) {
407            rs.mElement_TYPE = createUser(rs, DataType.RS_TYPE);
408        }
409        return rs.mElement_TYPE;
410    }
411
412    public static Element ALLOCATION(RenderScript rs) {
413        if(rs.mElement_ALLOCATION == null) {
414            rs.mElement_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION);
415        }
416        return rs.mElement_ALLOCATION;
417    }
418
419    public static Element SAMPLER(RenderScript rs) {
420        if(rs.mElement_SAMPLER == null) {
421            rs.mElement_SAMPLER = createUser(rs, DataType.RS_SAMPLER);
422        }
423        return rs.mElement_SAMPLER;
424    }
425
426    public static Element SCRIPT(RenderScript rs) {
427        if(rs.mElement_SCRIPT == null) {
428            rs.mElement_SCRIPT = createUser(rs, DataType.RS_SCRIPT);
429        }
430        return rs.mElement_SCRIPT;
431    }
432
433    public static Element MESH(RenderScript rs) {
434        if(rs.mElement_MESH == null) {
435            rs.mElement_MESH = createUser(rs, DataType.RS_MESH);
436        }
437        return rs.mElement_MESH;
438    }
439
440    public static Element PROGRAM_FRAGMENT(RenderScript rs) {
441        if(rs.mElement_PROGRAM_FRAGMENT == null) {
442            rs.mElement_PROGRAM_FRAGMENT = createUser(rs, DataType.RS_PROGRAM_FRAGMENT);
443        }
444        return rs.mElement_PROGRAM_FRAGMENT;
445    }
446
447    public static Element PROGRAM_VERTEX(RenderScript rs) {
448        if(rs.mElement_PROGRAM_VERTEX == null) {
449            rs.mElement_PROGRAM_VERTEX = createUser(rs, DataType.RS_PROGRAM_VERTEX);
450        }
451        return rs.mElement_PROGRAM_VERTEX;
452    }
453
454    public static Element PROGRAM_RASTER(RenderScript rs) {
455        if(rs.mElement_PROGRAM_RASTER == null) {
456            rs.mElement_PROGRAM_RASTER = createUser(rs, DataType.RS_PROGRAM_RASTER);
457        }
458        return rs.mElement_PROGRAM_RASTER;
459    }
460
461    public static Element PROGRAM_STORE(RenderScript rs) {
462        if(rs.mElement_PROGRAM_STORE == null) {
463            rs.mElement_PROGRAM_STORE = createUser(rs, DataType.RS_PROGRAM_STORE);
464        }
465        return rs.mElement_PROGRAM_STORE;
466    }
467
468    public static Element FONT(RenderScript rs) {
469        if(rs.mElement_FONT == null) {
470            rs.mElement_FONT = createUser(rs, DataType.RS_FONT);
471        }
472        return rs.mElement_FONT;
473    }
474
475
476    public static Element A_8(RenderScript rs) {
477        if(rs.mElement_A_8 == null) {
478            rs.mElement_A_8 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_A);
479        }
480        return rs.mElement_A_8;
481    }
482
483    public static Element RGB_565(RenderScript rs) {
484        if(rs.mElement_RGB_565 == null) {
485            rs.mElement_RGB_565 = createPixel(rs, DataType.UNSIGNED_5_6_5, DataKind.PIXEL_RGB);
486        }
487        return rs.mElement_RGB_565;
488    }
489
490    public static Element RGB_888(RenderScript rs) {
491        if(rs.mElement_RGB_888 == null) {
492            rs.mElement_RGB_888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGB);
493        }
494        return rs.mElement_RGB_888;
495    }
496
497    public static Element RGBA_5551(RenderScript rs) {
498        if(rs.mElement_RGBA_5551 == null) {
499            rs.mElement_RGBA_5551 = createPixel(rs, DataType.UNSIGNED_5_5_5_1, DataKind.PIXEL_RGBA);
500        }
501        return rs.mElement_RGBA_5551;
502    }
503
504    public static Element RGBA_4444(RenderScript rs) {
505        if(rs.mElement_RGBA_4444 == null) {
506            rs.mElement_RGBA_4444 = createPixel(rs, DataType.UNSIGNED_4_4_4_4, DataKind.PIXEL_RGBA);
507        }
508        return rs.mElement_RGBA_4444;
509    }
510
511    public static Element RGBA_8888(RenderScript rs) {
512        if(rs.mElement_RGBA_8888 == null) {
513            rs.mElement_RGBA_8888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGBA);
514        }
515        return rs.mElement_RGBA_8888;
516    }
517
518    public static Element F32_2(RenderScript rs) {
519        if(rs.mElement_FLOAT_2 == null) {
520            rs.mElement_FLOAT_2 = createVector(rs, DataType.FLOAT_32, 2);
521        }
522        return rs.mElement_FLOAT_2;
523    }
524
525    public static Element F32_3(RenderScript rs) {
526        if(rs.mElement_FLOAT_3 == null) {
527            rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_32, 3);
528        }
529        return rs.mElement_FLOAT_3;
530    }
531
532    public static Element F32_4(RenderScript rs) {
533        if(rs.mElement_FLOAT_4 == null) {
534            rs.mElement_FLOAT_4 = createVector(rs, DataType.FLOAT_32, 4);
535        }
536        return rs.mElement_FLOAT_4;
537    }
538
539    public static Element F64_2(RenderScript rs) {
540        if(rs.mElement_DOUBLE_2 == null) {
541            rs.mElement_DOUBLE_2 = createVector(rs, DataType.FLOAT_64, 2);
542        }
543        return rs.mElement_DOUBLE_2;
544    }
545
546    public static Element F64_3(RenderScript rs) {
547        if(rs.mElement_DOUBLE_3 == null) {
548            rs.mElement_DOUBLE_3 = createVector(rs, DataType.FLOAT_64, 3);
549        }
550        return rs.mElement_DOUBLE_3;
551    }
552
553    public static Element F64_4(RenderScript rs) {
554        if(rs.mElement_DOUBLE_4 == null) {
555            rs.mElement_DOUBLE_4 = createVector(rs, DataType.FLOAT_64, 4);
556        }
557        return rs.mElement_DOUBLE_4;
558    }
559
560    public static Element U8_2(RenderScript rs) {
561        if(rs.mElement_UCHAR_2 == null) {
562            rs.mElement_UCHAR_2 = createVector(rs, DataType.UNSIGNED_8, 2);
563        }
564        return rs.mElement_UCHAR_2;
565    }
566
567    public static Element U8_3(RenderScript rs) {
568        if(rs.mElement_UCHAR_3 == null) {
569            rs.mElement_UCHAR_3 = createVector(rs, DataType.UNSIGNED_8, 3);
570        }
571        return rs.mElement_UCHAR_3;
572    }
573
574    public static Element U8_4(RenderScript rs) {
575        if(rs.mElement_UCHAR_4 == null) {
576            rs.mElement_UCHAR_4 = createVector(rs, DataType.UNSIGNED_8, 4);
577        }
578        return rs.mElement_UCHAR_4;
579    }
580
581    public static Element I8_2(RenderScript rs) {
582        if(rs.mElement_CHAR_2 == null) {
583            rs.mElement_CHAR_2 = createVector(rs, DataType.SIGNED_8, 2);
584        }
585        return rs.mElement_CHAR_2;
586    }
587
588    public static Element I8_3(RenderScript rs) {
589        if(rs.mElement_CHAR_3 == null) {
590            rs.mElement_CHAR_3 = createVector(rs, DataType.SIGNED_8, 3);
591        }
592        return rs.mElement_CHAR_3;
593    }
594
595    public static Element I8_4(RenderScript rs) {
596        if(rs.mElement_CHAR_4 == null) {
597            rs.mElement_CHAR_4 = createVector(rs, DataType.SIGNED_8, 4);
598        }
599        return rs.mElement_CHAR_4;
600    }
601
602    public static Element U16_2(RenderScript rs) {
603        if(rs.mElement_USHORT_2 == null) {
604            rs.mElement_USHORT_2 = createVector(rs, DataType.UNSIGNED_16, 2);
605        }
606        return rs.mElement_USHORT_2;
607    }
608
609    public static Element U16_3(RenderScript rs) {
610        if(rs.mElement_USHORT_3 == null) {
611            rs.mElement_USHORT_3 = createVector(rs, DataType.UNSIGNED_16, 3);
612        }
613        return rs.mElement_USHORT_3;
614    }
615
616    public static Element U16_4(RenderScript rs) {
617        if(rs.mElement_USHORT_4 == null) {
618            rs.mElement_USHORT_4 = createVector(rs, DataType.UNSIGNED_16, 4);
619        }
620        return rs.mElement_USHORT_4;
621    }
622
623    public static Element I16_2(RenderScript rs) {
624        if(rs.mElement_SHORT_2 == null) {
625            rs.mElement_SHORT_2 = createVector(rs, DataType.SIGNED_16, 2);
626        }
627        return rs.mElement_SHORT_2;
628    }
629
630    public static Element I16_3(RenderScript rs) {
631        if(rs.mElement_SHORT_3 == null) {
632            rs.mElement_SHORT_3 = createVector(rs, DataType.SIGNED_16, 3);
633        }
634        return rs.mElement_SHORT_3;
635    }
636
637    public static Element I16_4(RenderScript rs) {
638        if(rs.mElement_SHORT_4 == null) {
639            rs.mElement_SHORT_4 = createVector(rs, DataType.SIGNED_16, 4);
640        }
641        return rs.mElement_SHORT_4;
642    }
643
644    public static Element U32_2(RenderScript rs) {
645        if(rs.mElement_UINT_2 == null) {
646            rs.mElement_UINT_2 = createVector(rs, DataType.UNSIGNED_32, 2);
647        }
648        return rs.mElement_UINT_2;
649    }
650
651    public static Element U32_3(RenderScript rs) {
652        if(rs.mElement_UINT_3 == null) {
653            rs.mElement_UINT_3 = createVector(rs, DataType.UNSIGNED_32, 3);
654        }
655        return rs.mElement_UINT_3;
656    }
657
658    public static Element U32_4(RenderScript rs) {
659        if(rs.mElement_UINT_4 == null) {
660            rs.mElement_UINT_4 = createVector(rs, DataType.UNSIGNED_32, 4);
661        }
662        return rs.mElement_UINT_4;
663    }
664
665    public static Element I32_2(RenderScript rs) {
666        if(rs.mElement_INT_2 == null) {
667            rs.mElement_INT_2 = createVector(rs, DataType.SIGNED_32, 2);
668        }
669        return rs.mElement_INT_2;
670    }
671
672    public static Element I32_3(RenderScript rs) {
673        if(rs.mElement_INT_3 == null) {
674            rs.mElement_INT_3 = createVector(rs, DataType.SIGNED_32, 3);
675        }
676        return rs.mElement_INT_3;
677    }
678
679    public static Element I32_4(RenderScript rs) {
680        if(rs.mElement_INT_4 == null) {
681            rs.mElement_INT_4 = createVector(rs, DataType.SIGNED_32, 4);
682        }
683        return rs.mElement_INT_4;
684    }
685
686    public static Element U64_2(RenderScript rs) {
687        if(rs.mElement_ULONG_2 == null) {
688            rs.mElement_ULONG_2 = createVector(rs, DataType.UNSIGNED_64, 2);
689        }
690        return rs.mElement_ULONG_2;
691    }
692
693    public static Element U64_3(RenderScript rs) {
694        if(rs.mElement_ULONG_3 == null) {
695            rs.mElement_ULONG_3 = createVector(rs, DataType.UNSIGNED_64, 3);
696        }
697        return rs.mElement_ULONG_3;
698    }
699
700    public static Element U64_4(RenderScript rs) {
701        if(rs.mElement_ULONG_4 == null) {
702            rs.mElement_ULONG_4 = createVector(rs, DataType.UNSIGNED_64, 4);
703        }
704        return rs.mElement_ULONG_4;
705    }
706
707    public static Element I64_2(RenderScript rs) {
708        if(rs.mElement_LONG_2 == null) {
709            rs.mElement_LONG_2 = createVector(rs, DataType.SIGNED_64, 2);
710        }
711        return rs.mElement_LONG_2;
712    }
713
714    public static Element I64_3(RenderScript rs) {
715        if(rs.mElement_LONG_3 == null) {
716            rs.mElement_LONG_3 = createVector(rs, DataType.SIGNED_64, 3);
717        }
718        return rs.mElement_LONG_3;
719    }
720
721    public static Element I64_4(RenderScript rs) {
722        if(rs.mElement_LONG_4 == null) {
723            rs.mElement_LONG_4 = createVector(rs, DataType.SIGNED_64, 4);
724        }
725        return rs.mElement_LONG_4;
726    }
727
728    public static Element YUV(RenderScript rs) {
729        if (rs.mElement_YUV == null) {
730            rs.mElement_YUV = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_YUV);
731        }
732        return rs.mElement_YUV;
733    }
734
735    public static Element MATRIX_4X4(RenderScript rs) {
736        if(rs.mElement_MATRIX_4X4 == null) {
737            rs.mElement_MATRIX_4X4 = createUser(rs, DataType.MATRIX_4X4);
738        }
739        return rs.mElement_MATRIX_4X4;
740    }
741
742    /** @deprecated use MATRIX_4X4
743    */
744    public static Element MATRIX4X4(RenderScript rs) {
745        return MATRIX_4X4(rs);
746    }
747
748    public static Element MATRIX_3X3(RenderScript rs) {
749        if(rs.mElement_MATRIX_3X3 == null) {
750            rs.mElement_MATRIX_3X3 = createUser(rs, DataType.MATRIX_3X3);
751        }
752        return rs.mElement_MATRIX_3X3;
753    }
754
755    public static Element MATRIX_2X2(RenderScript rs) {
756        if(rs.mElement_MATRIX_2X2 == null) {
757            rs.mElement_MATRIX_2X2 = createUser(rs, DataType.MATRIX_2X2);
758        }
759        return rs.mElement_MATRIX_2X2;
760    }
761
762    Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) {
763        super(id, rs);
764        mSize = 0;
765        mVectorSize = 1;
766        mElements = e;
767        mElementNames = n;
768        mArraySizes = as;
769        mType = DataType.NONE;
770        mKind = DataKind.USER;
771        mOffsetInBytes = new int[mElements.length];
772        for (int ct = 0; ct < mElements.length; ct++ ) {
773            mOffsetInBytes[ct] = mSize;
774            mSize += mElements[ct].mSize * mArraySizes[ct];
775        }
776        updateVisibleSubElements();
777    }
778
779    Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
780        super(id, rs);
781        if ((dt != DataType.UNSIGNED_5_6_5) &&
782            (dt != DataType.UNSIGNED_4_4_4_4) &&
783            (dt != DataType.UNSIGNED_5_5_5_1)) {
784            if (size == 3) {
785                mSize = dt.mSize * 4;
786            } else {
787                mSize = dt.mSize * size;
788            }
789        } else {
790            mSize = dt.mSize;
791        }
792        mType = dt;
793        mKind = dk;
794        mNormalized = norm;
795        mVectorSize = size;
796    }
797
798    Element(int id, RenderScript rs) {
799        super(id, rs);
800    }
801
802    @Override
803    void updateFromNative() {
804        super.updateFromNative();
805
806        // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
807        int[] dataBuffer = new int[5];
808        mRS.nElementGetNativeData(getID(mRS), dataBuffer);
809
810        mNormalized = dataBuffer[2] == 1 ? true : false;
811        mVectorSize = dataBuffer[3];
812        mSize = 0;
813        for (DataType dt: DataType.values()) {
814            if(dt.mID == dataBuffer[0]){
815                mType = dt;
816                mSize = mType.mSize * mVectorSize;
817            }
818        }
819        for (DataKind dk: DataKind.values()) {
820            if(dk.mID == dataBuffer[1]){
821                mKind = dk;
822            }
823        }
824
825        int numSubElements = dataBuffer[4];
826        if(numSubElements > 0) {
827            mElements = new Element[numSubElements];
828            mElementNames = new String[numSubElements];
829            mArraySizes = new int[numSubElements];
830            mOffsetInBytes = new int[numSubElements];
831
832            int[] subElementIds = new int[numSubElements];
833            mRS.nElementGetSubElements(getID(mRS), subElementIds, mElementNames, mArraySizes);
834            for(int i = 0; i < numSubElements; i ++) {
835                mElements[i] = new Element(subElementIds[i], mRS);
836                mElements[i].updateFromNative();
837                mOffsetInBytes[i] = mSize;
838                mSize += mElements[i].mSize * mArraySizes[i];
839            }
840        }
841        updateVisibleSubElements();
842    }
843
844    /**
845     * Create a custom Element of the specified DataType.  The DataKind will be
846     * set to USER and the vector size to 1 indicating non-vector.
847     *
848     * @param rs The context associated with the new Element.
849     * @param dt The DataType for the new element.
850     * @return Element
851     */
852    static Element createUser(RenderScript rs, DataType dt) {
853        DataKind dk = DataKind.USER;
854        boolean norm = false;
855        int vecSize = 1;
856        int id = rs.nElementCreate(dt.mID, dk.mID, norm, vecSize);
857        return new Element(id, rs, dt, dk, norm, vecSize);
858    }
859
860    /**
861     * Create a custom vector element of the specified DataType and vector size.
862     * DataKind will be set to USER. Only primitive types (FLOAT_32, FLOAT_64,
863     * SIGNED_8, SIGNED_16, SIGNED_32, SIGNED_64, UNSIGNED_8, UNSIGNED_16,
864     * UNSIGNED_32, UNSIGNED_64, BOOLEAN) are supported.
865     *
866     * @param rs The context associated with the new Element.
867     * @param dt The DataType for the new Element.
868     * @param size Vector size for the new Element.  Range 2-4 inclusive
869     *             supported.
870     *
871     * @return Element
872     */
873    public static Element createVector(RenderScript rs, DataType dt, int size) {
874        if (size < 2 || size > 4) {
875            throw new RSIllegalArgumentException("Vector size out of range 2-4.");
876        }
877
878        switch (dt) {
879        // Support only primitive integer/float/boolean types as vectors.
880        case FLOAT_32:
881        case FLOAT_64:
882        case SIGNED_8:
883        case SIGNED_16:
884        case SIGNED_32:
885        case SIGNED_64:
886        case UNSIGNED_8:
887        case UNSIGNED_16:
888        case UNSIGNED_32:
889        case UNSIGNED_64:
890        case BOOLEAN: {
891            DataKind dk = DataKind.USER;
892            boolean norm = false;
893            int id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
894            return new Element(id, rs, dt, dk, norm, size);
895        }
896
897        default: {
898            throw new RSIllegalArgumentException("Cannot create vector of " +
899                "non-primitive type.");
900        }
901        }
902    }
903
904    /**
905     * Create a new pixel Element type.  A matching DataType and DataKind must
906     * be provided.  The DataType and DataKind must contain the same number of
907     * components.  Vector size will be set to 1.
908     *
909     * @param rs The context associated with the new Element.
910     * @param dt The DataType for the new element.
911     * @param dk The DataKind to specify the mapping of each component in the
912     *           DataType.
913     *
914     * @return Element
915     */
916    public static Element createPixel(RenderScript rs, DataType dt, DataKind dk) {
917        if (!(dk == DataKind.PIXEL_L ||
918              dk == DataKind.PIXEL_A ||
919              dk == DataKind.PIXEL_LA ||
920              dk == DataKind.PIXEL_RGB ||
921              dk == DataKind.PIXEL_RGBA ||
922              dk == DataKind.PIXEL_DEPTH ||
923              dk == DataKind.PIXEL_YUV)) {
924            throw new RSIllegalArgumentException("Unsupported DataKind");
925        }
926        if (!(dt == DataType.UNSIGNED_8 ||
927              dt == DataType.UNSIGNED_16 ||
928              dt == DataType.UNSIGNED_5_6_5 ||
929              dt == DataType.UNSIGNED_4_4_4_4 ||
930              dt == DataType.UNSIGNED_5_5_5_1)) {
931            throw new RSIllegalArgumentException("Unsupported DataType");
932        }
933        if (dt == DataType.UNSIGNED_5_6_5 && dk != DataKind.PIXEL_RGB) {
934            throw new RSIllegalArgumentException("Bad kind and type combo");
935        }
936        if (dt == DataType.UNSIGNED_5_5_5_1 && dk != DataKind.PIXEL_RGBA) {
937            throw new RSIllegalArgumentException("Bad kind and type combo");
938        }
939        if (dt == DataType.UNSIGNED_4_4_4_4 && dk != DataKind.PIXEL_RGBA) {
940            throw new RSIllegalArgumentException("Bad kind and type combo");
941        }
942        if (dt == DataType.UNSIGNED_16 &&
943            dk != DataKind.PIXEL_DEPTH) {
944            throw new RSIllegalArgumentException("Bad kind and type combo");
945        }
946
947        int size = 1;
948        switch (dk) {
949        case PIXEL_LA:
950            size = 2;
951            break;
952        case PIXEL_RGB:
953            size = 3;
954            break;
955        case PIXEL_RGBA:
956            size = 4;
957            break;
958        case PIXEL_DEPTH:
959            size = 2;
960            break;
961        }
962
963        boolean norm = true;
964        int id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
965        return new Element(id, rs, dt, dk, norm, size);
966    }
967
968    /**
969     * Check if the current Element is compatible with another Element.
970     * Primitive Elements are compatible if they share the same underlying
971     * size and type (i.e. U8 is compatible with A_8). User-defined Elements
972     * must be equal in order to be compatible. This requires strict name
973     * equivalence for all sub-Elements (in addition to structural equivalence).
974     *
975     * @param e The Element to check compatibility with.
976     *
977     * @return boolean true if the Elements are compatible, otherwise false.
978     */
979    public boolean isCompatible(Element e) {
980        // Try strict BaseObj equality to start with.
981        if (this.equals(e)) {
982            return true;
983        }
984
985        // Ignore mKind because it is allowed to be different (user vs. pixel).
986        // We also ignore mNormalized because it can be different. The mType
987        // field must not be NONE since we require name equivalence for
988        // all user-created Elements.
989        return ((mSize == e.mSize) &&
990                (mType != DataType.NONE) &&
991                (mType == e.mType) &&
992                (mVectorSize == e.mVectorSize));
993    }
994
995    /**
996     * Builder class for producing complex elements with matching field and name
997     * pairs.  The builder starts empty.  The order in which elements are added
998     * is retained for the layout in memory.
999     *
1000     */
1001    public static class Builder {
1002        RenderScript mRS;
1003        Element[] mElements;
1004        String[] mElementNames;
1005        int[] mArraySizes;
1006        int mCount;
1007        int mSkipPadding;
1008
1009        /**
1010         * Create a builder object.
1011         *
1012         * @param rs
1013         */
1014        public Builder(RenderScript rs) {
1015            mRS = rs;
1016            mCount = 0;
1017            mElements = new Element[8];
1018            mElementNames = new String[8];
1019            mArraySizes = new int[8];
1020        }
1021
1022        /**
1023         * Add an array of elements to this element.
1024         *
1025         * @param element
1026         * @param name
1027         * @param arraySize
1028         */
1029        public Builder add(Element element, String name, int arraySize) {
1030            if (arraySize < 1) {
1031                throw new RSIllegalArgumentException("Array size cannot be less than 1.");
1032            }
1033
1034            // Skip padding fields after a vector 3 type.
1035            if (mSkipPadding != 0) {
1036                if (name.startsWith("#padding_")) {
1037                    mSkipPadding = 0;
1038                    return this;
1039                }
1040            }
1041
1042            if (element.mVectorSize == 3) {
1043                mSkipPadding = 1;
1044            } else {
1045                mSkipPadding = 0;
1046            }
1047
1048            if(mCount == mElements.length) {
1049                Element[] e = new Element[mCount + 8];
1050                String[] s = new String[mCount + 8];
1051                int[] as = new int[mCount + 8];
1052                System.arraycopy(mElements, 0, e, 0, mCount);
1053                System.arraycopy(mElementNames, 0, s, 0, mCount);
1054                System.arraycopy(mArraySizes, 0, as, 0, mCount);
1055                mElements = e;
1056                mElementNames = s;
1057                mArraySizes = as;
1058            }
1059            mElements[mCount] = element;
1060            mElementNames[mCount] = name;
1061            mArraySizes[mCount] = arraySize;
1062            mCount++;
1063            return this;
1064        }
1065
1066        /**
1067         * Add a single element to this Element.
1068         *
1069         * @param element
1070         * @param name
1071         */
1072        public Builder add(Element element, String name) {
1073            return add(element, name, 1);
1074        }
1075
1076        /**
1077         * Create the element from this builder.
1078         *
1079         *
1080         * @return Element
1081         */
1082        public Element create() {
1083            mRS.validate();
1084            Element[] ein = new Element[mCount];
1085            String[] sin = new String[mCount];
1086            int[] asin = new int[mCount];
1087            java.lang.System.arraycopy(mElements, 0, ein, 0, mCount);
1088            java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
1089            java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount);
1090
1091            int[] ids = new int[ein.length];
1092            for (int ct = 0; ct < ein.length; ct++ ) {
1093                ids[ct] = ein[ct].getID(mRS);
1094            }
1095            int id = mRS.nElementCreate2(ids, sin, asin);
1096            return new Element(id, mRS, ein, sin, asin);
1097        }
1098    }
1099}
1100
1101