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
19/**
20 * <p>A Type describes the {@link android.renderscript.Element} and dimensions used for an {@link
21 * android.renderscript.Allocation} or a parallel operation. Types are created through {@link
22 * android.renderscript.Type.Builder}.</p>
23 *
24 * <p>A Type always includes an {@link android.renderscript.Element} and an X
25 * dimension. A Type may be multidimensional, up to three dimensions. A nonzero
26 * value in the Y or Z dimensions indicates that the dimension is present. Note
27 * that a Type with only a given X dimension and a Type with the same X
28 * dimension but Y = 1 are not equivalent.</p>
29 *
30 * <p>A Type also supports inclusion of level of detail (LOD) or cube map
31 * faces. LOD and cube map faces are booleans to indicate present or not
32 * present. </p>
33 *
34 * <p>A Type also supports YUV format information to support an
35 * {@link android.renderscript.Allocation} in a YUV format. The YUV formats
36 * supported are {@link android.graphics.ImageFormat#YV12},
37 * {@link android.graphics.ImageFormat#NV21}, and
38 * {@link android.graphics.ImageFormat#YUV_420_888}</p>
39 *
40 * <div class="special reference">
41 * <h3>Developer Guides</h3>
42 * <p>For more information about creating an application that uses RenderScript, read the
43 * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p>
44 * </div>
45 **/
46public class Type extends BaseObj {
47    int mDimX;
48    int mDimY;
49    int mDimZ;
50    boolean mDimMipmaps;
51    boolean mDimFaces;
52    int mDimYuv;
53    int mElementCount;
54    Element mElement;
55    int mArrays[];
56
57    static final int mMaxArrays = 4;
58
59    public enum CubemapFace {
60        POSITIVE_X (0),
61        NEGATIVE_X (1),
62        POSITIVE_Y (2),
63        NEGATIVE_Y (3),
64        POSITIVE_Z (4),
65        NEGATIVE_Z (5),
66        @Deprecated
67        POSITVE_X (0),
68        @Deprecated
69        POSITVE_Y (2),
70        @Deprecated
71        POSITVE_Z (4);
72
73        int mID;
74        CubemapFace(int id) {
75            mID = id;
76        }
77    }
78
79    /**
80     * Return the element associated with this Type.
81     *
82     * @return Element
83     */
84    public Element getElement() {
85        return mElement;
86    }
87
88    /**
89     * Return the value of the X dimension.
90     *
91     * @return int
92     */
93    public int getX() {
94        return mDimX;
95    }
96
97    /**
98     * Return the value of the Y dimension or 0 for a 1D allocation.
99     *
100     * @return int
101     */
102    public int getY() {
103        return mDimY;
104    }
105
106    /**
107     * Return the value of the Z dimension or 0 for a 1D or 2D allocation.
108     *
109     * @return int
110     */
111    public int getZ() {
112        return mDimZ;
113    }
114
115    /**
116     * Get the YUV format
117     *
118     *
119     * @return int
120     */
121    public int getYuv() {
122        return mDimYuv;
123    }
124
125    /**
126     * Return if the Type has a mipmap chain.
127     *
128     * @return boolean
129     */
130    public boolean hasMipmaps() {
131        return mDimMipmaps;
132    }
133
134    /**
135     * Return if the Type is a cube map.
136     *
137     * @return boolean
138     */
139    public boolean hasFaces() {
140        return mDimFaces;
141    }
142
143    /**
144     * Return the total number of accessable cells in the Type.
145     *
146     * @return int
147     */
148    public int getCount() {
149        return mElementCount;
150    }
151
152    /**
153     * @hide
154      * Return the dimension of the specified array.
155      *
156      * @param arrayNum  The array dimension to query
157      * @return int
158      */
159    public int getArray(int arrayNum) {
160        if ((arrayNum < 0) || (arrayNum >= mMaxArrays)) {
161            throw new RSIllegalArgumentException("Array dimension out of range.");
162        }
163
164        if (mArrays == null || arrayNum >= mArrays.length) {
165            // Dimension in range but no array for that dimension allocated
166            return 0;
167        }
168
169        return mArrays[arrayNum];
170    }
171
172    /**
173     * @hide
174      * Return the number of array dimensions.
175      *
176      * @return int
177      */
178    public int getArrayCount() {
179        if (mArrays != null) return mArrays.length;
180        return 0;
181    }
182
183    void calcElementCount() {
184        boolean hasLod = hasMipmaps();
185        int x = getX();
186        int y = getY();
187        int z = getZ();
188        int faces = 1;
189        if (hasFaces()) {
190            faces = 6;
191        }
192        if (x == 0) {
193            x = 1;
194        }
195        if (y == 0) {
196            y = 1;
197        }
198        if (z == 0) {
199            z = 1;
200        }
201
202        int count = x * y * z * faces;
203
204        while (hasLod && ((x > 1) || (y > 1) || (z > 1))) {
205            if(x > 1) {
206                x >>= 1;
207            }
208            if(y > 1) {
209                y >>= 1;
210            }
211            if(z > 1) {
212                z >>= 1;
213            }
214
215            count += x * y * z * faces;
216        }
217
218        if (mArrays != null) {
219            for (int ct = 0; ct < mArrays.length; ct++) {
220                count *= mArrays[ct];
221            }
222        }
223
224        mElementCount = count;
225    }
226
227
228    Type(long id, RenderScript rs) {
229        super(id, rs);
230        guard.open("destroy");
231    }
232
233    @Override
234    void updateFromNative() {
235        // We have 6 integer/long to obtain mDimX; mDimY; mDimZ;
236        // mDimLOD; mDimFaces; mElement;
237        long[] dataBuffer = new long[6];
238        mRS.nTypeGetNativeData(getID(mRS), dataBuffer);
239
240        mDimX = (int)dataBuffer[0];
241        mDimY = (int)dataBuffer[1];
242        mDimZ = (int)dataBuffer[2];
243        mDimMipmaps = dataBuffer[3] == 1 ? true : false;
244        mDimFaces = dataBuffer[4] == 1 ? true : false;
245
246        long elementID = dataBuffer[5];
247        if(elementID != 0) {
248            mElement = new Element(elementID, mRS);
249            mElement.updateFromNative();
250        }
251        calcElementCount();
252    }
253
254    /**
255     * Utility function for creating basic 1D types. The type is
256     * created without mipmaps enabled.
257     *
258     * @param rs The RenderScript context
259     * @param e The Element for the Type
260     * @param dimX The X dimension, must be > 0
261     *
262     * @return Type
263     */
264    static public Type createX(RenderScript rs, Element e, int dimX) {
265        if (dimX < 1) {
266            throw new RSInvalidStateException("Dimension must be >= 1.");
267        }
268
269        long id = rs.nTypeCreate(e.getID(rs), dimX, 0, 0, false, false, 0);
270        Type t = new Type(id, rs);
271        t.mElement = e;
272        t.mDimX = dimX;
273        t.calcElementCount();
274        return t;
275    }
276
277    /**
278     * Utility function for creating basic 2D types. The type is
279     * created without mipmaps or cubemaps.
280     *
281     * @param rs The RenderScript context
282     * @param e The Element for the Type
283     * @param dimX The X dimension, must be > 0
284     * @param dimY The Y dimension, must be > 0
285     *
286     * @return Type
287     */
288    static public Type createXY(RenderScript rs, Element e, int dimX, int dimY) {
289        if ((dimX < 1) || (dimY < 1)) {
290            throw new RSInvalidStateException("Dimension must be >= 1.");
291        }
292
293        long id = rs.nTypeCreate(e.getID(rs), dimX, dimY, 0, false, false, 0);
294        Type t = new Type(id, rs);
295        t.mElement = e;
296        t.mDimX = dimX;
297        t.mDimY = dimY;
298        t.calcElementCount();
299        return t;
300    }
301
302    /**
303     * Utility function for creating basic 3D types. The type is
304     * created without mipmaps.
305     *
306     * @param rs The RenderScript context
307     * @param e The Element for the Type
308     * @param dimX The X dimension, must be > 0
309     * @param dimY The Y dimension, must be > 0
310     * @param dimZ The Z dimension, must be > 0
311     *
312     * @return Type
313     */
314    static public Type createXYZ(RenderScript rs, Element e, int dimX, int dimY, int dimZ) {
315        if ((dimX < 1) || (dimY < 1) || (dimZ < 1)) {
316            throw new RSInvalidStateException("Dimension must be >= 1.");
317        }
318
319        long id = rs.nTypeCreate(e.getID(rs), dimX, dimY, dimZ, false, false, 0);
320        Type t = new Type(id, rs);
321        t.mElement = e;
322        t.mDimX = dimX;
323        t.mDimY = dimY;
324        t.mDimZ = dimZ;
325        t.calcElementCount();
326        return t;
327    }
328
329    /**
330     * Builder class for Type.
331     *
332     */
333    public static class Builder {
334        RenderScript mRS;
335        int mDimX = 1;
336        int mDimY;
337        int mDimZ;
338        boolean mDimMipmaps;
339        boolean mDimFaces;
340        int mYuv;
341        int[] mArray = new int[mMaxArrays];
342
343        Element mElement;
344
345        /**
346         * Create a new builder object.
347         *
348         * @param rs
349         * @param e The element for the type to be created.
350         */
351        public Builder(RenderScript rs, Element e) {
352            e.checkValid();
353            mRS = rs;
354            mElement = e;
355        }
356
357        /**
358         * Add a dimension to the Type.
359         *
360         *
361         * @param value
362         */
363        public Builder setX(int value) {
364            if(value < 1) {
365                throw new RSIllegalArgumentException("Values of less than 1 for Dimension X are not valid.");
366            }
367            mDimX = value;
368            return this;
369        }
370
371        public Builder setY(int value) {
372            if(value < 1) {
373                throw new RSIllegalArgumentException("Values of less than 1 for Dimension Y are not valid.");
374            }
375            mDimY = value;
376            return this;
377        }
378
379        public Builder setZ(int value) {
380            if(value < 1) {
381                throw new RSIllegalArgumentException("Values of less than 1 for Dimension Z are not valid.");
382            }
383            mDimZ = value;
384            return this;
385        }
386
387        /**
388         * @hide
389         * Adds an array dimension to the builder
390         *
391         * @param dim
392         * @param value
393         *
394         * @return Builder
395         */
396        public Builder setArray(int dim, int value) {
397            if(dim < 0 || dim >= mMaxArrays) {
398                throw new RSIllegalArgumentException("Array dimension out of range.");
399            }
400            mArray[dim] = value;
401            return this;
402        }
403
404        public Builder setMipmaps(boolean value) {
405            mDimMipmaps = value;
406            return this;
407        }
408
409        public Builder setFaces(boolean value) {
410            mDimFaces = value;
411            return this;
412        }
413
414        /**
415         * Set the YUV layout for a Type.
416         *
417         * @param yuvFormat {@link android.graphics.ImageFormat#YV12}, {@link android.graphics.ImageFormat#NV21}, or
418         * {@link android.graphics.ImageFormat#YUV_420_888}.
419         */
420        public Builder setYuvFormat(int yuvFormat) {
421            switch (yuvFormat) {
422            case android.graphics.ImageFormat.NV21:
423            case android.graphics.ImageFormat.YV12:
424            case android.graphics.ImageFormat.YUV_420_888:
425                break;
426
427            default:
428                throw new RSIllegalArgumentException(
429                    "Only ImageFormat.NV21, .YV12, and .YUV_420_888 are supported..");
430            }
431
432            mYuv = yuvFormat;
433            return this;
434        }
435
436
437        /**
438         * Validate structure and create a new Type.
439         *
440         * @return Type
441         */
442        public Type create() {
443            if (mDimZ > 0) {
444                if ((mDimX < 1) || (mDimY < 1)) {
445                    throw new RSInvalidStateException("Both X and Y dimension required when Z is present.");
446                }
447                if (mDimFaces) {
448                    throw new RSInvalidStateException("Cube maps not supported with 3D types.");
449                }
450            }
451            if (mDimY > 0) {
452                if (mDimX < 1) {
453                    throw new RSInvalidStateException("X dimension required when Y is present.");
454                }
455            }
456            if (mDimFaces) {
457                if (mDimY < 1) {
458                    throw new RSInvalidStateException("Cube maps require 2D Types.");
459                }
460            }
461
462            if (mYuv != 0) {
463                if ((mDimZ != 0) || mDimFaces || mDimMipmaps) {
464                    throw new RSInvalidStateException("YUV only supports basic 2D.");
465                }
466            }
467
468            int[] arrays = null;
469            for (int ct = mMaxArrays - 1; ct >= 0; ct--) {
470                if (mArray[ct] != 0 && arrays == null) {
471                    arrays = new int[ct];
472                }
473                if ((mArray[ct] == 0) && (arrays != null)) {
474                    throw new RSInvalidStateException("Array dimensions must be contigous from 0.");
475                }
476            }
477
478            long id = mRS.nTypeCreate(mElement.getID(mRS),
479                                     mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mYuv);
480            Type t = new Type(id, mRS);
481            t.mElement = mElement;
482            t.mDimX = mDimX;
483            t.mDimY = mDimY;
484            t.mDimZ = mDimZ;
485            t.mDimMipmaps = mDimMipmaps;
486            t.mDimFaces = mDimFaces;
487            t.mDimYuv = mYuv;
488            t.mArrays = arrays;
489
490            t.calcElementCount();
491            return t;
492        }
493    }
494
495}
496