Allocation.java revision 67f2e442a31b8395e3c1951f8e91139ec7f2be99
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.io.IOException;
20import java.io.InputStream;
21
22import android.content.res.Resources;
23import android.content.res.AssetManager;
24import android.graphics.Bitmap;
25import android.graphics.BitmapFactory;
26import android.util.Log;
27import android.util.TypedValue;
28
29/**
30 * @hide
31 *
32 **/
33public class Allocation extends BaseObj {
34    Type mType;
35    Bitmap mBitmap;
36
37    public enum CubemapLayout {
38        VERTICAL_FACE_LIST (0),
39        HORIZONTAL_FACE_LIST (1),
40        VERTICAL_CROSS (2),
41        HORIZONTAL_CROSS (3);
42
43        int mID;
44        CubemapLayout(int id) {
45            mID = id;
46        }
47    }
48
49    Allocation(int id, RenderScript rs, Type t) {
50        super(id, rs);
51        mType = t;
52    }
53
54    Allocation(int id, RenderScript rs) {
55        super(id, rs);
56    }
57
58    @Override
59    void updateFromNative() {
60        super.updateFromNative();
61        int typeID = mRS.nAllocationGetType(getID());
62        if(typeID != 0) {
63            mType = new Type(typeID, mRS);
64            mType.updateFromNative();
65        }
66    }
67
68    public Type getType() {
69        return mType;
70    }
71
72    public void uploadToTexture(int baseMipLevel) {
73        mRS.validate();
74        mRS.nAllocationUploadToTexture(getID(), false, baseMipLevel);
75    }
76
77    public void uploadToTexture(boolean genMips, int baseMipLevel) {
78        mRS.validate();
79        mRS.nAllocationUploadToTexture(getID(), genMips, baseMipLevel);
80    }
81
82    public void uploadToBufferObject() {
83        mRS.validate();
84        mRS.nAllocationUploadToBufferObject(getID());
85    }
86
87    public void data(int[] d) {
88        mRS.validate();
89        subData1D(0, mType.getElementCount(), d);
90    }
91    public void data(short[] d) {
92        mRS.validate();
93        subData1D(0, mType.getElementCount(), d);
94    }
95    public void data(byte[] d) {
96        mRS.validate();
97        subData1D(0, mType.getElementCount(), d);
98    }
99    public void data(float[] d) {
100        mRS.validate();
101        subData1D(0, mType.getElementCount(), d);
102    }
103
104    public void updateFromBitmap(Bitmap b) {
105
106        mRS.validate();
107        if(mType.getX() != b.getWidth() ||
108           mType.getY() != b.getHeight()) {
109            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
110        }
111
112        mRS.nAllocationUpdateFromBitmap(getID(), b);
113    }
114
115    public void subData(int xoff, FieldPacker fp) {
116        int eSize = mType.mElement.getSizeBytes();
117        final byte[] data = fp.getData();
118
119        int count = data.length / eSize;
120        if ((eSize * count) != data.length) {
121            throw new RSIllegalArgumentException("Field packer length " + data.length +
122                                               " not divisible by element size " + eSize + ".");
123        }
124        data1DChecks(xoff, count, data.length, data.length);
125        mRS.nAllocationSubData1D(getID(), xoff, count, data, data.length);
126    }
127
128
129    public void subElementData(int xoff, int component_number, FieldPacker fp) {
130        if (component_number >= mType.mElement.mElements.length) {
131            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
132        }
133        if(xoff < 0) {
134            throw new RSIllegalArgumentException("Offset must be >= 0.");
135        }
136
137        final byte[] data = fp.getData();
138        int eSize = mType.mElement.mElements[component_number].getSizeBytes();
139
140        if (data.length != eSize) {
141            throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
142                                               " does not match component size " + eSize + ".");
143        }
144
145        mRS.nAllocationSubElementData1D(getID(), xoff, component_number, data, data.length);
146    }
147
148    private void data1DChecks(int off, int count, int len, int dataSize) {
149        mRS.validate();
150        if(off < 0) {
151            throw new RSIllegalArgumentException("Offset must be >= 0.");
152        }
153        if(count < 1) {
154            throw new RSIllegalArgumentException("Count must be >= 1.");
155        }
156        if((off + count) > mType.getElementCount()) {
157            throw new RSIllegalArgumentException("Overflow, Available count " + mType.getElementCount() +
158                                               ", got " + count + " at offset " + off + ".");
159        }
160        if((len) < dataSize) {
161            throw new RSIllegalArgumentException("Array too small for allocation type.");
162        }
163    }
164
165    public void subData1D(int off, int count, int[] d) {
166        int dataSize = mType.mElement.getSizeBytes() * count;
167        data1DChecks(off, count, d.length * 4, dataSize);
168        mRS.nAllocationSubData1D(getID(), off, count, d, dataSize);
169    }
170    public void subData1D(int off, int count, short[] d) {
171        int dataSize = mType.mElement.getSizeBytes() * count;
172        data1DChecks(off, count, d.length * 2, dataSize);
173        mRS.nAllocationSubData1D(getID(), off, count, d, dataSize);
174    }
175    public void subData1D(int off, int count, byte[] d) {
176        int dataSize = mType.mElement.getSizeBytes() * count;
177        data1DChecks(off, count, d.length, dataSize);
178        mRS.nAllocationSubData1D(getID(), off, count, d, dataSize);
179    }
180    public void subData1D(int off, int count, float[] d) {
181        int dataSize = mType.mElement.getSizeBytes() * count;
182        data1DChecks(off, count, d.length * 4, dataSize);
183        mRS.nAllocationSubData1D(getID(), off, count, d, dataSize);
184    }
185
186
187    public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
188        mRS.validate();
189        mRS.nAllocationSubData2D(getID(), xoff, yoff, w, h, d, d.length * 4);
190    }
191
192    public void subData2D(int xoff, int yoff, int w, int h, float[] d) {
193        mRS.validate();
194        mRS.nAllocationSubData2D(getID(), xoff, yoff, w, h, d, d.length * 4);
195    }
196
197    public void readData(int[] d) {
198        mRS.validate();
199        mRS.nAllocationRead(getID(), d);
200    }
201
202    public void readData(float[] d) {
203        mRS.validate();
204        mRS.nAllocationRead(getID(), d);
205    }
206
207    public synchronized void resize(int dimX) {
208        if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
209            throw new RSInvalidStateException("Resize only support for 1D allocations at this time.");
210        }
211        mRS.nAllocationResize1D(getID(), dimX);
212        mRS.finish();  // Necessary because resize is fifoed and update is async.
213
214        int typeID = mRS.nAllocationGetType(getID());
215        mType = new Type(typeID, mRS);
216        mType.updateFromNative();
217    }
218
219    /*
220    public void resize(int dimX, int dimY) {
221        if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
222            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
223        }
224        if (mType.getY() == 0) {
225            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
226        }
227        mRS.nAllocationResize2D(getID(), dimX, dimY);
228    }
229    */
230
231    public class Adapter1D extends BaseObj {
232        Adapter1D(int id, RenderScript rs) {
233            super(id, rs);
234        }
235
236        public void setConstraint(Dimension dim, int value) {
237            mRS.validate();
238            mRS.nAdapter1DSetConstraint(getID(), dim.mID, value);
239        }
240
241        public void data(int[] d) {
242            mRS.validate();
243            mRS.nAdapter1DData(getID(), d);
244        }
245
246        public void data(float[] d) {
247            mRS.validate();
248            mRS.nAdapter1DData(getID(), d);
249        }
250
251        public void subData(int off, int count, int[] d) {
252            mRS.validate();
253            mRS.nAdapter1DSubData(getID(), off, count, d);
254        }
255
256        public void subData(int off, int count, float[] d) {
257            mRS.validate();
258            mRS.nAdapter1DSubData(getID(), off, count, d);
259        }
260    }
261
262    public Adapter1D createAdapter1D() {
263        mRS.validate();
264        int id = mRS.nAdapter1DCreate();
265        if(id == 0) {
266            throw new RSRuntimeException("Adapter creation failed.");
267        }
268        mRS.nAdapter1DBindAllocation(id, getID());
269        return new Adapter1D(id, mRS);
270    }
271
272
273    public class Adapter2D extends BaseObj {
274        Adapter2D(int id, RenderScript rs) {
275            super(id, rs);
276        }
277
278        public void setConstraint(Dimension dim, int value) {
279            mRS.validate();
280            mRS.nAdapter2DSetConstraint(getID(), dim.mID, value);
281        }
282
283        public void data(int[] d) {
284            mRS.validate();
285            mRS.nAdapter2DData(getID(), d);
286        }
287
288        public void data(float[] d) {
289            mRS.validate();
290            mRS.nAdapter2DData(getID(), d);
291        }
292
293        public void subData(int xoff, int yoff, int w, int h, int[] d) {
294            mRS.validate();
295            mRS.nAdapter2DSubData(getID(), xoff, yoff, w, h, d);
296        }
297
298        public void subData(int xoff, int yoff, int w, int h, float[] d) {
299            mRS.validate();
300            mRS.nAdapter2DSubData(getID(), xoff, yoff, w, h, d);
301        }
302    }
303
304    public Adapter2D createAdapter2D() {
305        mRS.validate();
306        int id = mRS.nAdapter2DCreate();
307        if(id == 0) {
308            throw new RSRuntimeException("allocation failed.");
309        }
310        mRS.nAdapter2DBindAllocation(id, getID());
311        if(id == 0) {
312            throw new RSRuntimeException("Adapter creation failed.");
313        }
314        return new Adapter2D(id, mRS);
315    }
316
317
318    // creation
319
320    private static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
321    static {
322        mBitmapOptions.inScaled = false;
323    }
324
325    static public Allocation createTyped(RenderScript rs, Type type) {
326
327        rs.validate();
328        if(type.getID() == 0) {
329            throw new RSInvalidStateException("Bad Type");
330        }
331        int id = rs.nAllocationCreateTyped(type.getID());
332        if(id == 0) {
333            throw new RSRuntimeException("Allocation creation failed.");
334        }
335        return new Allocation(id, rs, type);
336    }
337
338    static public Allocation createSized(RenderScript rs, Element e, int count)
339        throws IllegalArgumentException {
340
341        rs.validate();
342        Type.Builder b = new Type.Builder(rs, e);
343        b.add(Dimension.X, count);
344        Type t = b.create();
345
346        int id = rs.nAllocationCreateTyped(t.getID());
347        if(id == 0) {
348            throw new RSRuntimeException("Allocation creation failed.");
349        }
350        return new Allocation(id, rs, t);
351    }
352
353    static private Element elementFromBitmap(RenderScript rs, Bitmap b) {
354        final Bitmap.Config bc = b.getConfig();
355        if (bc == Bitmap.Config.ALPHA_8) {
356            return Element.A_8(rs);
357        }
358        if (bc == Bitmap.Config.ARGB_4444) {
359            return Element.RGBA_4444(rs);
360        }
361        if (bc == Bitmap.Config.ARGB_8888) {
362            return Element.RGBA_8888(rs);
363        }
364        if (bc == Bitmap.Config.RGB_565) {
365            return Element.RGB_565(rs);
366        }
367        throw new RSInvalidStateException("Bad bitmap type: " + bc);
368    }
369
370    static private Type typeFromBitmap(RenderScript rs, Bitmap b, boolean mip) {
371        Element e = elementFromBitmap(rs, b);
372        Type.Builder tb = new Type.Builder(rs, e);
373        tb.add(Dimension.X, b.getWidth());
374        tb.add(Dimension.Y, b.getHeight());
375        if (mip) {
376            tb.add(Dimension.LOD, 1);
377        }
378        return tb.create();
379    }
380
381    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
382                                              Element dstFmt, boolean genMips) {
383        rs.validate();
384        Type t = typeFromBitmap(rs, b, genMips);
385
386        int id = rs.nAllocationCreateFromBitmap(dstFmt.getID(), genMips, b);
387        if(id == 0) {
388            throw new RSRuntimeException("Load failed.");
389        }
390        return new Allocation(id, rs, t);
391    }
392
393    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
394                                                     Element dstFmt,
395                                                     boolean genMips,
396                                                     CubemapLayout layout) {
397        rs.validate();
398        int height = b.getHeight();
399        int width = b.getWidth();
400
401        if (layout != CubemapLayout.VERTICAL_FACE_LIST) {
402            throw new RSIllegalArgumentException("Only vertical face list supported");
403        }
404        if (height % 6 != 0) {
405            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
406        }
407        if (height / 6 != width) {
408            throw new RSIllegalArgumentException("Only square cobe map faces supported");
409        }
410        boolean isPow2 = (width & (width - 1)) == 0;
411        if (!isPow2) {
412            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
413        }
414
415        Element e = elementFromBitmap(rs, b);
416        Type.Builder tb = new Type.Builder(rs, e);
417        tb.add(Dimension.X, width);
418        tb.add(Dimension.Y, width);
419        tb.add(Dimension.FACE, 1);
420        if (genMips) {
421            tb.add(Dimension.LOD, 1);
422        }
423        Type t = tb.create();
424
425        int id = rs.nAllocationCubeCreateFromBitmap(dstFmt.getID(), genMips, b);
426        if(id == 0) {
427            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
428        }
429        return new Allocation(id, rs, t);
430    }
431
432    static public Allocation createBitmapRef(RenderScript rs, Bitmap b) {
433
434        rs.validate();
435        Type t = typeFromBitmap(rs, b, false);
436
437        int id = rs.nAllocationCreateBitmapRef(t.getID(), b);
438        if(id == 0) {
439            throw new RSRuntimeException("Load failed.");
440        }
441
442        Allocation a = new Allocation(id, rs, t);
443        a.mBitmap = b;
444        return a;
445    }
446
447    static public Allocation createFromBitmapResource(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips) {
448
449        rs.validate();
450        InputStream is = null;
451        try {
452            final TypedValue value = new TypedValue();
453            is = res.openRawResource(id, value);
454
455            int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
456            int aId = rs.nAllocationCreateFromAssetStream(dstFmt.getID(), genMips, asset);
457
458            if (aId == 0) {
459                throw new RSRuntimeException("Load failed.");
460            }
461            Allocation alloc = new Allocation(aId, rs, null);
462            alloc.updateFromNative();
463            return alloc;
464        } finally {
465            if (is != null) {
466                try {
467                    is.close();
468                } catch (IOException e) {
469                    // Ignore
470                }
471            }
472        }
473    }
474
475    static public Allocation createFromString(RenderScript rs, String str) {
476        byte[] allocArray = null;
477        try {
478            allocArray = str.getBytes("UTF-8");
479            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length);
480            alloc.data(allocArray);
481            return alloc;
482        }
483        catch (Exception e) {
484            throw new RSRuntimeException("Could not convert string to utf-8.");
485        }
486    }
487}
488
489
490