Element.java revision 347697710d033036c533bd6cee409c4b4c19d437
1/*
2 * Copyright (C) 2008 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>The most basic data type. An element represents one cell of a memory allocation.
24 * Element is the basic data type of Renderscript. An element can be of two forms: Basic elements or Complex forms.
25 * Examples of basic elements are:</p>
26 * <ul>
27 *  <li>Single float value</li>
28 *  <li>4 element float vector</li>
29 *  <li>single RGB-565 color</li>
30 *  <li>single unsigned int 16</li>
31 * </ul>
32 * <p>Complex elements contain a list of sub-elements and names that
33 * represents a structure of data. The fields can be accessed by name
34 * from a script or shader. The memory layout is defined and ordered. Data
35 * alignment is determinied by the most basic primitive type. i.e. a float4
36 * vector will be alligned to sizeof(float) and not sizeof(float4).  The
37 * ordering of elements in memory will be the order in which they were added
38 * with each component aligned as necessary. No re-ordering will be done.</p>
39 *
40 * <p>The primary source of elements are from scripts. A script that exports a
41 * bind point for a data structure generates a Renderscript element to represent the
42 * data exported by the script. The other common source of elements is from bitmap formats.</p>
43 **/
44public class Element extends BaseObj {
45    int mSize;
46    Element[] mElements;
47    String[] mElementNames;
48    int[] mArraySizes;
49
50    DataType mType;
51    DataKind mKind;
52    boolean mNormalized;
53    int mVectorSize;
54
55    int getSizeBytes() {return mSize;}
56
57
58    /**
59     * DataType represents the basic type information for a basic element.  The
60     * naming convention follows.  For numeric types its FLOAT, SIGNED, UNSIGNED
61     * followed by the _BITS where BITS is the size of the data.  BOOLEAN is a
62     * true / false (1,0) represented in an 8 bit container.  The UNSIGNED
63     * variants with multiple bit definitions are for packed graphical data
64     * formats and represents vectors with per vector member sizes which are
65     * treated as a single unit for packing and alignment purposes.
66     *
67     * MATRIX the three matrix types contain FLOAT_32 elements and are treated
68     * as 32 bits for alignment purposes.
69     *
70     * RS_* objects.  32 bit opaque handles.
71     */
72    public enum DataType {
73        //FLOAT_16 (1, 2),
74        FLOAT_32 (2, 4),
75        FLOAT_64 (3, 8),
76        SIGNED_8 (4, 1),
77        SIGNED_16 (5, 2),
78        SIGNED_32 (6, 4),
79        SIGNED_64 (7, 8),
80        UNSIGNED_8 (8, 1),
81        UNSIGNED_16 (9, 2),
82        UNSIGNED_32 (10, 4),
83        UNSIGNED_64 (11, 8),
84
85        BOOLEAN(12, 1),
86
87        UNSIGNED_5_6_5 (13, 2),
88        UNSIGNED_5_5_5_1 (14, 2),
89        UNSIGNED_4_4_4_4 (15, 2),
90
91        MATRIX_4X4 (16, 64),
92        MATRIX_3X3 (17, 36),
93        MATRIX_2X2 (18, 16),
94
95        RS_ELEMENT (1000, 4),
96        RS_TYPE (1001, 4),
97        RS_ALLOCATION (1002, 4),
98        RS_SAMPLER (1003, 4),
99        RS_SCRIPT (1004, 4),
100        RS_MESH (1005, 4),
101        RS_PROGRAM_FRAGMENT (1006, 4),
102        RS_PROGRAM_VERTEX (1007, 4),
103        RS_PROGRAM_RASTER (1008, 4),
104        RS_PROGRAM_STORE (1009, 4);
105
106        int mID;
107        int mSize;
108        DataType(int id, int size) {
109            mID = id;
110            mSize = size;
111        }
112    }
113
114    /**
115     * The special interpretation of the data if required.  This is primarly
116     * useful for graphical data.  USER indicates no special interpretation is
117     * expected.  PIXEL is used in conjunction with the standard data types for
118     * representing texture formats.
119     */
120    public enum DataKind {
121        USER (0),
122
123        PIXEL_L (7),
124        PIXEL_A (8),
125        PIXEL_LA (9),
126        PIXEL_RGB (10),
127        PIXEL_RGBA (11);
128
129        int mID;
130        DataKind(int id) {
131            mID = id;
132        }
133    }
134
135    /**
136     * Return if a element is too complex for use as a data source for a Mesh or
137     * a Program.
138     *
139     * @return boolean
140     */
141    public boolean isComplex() {
142        if (mElements == null) {
143            return false;
144        }
145        for (int ct=0; ct < mElements.length; ct++) {
146            if (mElements[ct].mElements != null) {
147                return true;
148            }
149        }
150        return false;
151    }
152
153    /**
154     * Utility function for returning an Element containing a single Boolean.
155     *
156     * @param rs Context to which the element will belong.
157     *
158     * @return Element
159     */
160    public static Element BOOLEAN(RenderScript rs) {
161        if(rs.mElement_BOOLEAN == null) {
162            rs.mElement_BOOLEAN = createUser(rs, DataType.BOOLEAN);
163        }
164        return rs.mElement_BOOLEAN;
165    }
166
167    /**
168     * Utility function for returning an Element containing a single UNSIGNED_8.
169     *
170     * @param rs Context to which the element will belong.
171     *
172     * @return Element
173     */
174    public static Element U8(RenderScript rs) {
175        if(rs.mElement_U8 == null) {
176            rs.mElement_U8 = createUser(rs, DataType.UNSIGNED_8);
177        }
178        return rs.mElement_U8;
179    }
180
181    /**
182     * Utility function for returning an Element containing a single SIGNED_8.
183     *
184     * @param rs Context to which the element will belong.
185     *
186     * @return Element
187     */
188    public static Element I8(RenderScript rs) {
189        if(rs.mElement_I8 == null) {
190            rs.mElement_I8 = createUser(rs, DataType.SIGNED_8);
191        }
192        return rs.mElement_I8;
193    }
194
195    public static Element U16(RenderScript rs) {
196        if(rs.mElement_U16 == null) {
197            rs.mElement_U16 = createUser(rs, DataType.UNSIGNED_16);
198        }
199        return rs.mElement_U16;
200    }
201
202    public static Element I16(RenderScript rs) {
203        if(rs.mElement_I16 == null) {
204            rs.mElement_I16 = createUser(rs, DataType.SIGNED_16);
205        }
206        return rs.mElement_I16;
207    }
208
209    public static Element U32(RenderScript rs) {
210        if(rs.mElement_U32 == null) {
211            rs.mElement_U32 = createUser(rs, DataType.UNSIGNED_32);
212        }
213        return rs.mElement_U32;
214    }
215
216    public static Element I32(RenderScript rs) {
217        if(rs.mElement_I32 == null) {
218            rs.mElement_I32 = createUser(rs, DataType.SIGNED_32);
219        }
220        return rs.mElement_I32;
221    }
222
223    public static Element U64(RenderScript rs) {
224        if(rs.mElement_U64 == null) {
225            rs.mElement_U64 = createUser(rs, DataType.UNSIGNED_64);
226        }
227        return rs.mElement_U64;
228    }
229
230    public static Element I64(RenderScript rs) {
231        if(rs.mElement_I64 == null) {
232            rs.mElement_I64 = createUser(rs, DataType.SIGNED_64);
233        }
234        return rs.mElement_I64;
235    }
236
237    public static Element F32(RenderScript rs) {
238        if(rs.mElement_F32 == null) {
239            rs.mElement_F32 = createUser(rs, DataType.FLOAT_32);
240        }
241        return rs.mElement_F32;
242    }
243
244    public static Element F64(RenderScript rs) {
245        if(rs.mElement_F64 == null) {
246            rs.mElement_F64 = createUser(rs, DataType.FLOAT_64);
247        }
248        return rs.mElement_F64;
249    }
250
251    public static Element ELEMENT(RenderScript rs) {
252        if(rs.mElement_ELEMENT == null) {
253            rs.mElement_ELEMENT = createUser(rs, DataType.RS_ELEMENT);
254        }
255        return rs.mElement_ELEMENT;
256    }
257
258    public static Element TYPE(RenderScript rs) {
259        if(rs.mElement_TYPE == null) {
260            rs.mElement_TYPE = createUser(rs, DataType.RS_TYPE);
261        }
262        return rs.mElement_TYPE;
263    }
264
265    public static Element ALLOCATION(RenderScript rs) {
266        if(rs.mElement_ALLOCATION == null) {
267            rs.mElement_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION);
268        }
269        return rs.mElement_ALLOCATION;
270    }
271
272    public static Element SAMPLER(RenderScript rs) {
273        if(rs.mElement_SAMPLER == null) {
274            rs.mElement_SAMPLER = createUser(rs, DataType.RS_SAMPLER);
275        }
276        return rs.mElement_SAMPLER;
277    }
278
279    public static Element SCRIPT(RenderScript rs) {
280        if(rs.mElement_SCRIPT == null) {
281            rs.mElement_SCRIPT = createUser(rs, DataType.RS_SCRIPT);
282        }
283        return rs.mElement_SCRIPT;
284    }
285
286    public static Element MESH(RenderScript rs) {
287        if(rs.mElement_MESH == null) {
288            rs.mElement_MESH = createUser(rs, DataType.RS_MESH);
289        }
290        return rs.mElement_MESH;
291    }
292
293    public static Element PROGRAM_FRAGMENT(RenderScript rs) {
294        if(rs.mElement_PROGRAM_FRAGMENT == null) {
295            rs.mElement_PROGRAM_FRAGMENT = createUser(rs, DataType.RS_PROGRAM_FRAGMENT);
296        }
297        return rs.mElement_PROGRAM_FRAGMENT;
298    }
299
300    public static Element PROGRAM_VERTEX(RenderScript rs) {
301        if(rs.mElement_PROGRAM_VERTEX == null) {
302            rs.mElement_PROGRAM_VERTEX = createUser(rs, DataType.RS_PROGRAM_VERTEX);
303        }
304        return rs.mElement_PROGRAM_VERTEX;
305    }
306
307    public static Element PROGRAM_RASTER(RenderScript rs) {
308        if(rs.mElement_PROGRAM_RASTER == null) {
309            rs.mElement_PROGRAM_RASTER = createUser(rs, DataType.RS_PROGRAM_RASTER);
310        }
311        return rs.mElement_PROGRAM_RASTER;
312    }
313
314    public static Element PROGRAM_STORE(RenderScript rs) {
315        if(rs.mElement_PROGRAM_STORE == null) {
316            rs.mElement_PROGRAM_STORE = createUser(rs, DataType.RS_PROGRAM_STORE);
317        }
318        return rs.mElement_PROGRAM_STORE;
319    }
320
321
322    public static Element A_8(RenderScript rs) {
323        if(rs.mElement_A_8 == null) {
324            rs.mElement_A_8 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_A);
325        }
326        return rs.mElement_A_8;
327    }
328
329    public static Element RGB_565(RenderScript rs) {
330        if(rs.mElement_RGB_565 == null) {
331            rs.mElement_RGB_565 = createPixel(rs, DataType.UNSIGNED_5_6_5, DataKind.PIXEL_RGB);
332        }
333        return rs.mElement_RGB_565;
334    }
335
336    public static Element RGB_888(RenderScript rs) {
337        if(rs.mElement_RGB_888 == null) {
338            rs.mElement_RGB_888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGB);
339        }
340        return rs.mElement_RGB_888;
341    }
342
343    public static Element RGBA_5551(RenderScript rs) {
344        if(rs.mElement_RGBA_5551 == null) {
345            rs.mElement_RGBA_5551 = createPixel(rs, DataType.UNSIGNED_5_5_5_1, DataKind.PIXEL_RGBA);
346        }
347        return rs.mElement_RGBA_5551;
348    }
349
350    public static Element RGBA_4444(RenderScript rs) {
351        if(rs.mElement_RGBA_4444 == null) {
352            rs.mElement_RGBA_4444 = createPixel(rs, DataType.UNSIGNED_4_4_4_4, DataKind.PIXEL_RGBA);
353        }
354        return rs.mElement_RGBA_4444;
355    }
356
357    public static Element RGBA_8888(RenderScript rs) {
358        if(rs.mElement_RGBA_8888 == null) {
359            rs.mElement_RGBA_8888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGBA);
360        }
361        return rs.mElement_RGBA_8888;
362    }
363
364    public static Element F32_2(RenderScript rs) {
365        if(rs.mElement_FLOAT_2 == null) {
366            rs.mElement_FLOAT_2 = createVector(rs, DataType.FLOAT_32, 2);
367        }
368        return rs.mElement_FLOAT_2;
369    }
370
371    public static Element F32_3(RenderScript rs) {
372        if(rs.mElement_FLOAT_3 == null) {
373            rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_32, 3);
374        }
375        return rs.mElement_FLOAT_3;
376    }
377
378    public static Element F32_4(RenderScript rs) {
379        if(rs.mElement_FLOAT_4 == null) {
380            rs.mElement_FLOAT_4 = createVector(rs, DataType.FLOAT_32, 4);
381        }
382        return rs.mElement_FLOAT_4;
383    }
384
385    public static Element U8_4(RenderScript rs) {
386        if(rs.mElement_UCHAR_4 == null) {
387            rs.mElement_UCHAR_4 = createVector(rs, DataType.UNSIGNED_8, 4);
388        }
389        return rs.mElement_UCHAR_4;
390    }
391
392    public static Element MATRIX_4X4(RenderScript rs) {
393        if(rs.mElement_MATRIX_4X4 == null) {
394            rs.mElement_MATRIX_4X4 = createUser(rs, DataType.MATRIX_4X4);
395        }
396        return rs.mElement_MATRIX_4X4;
397    }
398    public static Element MATRIX4X4(RenderScript rs) {
399        return MATRIX_4X4(rs);
400    }
401
402    public static Element MATRIX_3X3(RenderScript rs) {
403        if(rs.mElement_MATRIX_3X3 == null) {
404            rs.mElement_MATRIX_3X3 = createUser(rs, DataType.MATRIX_3X3);
405        }
406        return rs.mElement_MATRIX_3X3;
407    }
408
409    public static Element MATRIX_2X2(RenderScript rs) {
410        if(rs.mElement_MATRIX_2X2 == null) {
411            rs.mElement_MATRIX_2X2 = createUser(rs, DataType.MATRIX_2X2);
412        }
413        return rs.mElement_MATRIX_2X2;
414    }
415
416    Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) {
417        super(id, rs);
418        mSize = 0;
419        mElements = e;
420        mElementNames = n;
421        mArraySizes = as;
422        for (int ct = 0; ct < mElements.length; ct++ ) {
423            mSize += mElements[ct].mSize * mArraySizes[ct];
424        }
425    }
426
427    Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
428        super(id, rs);
429        if ((dt != DataType.UNSIGNED_5_6_5) &&
430            (dt != DataType.UNSIGNED_4_4_4_4) &&
431            (dt != DataType.UNSIGNED_5_5_5_1)) {
432            mSize = dt.mSize * size;
433        } else {
434            mSize = dt.mSize;
435        }
436        mType = dt;
437        mKind = dk;
438        mNormalized = norm;
439        mVectorSize = size;
440    }
441
442    Element(int id, RenderScript rs) {
443        super(id, rs);
444    }
445
446    @Override
447    void updateFromNative() {
448        super.updateFromNative();
449
450        // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
451        int[] dataBuffer = new int[5];
452        mRS.nElementGetNativeData(getID(), dataBuffer);
453
454        mNormalized = dataBuffer[2] == 1 ? true : false;
455        mVectorSize = dataBuffer[3];
456        mSize = 0;
457        for (DataType dt: DataType.values()) {
458            if(dt.mID == dataBuffer[0]){
459                mType = dt;
460                mSize = mType.mSize * mVectorSize;
461            }
462        }
463        for (DataKind dk: DataKind.values()) {
464            if(dk.mID == dataBuffer[1]){
465                mKind = dk;
466            }
467        }
468
469        int numSubElements = dataBuffer[4];
470        if(numSubElements > 0) {
471            mElements = new Element[numSubElements];
472            mElementNames = new String[numSubElements];
473
474            int[] subElementIds = new int[numSubElements];
475            mRS.nElementGetSubElements(getID(), subElementIds, mElementNames);
476            for(int i = 0; i < numSubElements; i ++) {
477                mElements[i] = new Element(subElementIds[i], mRS);
478                mElements[i].updateFromNative();
479                mSize += mElements[i].mSize;
480            }
481        }
482
483    }
484
485    /**
486     * Create a custom Element of the specified DataType.  The DataKind will be
487     * set to USER and the vector size to 1 indicating non-vector.
488     *
489     * @param rs The context associated with the new Element.
490     * @param dt The DataType for the new element.
491     * @return Element
492     */
493    static Element createUser(RenderScript rs, DataType dt) {
494        DataKind dk = DataKind.USER;
495        boolean norm = false;
496        int vecSize = 1;
497        int id = rs.nElementCreate(dt.mID, dk.mID, norm, vecSize);
498        return new Element(id, rs, dt, dk, norm, vecSize);
499    }
500
501    /**
502     * Create a custom vector element of the specified DataType and vector size.
503     *  DataKind will be set to USER.
504     *
505     * @param rs The context associated with the new Element.
506     * @param dt The DataType for the new element.
507     * @param size Vector size for the new Element.  Range 2-4 inclusive
508     *             supported.
509     *
510     * @return Element
511     */
512    public static Element createVector(RenderScript rs, DataType dt, int size) {
513        if (size < 2 || size > 4) {
514            throw new RSIllegalArgumentException("Vector size out of range 2-4.");
515        }
516        DataKind dk = DataKind.USER;
517        boolean norm = false;
518        int id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
519        return new Element(id, rs, dt, dk, norm, size);
520    }
521
522    /**
523     * Create a new pixel Element type.  A matching DataType and DataKind must
524     * be provided.  The DataType and DataKind must contain the same number of
525     * components.  Vector size will be set to 1.
526     *
527     * @param rs The context associated with the new Element.
528     * @param dt The DataType for the new element.
529     * @param dk The DataKind to specify the mapping of each component in the
530     *           DataType.
531     *
532     * @return Element
533     */
534    public static Element createPixel(RenderScript rs, DataType dt, DataKind dk) {
535        if (!(dk == DataKind.PIXEL_L ||
536              dk == DataKind.PIXEL_A ||
537              dk == DataKind.PIXEL_LA ||
538              dk == DataKind.PIXEL_RGB ||
539              dk == DataKind.PIXEL_RGBA)) {
540            throw new RSIllegalArgumentException("Unsupported DataKind");
541        }
542        if (!(dt == DataType.UNSIGNED_8 ||
543              dt == DataType.UNSIGNED_5_6_5 ||
544              dt == DataType.UNSIGNED_4_4_4_4 ||
545              dt == DataType.UNSIGNED_5_5_5_1)) {
546            throw new RSIllegalArgumentException("Unsupported DataType");
547        }
548        if (dt == DataType.UNSIGNED_5_6_5 && dk != DataKind.PIXEL_RGB) {
549            throw new RSIllegalArgumentException("Bad kind and type combo");
550        }
551        if (dt == DataType.UNSIGNED_5_5_5_1 && dk != DataKind.PIXEL_RGBA) {
552            throw new RSIllegalArgumentException("Bad kind and type combo");
553        }
554        if (dt == DataType.UNSIGNED_4_4_4_4 && dk != DataKind.PIXEL_RGBA) {
555            throw new RSIllegalArgumentException("Bad kind and type combo");
556        }
557
558        int size = 1;
559        if (dk == DataKind.PIXEL_LA) {
560            size = 2;
561        }
562        if (dk == DataKind.PIXEL_RGB) {
563            size = 3;
564        }
565        if (dk == DataKind.PIXEL_RGBA) {
566            size = 4;
567        }
568
569        boolean norm = true;
570        int id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
571        return new Element(id, rs, dt, dk, norm, size);
572    }
573
574    /**
575     * Builder class for producing complex elements with matching field and name
576     * pairs.  The builder starts empty.  The order in which elements are added
577     * is retained for the layout in memory.
578     *
579     */
580    public static class Builder {
581        RenderScript mRS;
582        Element[] mElements;
583        String[] mElementNames;
584        int[] mArraySizes;
585        int mCount;
586
587        /**
588         * Create a builder object.
589         *
590         * @param rs
591         */
592        public Builder(RenderScript rs) {
593            mRS = rs;
594            mCount = 0;
595            mElements = new Element[8];
596            mElementNames = new String[8];
597            mArraySizes = new int[8];
598        }
599
600        /**
601         * Add an array of elements to this element.
602         *
603         * @param element
604         * @param name
605         * @param arraySize
606         */
607        public Builder add(Element element, String name, int arraySize) {
608            if (arraySize < 1) {
609                throw new RSIllegalArgumentException("Array size cannot be less than 1.");
610            }
611            if(mCount == mElements.length) {
612                Element[] e = new Element[mCount + 8];
613                String[] s = new String[mCount + 8];
614                int[] as = new int[mCount + 8];
615                System.arraycopy(mElements, 0, e, 0, mCount);
616                System.arraycopy(mElementNames, 0, s, 0, mCount);
617                System.arraycopy(mArraySizes, 0, as, 0, mCount);
618                mElements = e;
619                mElementNames = s;
620                mArraySizes = as;
621            }
622            mElements[mCount] = element;
623            mElementNames[mCount] = name;
624            mArraySizes[mCount] = arraySize;
625            mCount++;
626            return this;
627        }
628
629        /**
630         * Add a single element to this Element.
631         *
632         * @param element
633         * @param name
634         */
635        public Builder add(Element element, String name) {
636            return add(element, name, 1);
637        }
638
639        /**
640         * Create the element from this builder.
641         *
642         *
643         * @return Element
644         */
645        public Element create() {
646            mRS.validate();
647            Element[] ein = new Element[mCount];
648            String[] sin = new String[mCount];
649            int[] asin = new int[mCount];
650            java.lang.System.arraycopy(mElements, 0, ein, 0, mCount);
651            java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
652            java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount);
653
654            int[] ids = new int[ein.length];
655            for (int ct = 0; ct < ein.length; ct++ ) {
656                ids[ct] = ein[ct].getID();
657            }
658            int id = mRS.nElementCreate2(ids, sin, asin);
659            return new Element(id, mRS, ein, sin, asin);
660        }
661    }
662}
663
664