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