Allocation.java revision dcc231955d81c66309ce97cca05a25f79ee7d5ea
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;
21import android.content.res.Resources;
22import android.content.res.AssetManager;
23import android.graphics.Bitmap;
24import android.graphics.BitmapFactory;
25import android.util.Log;
26import android.util.TypedValue;
27
28/**
29 * Memory allocation class for renderscript.  An allocation combines a Type with
30 * memory to provide storage for user data and objects.
31 *
32 * Allocations may exist in one or more memory spaces.  Currently those are
33 * Script: accessable by RS scripts.
34 * Graphics Texture: accessable as a graphics texture.
35 * Graphics Vertex: accessable as graphical vertex data.
36 * Graphics Constants: Accessable as constants in user shaders
37 *
38 * By default java side updates are always applied to the script accessable
39 * memory.  If this is not present they are then applied to the various HW
40 * memory types.  A syncAll call is necessary after the script data is update to
41 * keep the other memory spaces in sync.
42 *
43 **/
44public class Allocation extends BaseObj {
45    Type mType;
46    Bitmap mBitmap;
47    int mUsage;
48
49    public static final int USAGE_SCRIPT = 0x0001;
50    public static final int USAGE_GRAPHICS_TEXTURE = 0x0002;
51    public static final int USAGE_GRAPHICS_VERTEX = 0x0004;
52    public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008;
53
54
55    public enum MipmapControl {
56        MIPMAP_NONE(0),
57        MIPMAP_FULL(1),
58        MIPMAP_ON_SYNC_TO_TEXTURE(2);
59
60        int mID;
61        MipmapControl(int id) {
62            mID = id;
63        }
64    }
65
66    Allocation(int id, RenderScript rs, Type t, int usage) {
67        super(id, rs);
68        if ((usage & ~(USAGE_SCRIPT |
69                       USAGE_GRAPHICS_TEXTURE |
70                       USAGE_GRAPHICS_VERTEX |
71                       USAGE_GRAPHICS_CONSTANTS)) != 0) {
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        copy1DRangeFrom(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        copy1DRangeFrom(0, mType.getCount(), d);
129    }
130    public void copyFrom(short[] d) {
131        mRS.validate();
132        copy1DRangeFrom(0, mType.getCount(), d);
133    }
134    public void copyFrom(byte[] d) {
135        mRS.validate();
136        copy1DRangeFrom(0, mType.getCount(), d);
137    }
138    public void copyFrom(float[] d) {
139        mRS.validate();
140        copy1DRangeFrom(0, mType.getCount(), d);
141    }
142    public void copyFrom(Bitmap b) {
143        validateBitmap(b);
144        mRS.nAllocationCopyFromBitmap(getID(), b);
145    }
146
147    /**
148     * @hide
149     *
150     * This is only intended to be used by auto-generate code reflected from the
151     * renderscript script files.
152     *
153     * @param xoff
154     * @param fp
155     */
156    public void setOneElement(int xoff, FieldPacker fp) {
157        int eSize = mType.mElement.getSizeBytes();
158        final byte[] data = fp.getData();
159
160        int count = data.length / eSize;
161        if ((eSize * count) != data.length) {
162            throw new RSIllegalArgumentException("Field packer length " + data.length +
163                                               " not divisible by element size " + eSize + ".");
164        }
165        data1DChecks(xoff, count, data.length, data.length);
166        mRS.nAllocationData1D(getID(), xoff, 0, count, data, data.length);
167    }
168
169
170    /**
171     * @hide
172     *
173     * This is only intended to be used by auto-generate code reflected from the
174     * renderscript script files.
175     *
176     * @param xoff
177     * @param component_number
178     * @param fp
179     */
180    public void setOneComponent(int xoff, int component_number, FieldPacker fp) {
181        if (component_number >= mType.mElement.mElements.length) {
182            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
183        }
184        if(xoff < 0) {
185            throw new RSIllegalArgumentException("Offset must be >= 0.");
186        }
187
188        final byte[] data = fp.getData();
189        int eSize = mType.mElement.mElements[component_number].getSizeBytes();
190
191        if (data.length != eSize) {
192            throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
193                                               " does not match component size " + eSize + ".");
194        }
195
196        mRS.nAllocationElementData1D(getID(), xoff, 0, component_number, data, data.length);
197    }
198
199    private void data1DChecks(int off, int count, int len, int dataSize) {
200        mRS.validate();
201        if(off < 0) {
202            throw new RSIllegalArgumentException("Offset must be >= 0.");
203        }
204        if(count < 1) {
205            throw new RSIllegalArgumentException("Count must be >= 1.");
206        }
207        if((off + count) > mType.getCount()) {
208            throw new RSIllegalArgumentException("Overflow, Available count " + mType.getCount() +
209                                               ", got " + count + " at offset " + off + ".");
210        }
211        if((len) < dataSize) {
212            throw new RSIllegalArgumentException("Array too small for allocation type.");
213        }
214    }
215
216    public void copy1DRangeFrom(int off, int count, int[] d) {
217        int dataSize = mType.mElement.getSizeBytes() * count;
218        data1DChecks(off, count, d.length * 4, dataSize);
219        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
220    }
221    public void copy1DRangeFrom(int off, int count, short[] d) {
222        int dataSize = mType.mElement.getSizeBytes() * count;
223        data1DChecks(off, count, d.length * 2, dataSize);
224        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
225    }
226    public void copy1DRangeFrom(int off, int count, byte[] d) {
227        int dataSize = mType.mElement.getSizeBytes() * count;
228        data1DChecks(off, count, d.length, dataSize);
229        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
230    }
231    public void copy1DRangeFrom(int off, int count, float[] d) {
232        int dataSize = mType.mElement.getSizeBytes() * count;
233        data1DChecks(off, count, d.length * 4, dataSize);
234        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
235    }
236
237
238    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] d) {
239        mRS.validate();
240        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, d, d.length);
241    }
242
243    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] d) {
244        mRS.validate();
245        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, d, d.length * 2);
246    }
247
248    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] d) {
249        mRS.validate();
250        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, d, d.length * 4);
251    }
252
253    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] d) {
254        mRS.validate();
255        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, d, d.length * 4);
256    }
257
258    public void copy2DRangeFrom(int xoff, int yoff, Bitmap b) {
259        mRS.validate();
260        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, b);
261    }
262
263
264    public void copyTo(Bitmap b) {
265        validateBitmap(b);
266        mRS.nAllocationCopyToBitmap(getID(), b);
267    }
268
269    public void copyTo(byte[] d) {
270        mRS.validate();
271        mRS.nAllocationRead(getID(), d);
272    }
273
274    public void copyTo(short[] d) {
275        mRS.validate();
276        mRS.nAllocationRead(getID(), d);
277    }
278
279    public void copyTo(int[] d) {
280        mRS.validate();
281        mRS.nAllocationRead(getID(), d);
282    }
283
284    public void copyTo(float[] d) {
285        mRS.validate();
286        mRS.nAllocationRead(getID(), d);
287    }
288
289    public synchronized void resize(int dimX) {
290        if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
291            throw new RSInvalidStateException("Resize only support for 1D allocations at this time.");
292        }
293        mRS.nAllocationResize1D(getID(), dimX);
294        mRS.finish();  // Necessary because resize is fifoed and update is async.
295
296        int typeID = mRS.nAllocationGetType(getID());
297        mType = new Type(typeID, mRS);
298        mType.updateFromNative();
299    }
300
301    /*
302    public void resize(int dimX, int dimY) {
303        if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
304            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
305        }
306        if (mType.getY() == 0) {
307            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
308        }
309        mRS.nAllocationResize2D(getID(), dimX, dimY);
310    }
311    */
312
313
314
315    // creation
316
317    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
318    static {
319        mBitmapOptions.inScaled = false;
320    }
321
322    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mc, int usage) {
323        rs.validate();
324        if (type.getID() == 0) {
325            throw new RSInvalidStateException("Bad Type");
326        }
327        int id = rs.nAllocationCreateTyped(type.getID(), mc.mID, usage);
328        if (id == 0) {
329            throw new RSRuntimeException("Allocation creation failed.");
330        }
331        return new Allocation(id, rs, type, usage);
332    }
333
334    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
335        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
336    }
337
338    static public Allocation createTyped(RenderScript rs, Type type) {
339        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
340    }
341
342    static public Allocation createSized(RenderScript rs, Element e,
343                                         int count, int usage) {
344        rs.validate();
345        Type.Builder b = new Type.Builder(rs, e);
346        b.setX(count);
347        Type t = b.create();
348
349        int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage);
350        if (id == 0) {
351            throw new RSRuntimeException("Allocation creation failed.");
352        }
353        return new Allocation(id, rs, t, usage);
354    }
355
356    static public Allocation createSized(RenderScript rs, Element e, int count) {
357        return createSized(rs, e, count, USAGE_SCRIPT);
358    }
359
360    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
361        final Bitmap.Config bc = b.getConfig();
362        if (bc == Bitmap.Config.ALPHA_8) {
363            return Element.A_8(rs);
364        }
365        if (bc == Bitmap.Config.ARGB_4444) {
366            return Element.RGBA_4444(rs);
367        }
368        if (bc == Bitmap.Config.ARGB_8888) {
369            return Element.RGBA_8888(rs);
370        }
371        if (bc == Bitmap.Config.RGB_565) {
372            return Element.RGB_565(rs);
373        }
374        throw new RSInvalidStateException("Bad bitmap type: " + bc);
375    }
376
377    static Type typeFromBitmap(RenderScript rs, Bitmap b,
378                                       MipmapControl mip) {
379        Element e = elementFromBitmap(rs, b);
380        Type.Builder tb = new Type.Builder(rs, e);
381        tb.setX(b.getWidth());
382        tb.setY(b.getHeight());
383        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
384        return tb.create();
385    }
386
387    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
388                                              MipmapControl mips,
389                                              int usage) {
390        rs.validate();
391        Type t = typeFromBitmap(rs, b, mips);
392
393        int id = rs.nAllocationCreateFromBitmap(t.getID(), mips.mID, b, usage);
394        if (id == 0) {
395            throw new RSRuntimeException("Load failed.");
396        }
397        return new Allocation(id, rs, t, usage);
398    }
399
400    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
401        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
402                                USAGE_GRAPHICS_TEXTURE);
403    }
404
405    /**
406    * Creates a cubemap allocation from a bitmap containing the
407    * horizontal list of cube faces. Each individual face must be
408    * the same size and power of 2
409    *
410    * @param rs
411    * @param b bitmap with cubemap faces layed out in the following
412    *          format: right, left, top, bottom, front, back
413    * @param mips specifies desired mipmap behaviour for the cubemap
414    * @param usage bitfield specifying how the cubemap is utilized
415    *
416    **/
417    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
418                                                     MipmapControl mips,
419                                                     int usage) {
420        rs.validate();
421
422        int height = b.getHeight();
423        int width = b.getWidth();
424
425        if (width % 6 != 0) {
426            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
427        }
428        if (width / 6 != height) {
429            throw new RSIllegalArgumentException("Only square cube map faces supported");
430        }
431        boolean isPow2 = (height & (height - 1)) == 0;
432        if (!isPow2) {
433            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
434        }
435
436        Element e = elementFromBitmap(rs, b);
437        Type.Builder tb = new Type.Builder(rs, e);
438        tb.setX(height);
439        tb.setY(height);
440        tb.setFaces(true);
441        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
442        Type t = tb.create();
443
444        int id = rs.nAllocationCubeCreateFromBitmap(t.getID(), mips.mID, b, usage);
445        if(id == 0) {
446            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
447        }
448        return new Allocation(id, rs, t, usage);
449    }
450
451    static public Allocation createCubemapFromBitmap(RenderScript rs,
452                                                     Bitmap b) {
453        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
454                                       USAGE_GRAPHICS_TEXTURE);
455    }
456
457    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
458                                                        Bitmap xpos,
459                                                        Bitmap xneg,
460                                                        Bitmap ypos,
461                                                        Bitmap yneg,
462                                                        Bitmap zpos,
463                                                        Bitmap zneg,
464                                                        MipmapControl mips,
465                                                        int usage) {
466        int height = xpos.getHeight();
467        if (xpos.getWidth() != height ||
468            xneg.getWidth() != height || xneg.getHeight() != height ||
469            ypos.getWidth() != height || ypos.getHeight() != height ||
470            yneg.getWidth() != height || yneg.getHeight() != height ||
471            zpos.getWidth() != height || zpos.getHeight() != height ||
472            zneg.getWidth() != height || zneg.getHeight() != height) {
473            throw new RSIllegalArgumentException("Only square cube map faces supported");
474        }
475        boolean isPow2 = (height & (height - 1)) == 0;
476        if (!isPow2) {
477            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
478        }
479
480        Element e = elementFromBitmap(rs, xpos);
481        Type.Builder tb = new Type.Builder(rs, e);
482        tb.setX(height);
483        tb.setY(height);
484        tb.setFaces(true);
485        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
486        Type t = tb.create();
487        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
488
489        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
490        adapter.setFace(Type.CubemapFace.POSITVE_X);
491        adapter.copyFrom(xpos);
492        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
493        adapter.copyFrom(xneg);
494        adapter.setFace(Type.CubemapFace.POSITVE_Y);
495        adapter.copyFrom(ypos);
496        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
497        adapter.copyFrom(yneg);
498        adapter.setFace(Type.CubemapFace.POSITVE_Z);
499        adapter.copyFrom(zpos);
500        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
501        adapter.copyFrom(zneg);
502
503        return cubemap;
504    }
505
506    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
507                                                        Bitmap xpos,
508                                                        Bitmap xneg,
509                                                        Bitmap ypos,
510                                                        Bitmap yneg,
511                                                        Bitmap zpos,
512                                                        Bitmap zneg) {
513        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
514                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
515                                          USAGE_GRAPHICS_TEXTURE);
516    }
517
518    static public Allocation createFromBitmapResource(RenderScript rs,
519                                                      Resources res,
520                                                      int id,
521                                                      MipmapControl mips,
522                                                      int usage) {
523
524        rs.validate();
525        Bitmap b = BitmapFactory.decodeResource(res, id);
526        Allocation alloc = createFromBitmap(rs, b, mips, usage);
527        b.recycle();
528        return alloc;
529    }
530
531    static public Allocation createFromBitmapResource(RenderScript rs,
532                                                      Resources res,
533                                                      int id) {
534        return createFromBitmapResource(rs, res, id,
535                                        MipmapControl.MIPMAP_NONE,
536                                        USAGE_GRAPHICS_TEXTURE);
537    }
538
539    static public Allocation createFromString(RenderScript rs,
540                                              String str,
541                                              int usage) {
542        rs.validate();
543        byte[] allocArray = null;
544        try {
545            allocArray = str.getBytes("UTF-8");
546            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
547            alloc.copyFrom(allocArray);
548            return alloc;
549        }
550        catch (Exception e) {
551            throw new RSRuntimeException("Could not convert string to utf-8.");
552        }
553    }
554}
555
556
557