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