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