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.support.v8.renderscript;
18
19
20import java.lang.reflect.Field;
21
22import android.graphics.ImageFormat;
23import android.util.Log;
24
25/**
26 * <p>A Type describes the {@link android.support.v8.renderscript.Element} and
27 * dimensions used for an {@link android.support.v8.renderscript.Allocation} or
28 * a parallel operation. Types are created through
29 * {@link android.support.v8.renderscript.Type.Builder}.</p>
30 *
31 * <p>A Type always includes an {@link android.support.v8.renderscript.Element}
32 * and an X dimension. A Type may be multidimensional, up to three dimensions.
33 * A nonzero value in the Y or Z dimensions indicates that the dimension is
34 * present. Note that a Type with only a given X dimension and a Type with the
35 * same X dimension but Y = 1 are not equivalent.</p>
36 *
37 * <p>A Type also supports inclusion of level of detail (LOD) or cube map
38 * faces. LOD and cube map faces are booleans to indicate present or not
39 * present. </p>
40 *
41 * <p>A Type also supports YUV format information to support an {@link
42 * android.support.v8.renderscript.Allocation} in a YUV format. The YUV formats
43 * supported are {@link android.graphics.ImageFormat#YV12} and {@link
44 * android.graphics.ImageFormat#NV21}.</p>
45 *
46 * <div class="special reference">
47 * <h3>Developer Guides</h3>
48 * <p>For more information about creating an application that uses RenderScript,
49 * read the
50 * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
51 * developer guide.</p>
52 * </div>
53 **/
54public class Type extends BaseObj {
55    int mDimX;
56    int mDimY;
57    int mDimZ;
58    boolean mDimMipmaps;
59    boolean mDimFaces;
60    int mDimYuv;
61    int mElementCount;
62    Element mElement;
63
64    public enum CubemapFace {
65        POSITIVE_X (0),
66        NEGATIVE_X (1),
67        POSITIVE_Y (2),
68        NEGATIVE_Y (3),
69        POSITIVE_Z (4),
70        NEGATIVE_Z (5);
71
72        int mID;
73        CubemapFace(int id) {
74            mID = id;
75        }
76    }
77
78    /**
79     * Return the element associated with this Type.
80     *
81     * @return Element
82     */
83    public Element getElement() {
84        return mElement;
85    }
86
87    /**
88     * Return the value of the X dimension.
89     *
90     * @return int
91     */
92    public int getX() {
93        return mDimX;
94    }
95
96    /**
97     * Return the value of the Y dimension or 0 for a 1D allocation.
98     *
99     * @return int
100     */
101    public int getY() {
102        return mDimY;
103    }
104
105    /**
106     * Return the value of the Z dimension or 0 for a 1D or 2D allocation.
107     *
108     * @return int
109     */
110    public int getZ() {
111        return mDimZ;
112    }
113
114    /**
115     * Get the YUV format
116     *
117     * @hide
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    void calcElementCount() {
153        boolean hasLod = hasMipmaps();
154        int x = getX();
155        int y = getY();
156        int z = getZ();
157        int faces = 1;
158        if (hasFaces()) {
159            faces = 6;
160        }
161        if (x == 0) {
162            x = 1;
163        }
164        if (y == 0) {
165            y = 1;
166        }
167        if (z == 0) {
168            z = 1;
169        }
170
171        int count = x * y * z * faces;
172
173        while (hasLod && ((x > 1) || (y > 1) || (z > 1))) {
174            if(x > 1) {
175                x >>= 1;
176            }
177            if(y > 1) {
178                y >>= 1;
179            }
180            if(z > 1) {
181                z >>= 1;
182            }
183
184            count += x * y * z * faces;
185        }
186        mElementCount = count;
187    }
188
189
190    Type(int id, RenderScript rs) {
191        super(id, rs);
192    }
193
194    /**
195     * Builder class for Type.
196     *
197     */
198    public static class Builder {
199        RenderScript mRS;
200        int mDimX = 1;
201        int mDimY;
202        int mDimZ;
203        boolean mDimMipmaps;
204        boolean mDimFaces;
205        int mYuv;
206
207        Element mElement;
208
209        /**
210         * Create a new builder object.
211         *
212         * @param rs
213         * @param e The element for the type to be created.
214         */
215        public Builder(RenderScript rs, Element e) {
216            e.checkValid();
217            mRS = rs;
218            mElement = e;
219        }
220
221        /**
222         * Add a dimension to the Type.
223         *
224         *
225         * @param value
226         */
227        public Builder setX(int value) {
228            if(value < 1) {
229                throw new RSIllegalArgumentException("Values of less than 1 for Dimension X are not valid.");
230            }
231            mDimX = value;
232            return this;
233        }
234
235        public Builder setY(int value) {
236            if(value < 1) {
237                throw new RSIllegalArgumentException("Values of less than 1 for Dimension Y are not valid.");
238            }
239            mDimY = value;
240            return this;
241        }
242
243        public Builder setZ(int value) {
244            if(value < 1) {
245                throw new RSIllegalArgumentException("Values of less than 1 for Dimension Z are not valid.");
246            }
247            mDimZ = value;
248            return this;
249        }
250
251        public Builder setMipmaps(boolean value) {
252            mDimMipmaps = value;
253            return this;
254        }
255
256        public Builder setFaces(boolean value) {
257            mDimFaces = value;
258            return this;
259        }
260
261        /**
262         * Set the YUV layout for a Type.
263         *
264         * @hide
265         *
266         * @param yuvFormat {@link android.graphics.ImageFormat#YV12} or {@link android.graphics.ImageFormat#NV21}
267         */
268        public Builder setYuvFormat(int yuvFormat) {
269            switch (yuvFormat) {
270            case android.graphics.ImageFormat.NV21:
271            case android.graphics.ImageFormat.YV12:
272                break;
273
274            default:
275                throw new RSIllegalArgumentException("Only NV21 and YV12 are supported..");
276            }
277
278            mYuv = yuvFormat;
279            return this;
280        }
281
282
283        /**
284         * Validate structure and create a new Type.
285         *
286         * @return Type
287         */
288        public Type create() {
289            if (mDimZ > 0) {
290                if ((mDimX < 1) || (mDimY < 1)) {
291                    throw new RSInvalidStateException("Both X and Y dimension required when Z is present.");
292                }
293                if (mDimFaces) {
294                    throw new RSInvalidStateException("Cube maps not supported with 3D types.");
295                }
296            }
297            if (mDimY > 0) {
298                if (mDimX < 1) {
299                    throw new RSInvalidStateException("X dimension required when Y is present.");
300                }
301            }
302            if (mDimFaces) {
303                if (mDimY < 1) {
304                    throw new RSInvalidStateException("Cube maps require 2D Types.");
305                }
306            }
307
308            if (mYuv != 0) {
309                if ((mDimZ != 0) || mDimFaces || mDimMipmaps) {
310                    throw new RSInvalidStateException("YUV only supports basic 2D.");
311                }
312            }
313
314            Type t;
315            if (mRS.isNative) {
316                RenderScriptThunker rst = (RenderScriptThunker)mRS;
317                t = TypeThunker.create(rst, mElement, mDimX, mDimY, mDimZ,
318                                       mDimMipmaps, mDimFaces, mYuv);
319            } else {
320                int id = mRS.nTypeCreate(mElement.getID(mRS),
321                                         mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mYuv);
322                t = new Type(id, mRS);
323            }
324            t.mElement = mElement;
325            t.mDimX = mDimX;
326            t.mDimY = mDimY;
327            t.mDimZ = mDimZ;
328            t.mDimMipmaps = mDimMipmaps;
329            t.mDimFaces = mDimFaces;
330            t.mDimYuv = mYuv;
331
332            t.calcElementCount();
333            return t;
334        }
335    }
336
337}
338