Allocation.java revision 21b4103e42cb0fa004cc4a978f49f63e7668ab0b
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    /**
50     * The usage of the allocation.  These signal to renderscript
51     * where to place the allocation in memory.
52     *
53     * SCRIPT The allocation will be bound to and accessed by
54     * scripts.
55     */
56    public static final int USAGE_SCRIPT = 0x0001;
57
58    /**
59     * GRAPHICS_TEXTURE The allcation will be used as a texture
60     * source by one or more graphcics programs.
61     *
62     */
63    public static final int USAGE_GRAPHICS_TEXTURE = 0x0002;
64
65    /**
66     * GRAPHICS_VERTEX The allocation will be used as a graphics
67     * mesh.
68     *
69     */
70    public static final int USAGE_GRAPHICS_VERTEX = 0x0004;
71
72
73    /**
74     * GRAPHICS_CONSTANTS The allocation will be used as the source
75     * of shader constants by one or more programs.
76     *
77     */
78    public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008;
79
80
81    /**
82     * Controls mipmap behavior when using the bitmap creation and
83     * update functions.
84     */
85    public enum MipmapControl {
86        /**
87         * No mipmaps will be generated and the type generated from the
88         * incoming bitmap will not contain additional LODs.
89         */
90        MIPMAP_NONE(0),
91
92        /**
93         * A Full mipmap chain will be created in script memory.  The
94         * type of the allocation will contain a full mipmap chain.  On
95         * upload to graphics the full chain will be transfered.
96         */
97        MIPMAP_FULL(1),
98
99        /**
100         * The type of the allocation will be the same as MIPMAP_NONE.
101         * It will not contain mipmaps.  On upload to graphics the
102         * graphics copy of the allocation data will contain a full
103         * mipmap chain generated from the top level in script memory.
104         */
105        MIPMAP_ON_SYNC_TO_TEXTURE(2);
106
107        int mID;
108        MipmapControl(int id) {
109            mID = id;
110        }
111    }
112
113    Allocation(int id, RenderScript rs, Type t, int usage) {
114        super(id, rs);
115        if ((usage & ~(USAGE_SCRIPT |
116                       USAGE_GRAPHICS_TEXTURE |
117                       USAGE_GRAPHICS_VERTEX |
118                       USAGE_GRAPHICS_CONSTANTS)) != 0) {
119            throw new RSIllegalArgumentException("Unknown usage specified.");
120        }
121        mType = t;
122    }
123
124    @Override
125    void updateFromNative() {
126        super.updateFromNative();
127        int typeID = mRS.nAllocationGetType(getID());
128        if(typeID != 0) {
129            mType = new Type(typeID, mRS);
130            mType.updateFromNative();
131        }
132    }
133
134    public Type getType() {
135        return mType;
136    }
137
138    public void syncAll(int srcLocation) {
139        switch (srcLocation) {
140        case USAGE_SCRIPT:
141        case USAGE_GRAPHICS_CONSTANTS:
142        case USAGE_GRAPHICS_TEXTURE:
143        case USAGE_GRAPHICS_VERTEX:
144            break;
145        default:
146            throw new RSIllegalArgumentException("Source must be exactly one usage type.");
147        }
148        mRS.validate();
149        mRS.nAllocationSyncAll(getID(), srcLocation);
150    }
151
152    public void copyFrom(BaseObj[] d) {
153        mRS.validate();
154        if (d.length != mType.getCount()) {
155            throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
156                                                 mType.getCount() + ", array length = " + d.length);
157        }
158        int i[] = new int[d.length];
159        for (int ct=0; ct < d.length; ct++) {
160            i[ct] = d[ct].getID();
161        }
162        copy1DRangeFrom(0, mType.getCount(), i);
163    }
164
165    private void validateBitmapFormat(Bitmap b) {
166        Bitmap.Config bc = b.getConfig();
167        switch (bc) {
168        case ALPHA_8:
169            if (mType.getElement().mKind != Element.DataKind.PIXEL_A) {
170                throw new RSIllegalArgumentException("Allocation kind is " +
171                                                     mType.getElement().mKind + ", type " +
172                                                     mType.getElement().mType +
173                                                     " of " + mType.getElement().getSizeBytes() +
174                                                     " bytes, passed bitmap was " + bc);
175            }
176            break;
177        case ARGB_8888:
178            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
179                (mType.getElement().getSizeBytes() != 4)) {
180                throw new RSIllegalArgumentException("Allocation kind is " +
181                                                     mType.getElement().mKind + ", type " +
182                                                     mType.getElement().mType +
183                                                     " of " + mType.getElement().getSizeBytes() +
184                                                     " bytes, passed bitmap was " + bc);
185            }
186            break;
187        case RGB_565:
188            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) ||
189                (mType.getElement().getSizeBytes() != 2)) {
190                throw new RSIllegalArgumentException("Allocation kind is " +
191                                                     mType.getElement().mKind + ", type " +
192                                                     mType.getElement().mType +
193                                                     " of " + mType.getElement().getSizeBytes() +
194                                                     " bytes, passed bitmap was " + bc);
195            }
196            break;
197        case ARGB_4444:
198            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
199                (mType.getElement().getSizeBytes() != 2)) {
200                throw new RSIllegalArgumentException("Allocation kind is " +
201                                                     mType.getElement().mKind + ", type " +
202                                                     mType.getElement().mType +
203                                                     " of " + mType.getElement().getSizeBytes() +
204                                                     " bytes, passed bitmap was " + bc);
205            }
206            break;
207
208        }
209    }
210
211    private void validateBitmapSize(Bitmap b) {
212        if(mType.getX() != b.getWidth() ||
213           mType.getY() != b.getHeight()) {
214            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
215        }
216    }
217
218    public void copyFrom(int[] d) {
219        mRS.validate();
220        copy1DRangeFrom(0, mType.getCount(), d);
221    }
222    public void copyFrom(short[] d) {
223        mRS.validate();
224        copy1DRangeFrom(0, mType.getCount(), d);
225    }
226    public void copyFrom(byte[] d) {
227        mRS.validate();
228        copy1DRangeFrom(0, mType.getCount(), d);
229    }
230    public void copyFrom(float[] d) {
231        mRS.validate();
232        copy1DRangeFrom(0, mType.getCount(), d);
233    }
234    public void copyFrom(Bitmap b) {
235        mRS.validate();
236        validateBitmapSize(b);
237        validateBitmapFormat(b);
238        mRS.nAllocationCopyFromBitmap(getID(), b);
239    }
240
241    /**
242     * This is only intended to be used by auto-generate code reflected from the
243     * renderscript script files.
244     *
245     * @param xoff
246     * @param fp
247     */
248    public void setFromFieldPacker(int xoff, FieldPacker fp) {
249        int eSize = mType.mElement.getSizeBytes();
250        final byte[] data = fp.getData();
251
252        int count = data.length / eSize;
253        if ((eSize * count) != data.length) {
254            throw new RSIllegalArgumentException("Field packer length " + data.length +
255                                               " not divisible by element size " + eSize + ".");
256        }
257        data1DChecks(xoff, count, data.length, data.length);
258        mRS.nAllocationData1D(getID(), xoff, 0, count, data, data.length);
259    }
260
261
262    /**
263     * This is only intended to be used by auto-generate code reflected from the
264     * renderscript script files.
265     *
266     * @param xoff
267     * @param component_number
268     * @param fp
269     */
270    public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
271        if (component_number >= mType.mElement.mElements.length) {
272            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
273        }
274        if(xoff < 0) {
275            throw new RSIllegalArgumentException("Offset must be >= 0.");
276        }
277
278        final byte[] data = fp.getData();
279        int eSize = mType.mElement.mElements[component_number].getSizeBytes();
280
281        if (data.length != eSize) {
282            throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
283                                               " does not match component size " + eSize + ".");
284        }
285
286        mRS.nAllocationElementData1D(getID(), xoff, 0, component_number, data, data.length);
287    }
288
289    private void data1DChecks(int off, int count, int len, int dataSize) {
290        mRS.validate();
291        if(off < 0) {
292            throw new RSIllegalArgumentException("Offset must be >= 0.");
293        }
294        if(count < 1) {
295            throw new RSIllegalArgumentException("Count must be >= 1.");
296        }
297        if((off + count) > mType.getCount()) {
298            throw new RSIllegalArgumentException("Overflow, Available count " + mType.getCount() +
299                                               ", got " + count + " at offset " + off + ".");
300        }
301        if((len) < dataSize) {
302            throw new RSIllegalArgumentException("Array too small for allocation type.");
303        }
304    }
305
306    /**
307     * Generate a mipmap chain.  Requires the type of the allocation
308     * include mipmaps.
309     *
310     * This function will generate a complete set of mipmaps from
311     * the top level lod and place them into the script memoryspace.
312     *
313     * If the allocation is also using other memory spaces a
314     * followup sync will be required.
315     */
316    public void generateMipmaps() {
317        mRS.nAllocationGenerateMipmaps(getID());
318    }
319
320    public void copy1DRangeFrom(int off, int count, int[] d) {
321        int dataSize = mType.mElement.getSizeBytes() * count;
322        data1DChecks(off, count, d.length * 4, dataSize);
323        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
324    }
325    public void copy1DRangeFrom(int off, int count, short[] d) {
326        int dataSize = mType.mElement.getSizeBytes() * count;
327        data1DChecks(off, count, d.length * 2, dataSize);
328        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
329    }
330    public void copy1DRangeFrom(int off, int count, byte[] d) {
331        int dataSize = mType.mElement.getSizeBytes() * count;
332        data1DChecks(off, count, d.length, dataSize);
333        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
334    }
335    public void copy1DRangeFrom(int off, int count, float[] d) {
336        int dataSize = mType.mElement.getSizeBytes() * count;
337        data1DChecks(off, count, d.length * 4, dataSize);
338        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
339    }
340
341    private void validate2DRange(int xoff, int yoff, int w, int h) {
342        if (xoff < 0 || yoff < 0) {
343            throw new RSIllegalArgumentException("Offset cannot be negative.");
344        }
345        if (h < 0 || w < 0) {
346            throw new RSIllegalArgumentException("Height or width cannot be negative.");
347        }
348        if ((xoff + w) > mType.mDimX ||
349            (yoff + h) > mType.mDimY) {
350            throw new RSIllegalArgumentException("Updated region larger than allocation.");
351        }
352    }
353
354    /**
355     * Copy a rectanglular region from the array into the
356     * allocation.  The incoming array is assumed to be tightly
357     * packed.
358     *
359     * @param xoff X offset of the region to update
360     * @param yoff Y offset of the region to update
361     * @param w Width of the incoming region to update
362     * @param h Height of the incoming region to update
363     * @param data to be placed into the allocation
364     */
365    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
366        mRS.validate();
367        validate2DRange(xoff, yoff, w, h);
368        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length);
369    }
370
371    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
372        mRS.validate();
373        validate2DRange(xoff, yoff, w, h);
374        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 2);
375    }
376
377    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
378        mRS.validate();
379        validate2DRange(xoff, yoff, w, h);
380        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 4);
381    }
382
383    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
384        mRS.validate();
385        validate2DRange(xoff, yoff, w, h);
386        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 4);
387    }
388
389    /**
390     * Copy a bitmap into an allocation.  The height and width of
391     * the update will use the height and width of the incoming
392     * bitmap.
393     *
394     * @param xoff X offset of the region to update
395     * @param yoff Y offset of the region to update
396     * @param data the bitmap to be copied
397     */
398    public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
399        mRS.validate();
400        validateBitmapFormat(data);
401        validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
402        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, data);
403    }
404
405
406    public void copyTo(Bitmap b) {
407        mRS.validate();
408        validateBitmapFormat(b);
409        validateBitmapSize(b);
410        mRS.nAllocationCopyToBitmap(getID(), b);
411    }
412
413    public void copyTo(byte[] d) {
414        mRS.validate();
415        mRS.nAllocationRead(getID(), d);
416    }
417
418    public void copyTo(short[] d) {
419        mRS.validate();
420        mRS.nAllocationRead(getID(), d);
421    }
422
423    public void copyTo(int[] d) {
424        mRS.validate();
425        mRS.nAllocationRead(getID(), d);
426    }
427
428    public void copyTo(float[] d) {
429        mRS.validate();
430        mRS.nAllocationRead(getID(), d);
431    }
432
433    /**
434     * Resize a 1D allocation.  The contents of the allocation are
435     * preserved.  If new elements are allocated objects are created
436     * with null contents and the new region is otherwise undefined.
437     *
438     * If the new region is smaller the references of any objects
439     * outside the new region will be released.
440     *
441     * A new type will be created with the new dimension.
442     *
443     * @param dimX The new size of the allocation.
444     */
445    public synchronized void resize(int dimX) {
446        if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
447            throw new RSInvalidStateException("Resize only support for 1D allocations at this time.");
448        }
449        mRS.nAllocationResize1D(getID(), dimX);
450        mRS.finish();  // Necessary because resize is fifoed and update is async.
451
452        int typeID = mRS.nAllocationGetType(getID());
453        mType = new Type(typeID, mRS);
454        mType.updateFromNative();
455    }
456
457    /*
458    public void resize(int dimX, int dimY) {
459        if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
460            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
461        }
462        if (mType.getY() == 0) {
463            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
464        }
465        mRS.nAllocationResize2D(getID(), dimX, dimY);
466    }
467    */
468
469
470
471    // creation
472
473    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
474    static {
475        mBitmapOptions.inScaled = false;
476    }
477
478    /**
479     *
480     * @param type renderscript type describing data layout
481     * @param mips specifies desired mipmap behaviour for the
482     *             allocation
483     * @param usage bit field specifying how the allocation is
484     *              utilized
485     */
486    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
487        rs.validate();
488        if (type.getID() == 0) {
489            throw new RSInvalidStateException("Bad Type");
490        }
491        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage);
492        if (id == 0) {
493            throw new RSRuntimeException("Allocation creation failed.");
494        }
495        return new Allocation(id, rs, type, usage);
496    }
497
498    /**
499     * Creates a renderscript allocation with the size specified by
500     * the type and no mipmaps generated by default
501     *
502     * @param rs Context to which the allocation will belong.
503     * @param type renderscript type describing data layout
504     * @param usage bit field specifying how the allocation is
505     *              utilized
506     *
507     * @return allocation
508     */
509    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
510        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
511    }
512
513    /**
514     * Creates a renderscript allocation for use by the script with
515     * the size specified by the type and no mipmaps generated by
516     * default
517     *
518     * @param rs Context to which the allocation will belong.
519     * @param type renderscript type describing data layout
520     *
521     * @return allocation
522     */
523    static public Allocation createTyped(RenderScript rs, Type type) {
524        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
525    }
526
527    /**
528     * Creates a renderscript allocation with a specified number of
529     * given elements
530     *
531     * @param rs Context to which the allocation will belong.
532     * @param e describes what each element of an allocation is
533     * @param count specifies the number of element in the allocation
534     * @param usage bit field specifying how the allocation is
535     *              utilized
536     *
537     * @return allocation
538     */
539    static public Allocation createSized(RenderScript rs, Element e,
540                                         int count, int usage) {
541        rs.validate();
542        Type.Builder b = new Type.Builder(rs, e);
543        b.setX(count);
544        Type t = b.create();
545
546        int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage);
547        if (id == 0) {
548            throw new RSRuntimeException("Allocation creation failed.");
549        }
550        return new Allocation(id, rs, t, usage);
551    }
552
553    /**
554     * Creates a renderscript allocation with a specified number of
555     * given elements
556     *
557     * @param rs Context to which the allocation will belong.
558     * @param e describes what each element of an allocation is
559     * @param count specifies the number of element in the allocation
560     *
561     * @return allocation
562     */
563    static public Allocation createSized(RenderScript rs, Element e, int count) {
564        return createSized(rs, e, count, USAGE_SCRIPT);
565    }
566
567    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
568        final Bitmap.Config bc = b.getConfig();
569        if (bc == Bitmap.Config.ALPHA_8) {
570            return Element.A_8(rs);
571        }
572        if (bc == Bitmap.Config.ARGB_4444) {
573            return Element.RGBA_4444(rs);
574        }
575        if (bc == Bitmap.Config.ARGB_8888) {
576            return Element.RGBA_8888(rs);
577        }
578        if (bc == Bitmap.Config.RGB_565) {
579            return Element.RGB_565(rs);
580        }
581        throw new RSInvalidStateException("Bad bitmap type: " + bc);
582    }
583
584    static Type typeFromBitmap(RenderScript rs, Bitmap b,
585                                       MipmapControl mip) {
586        Element e = elementFromBitmap(rs, b);
587        Type.Builder tb = new Type.Builder(rs, e);
588        tb.setX(b.getWidth());
589        tb.setY(b.getHeight());
590        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
591        return tb.create();
592    }
593
594    /**
595     * Creates a renderscript allocation from a bitmap
596     *
597     * @param rs Context to which the allocation will belong.
598     * @param b bitmap source for the allocation data
599     * @param mips specifies desired mipmap behaviour for the
600     *             allocation
601     * @param usage bit field specifying how the allocation is
602     *              utilized
603     *
604     * @return renderscript allocation containing bitmap data
605     *
606     */
607    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
608                                              MipmapControl mips,
609                                              int usage) {
610        rs.validate();
611        Type t = typeFromBitmap(rs, b, mips);
612
613        int id = rs.nAllocationCreateFromBitmap(t.getID(), mips.mID, b, usage);
614        if (id == 0) {
615            throw new RSRuntimeException("Load failed.");
616        }
617        return new Allocation(id, rs, t, usage);
618    }
619
620    /**
621     * Creates a non-mipmapped renderscript allocation to use as a
622     * graphics texture
623     *
624     * @param rs Context to which the allocation will belong.
625     * @param b bitmap source for the allocation data
626     *
627     * @return renderscript allocation containing bitmap data
628     *
629     */
630    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
631        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
632                                USAGE_GRAPHICS_TEXTURE);
633    }
634
635    /**
636     * Creates a cubemap allocation from a bitmap containing the
637     * horizontal list of cube faces. Each individual face must be
638     * the same size and power of 2
639     *
640     * @param rs Context to which the allocation will belong.
641     * @param b bitmap with cubemap faces layed out in the following
642     *          format: right, left, top, bottom, front, back
643     * @param mips specifies desired mipmap behaviour for the cubemap
644     * @param usage bit field specifying how the cubemap is utilized
645     *
646     * @return allocation containing cubemap data
647     *
648     */
649    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
650                                                     MipmapControl mips,
651                                                     int usage) {
652        rs.validate();
653
654        int height = b.getHeight();
655        int width = b.getWidth();
656
657        if (width % 6 != 0) {
658            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
659        }
660        if (width / 6 != height) {
661            throw new RSIllegalArgumentException("Only square cube map faces supported");
662        }
663        boolean isPow2 = (height & (height - 1)) == 0;
664        if (!isPow2) {
665            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
666        }
667
668        Element e = elementFromBitmap(rs, b);
669        Type.Builder tb = new Type.Builder(rs, e);
670        tb.setX(height);
671        tb.setY(height);
672        tb.setFaces(true);
673        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
674        Type t = tb.create();
675
676        int id = rs.nAllocationCubeCreateFromBitmap(t.getID(), mips.mID, b, usage);
677        if(id == 0) {
678            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
679        }
680        return new Allocation(id, rs, t, usage);
681    }
682
683    /**
684     * Creates a non-mipmapped cubemap allocation for use as a
685     * graphics texture from a bitmap containing the horizontal list
686     * of cube faces. Each individual face must be the same size and
687     * power of 2
688     *
689     * @param rs Context to which the allocation will belong.
690     * @param b bitmap with cubemap faces layed out in the following
691     *          format: right, left, top, bottom, front, back
692     *
693     * @return allocation containing cubemap data
694     *
695     */
696    static public Allocation createCubemapFromBitmap(RenderScript rs,
697                                                     Bitmap b) {
698        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
699                                       USAGE_GRAPHICS_TEXTURE);
700    }
701
702    /**
703     * Creates a cubemap allocation from 6 bitmaps containing
704     * the cube faces. All the faces must be the same size and
705     * power of 2
706     *
707     * @param rs Context to which the allocation will belong.
708     * @param xpos cubemap face in the positive x direction
709     * @param xneg cubemap face in the negative x direction
710     * @param ypos cubemap face in the positive y direction
711     * @param yneg cubemap face in the negative y direction
712     * @param zpos cubemap face in the positive z direction
713     * @param zneg cubemap face in the negative z direction
714     * @param mips specifies desired mipmap behaviour for the cubemap
715     * @param usage bit field specifying how the cubemap is utilized
716     *
717     * @return allocation containing cubemap data
718     *
719     */
720    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
721                                                        Bitmap xpos,
722                                                        Bitmap xneg,
723                                                        Bitmap ypos,
724                                                        Bitmap yneg,
725                                                        Bitmap zpos,
726                                                        Bitmap zneg,
727                                                        MipmapControl mips,
728                                                        int usage) {
729        int height = xpos.getHeight();
730        if (xpos.getWidth() != height ||
731            xneg.getWidth() != height || xneg.getHeight() != height ||
732            ypos.getWidth() != height || ypos.getHeight() != height ||
733            yneg.getWidth() != height || yneg.getHeight() != height ||
734            zpos.getWidth() != height || zpos.getHeight() != height ||
735            zneg.getWidth() != height || zneg.getHeight() != height) {
736            throw new RSIllegalArgumentException("Only square cube map faces supported");
737        }
738        boolean isPow2 = (height & (height - 1)) == 0;
739        if (!isPow2) {
740            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
741        }
742
743        Element e = elementFromBitmap(rs, xpos);
744        Type.Builder tb = new Type.Builder(rs, e);
745        tb.setX(height);
746        tb.setY(height);
747        tb.setFaces(true);
748        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
749        Type t = tb.create();
750        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
751
752        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
753        adapter.setFace(Type.CubemapFace.POSITVE_X);
754        adapter.copyFrom(xpos);
755        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
756        adapter.copyFrom(xneg);
757        adapter.setFace(Type.CubemapFace.POSITVE_Y);
758        adapter.copyFrom(ypos);
759        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
760        adapter.copyFrom(yneg);
761        adapter.setFace(Type.CubemapFace.POSITVE_Z);
762        adapter.copyFrom(zpos);
763        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
764        adapter.copyFrom(zneg);
765
766        return cubemap;
767    }
768
769    /**
770     * Creates a non-mipmapped cubemap allocation for use as a
771     * graphics texture from 6 bitmaps containing
772     * the cube faces. All the faces must be the same size and
773     * power of 2
774     *
775     * @param rs Context to which the allocation will belong.
776     * @param xpos cubemap face in the positive x direction
777     * @param xneg cubemap face in the negative x direction
778     * @param ypos cubemap face in the positive y direction
779     * @param yneg cubemap face in the negative y direction
780     * @param zpos cubemap face in the positive z direction
781     * @param zneg cubemap face in the negative z direction
782     *
783     * @return allocation containing cubemap data
784     *
785     */
786    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
787                                                        Bitmap xpos,
788                                                        Bitmap xneg,
789                                                        Bitmap ypos,
790                                                        Bitmap yneg,
791                                                        Bitmap zpos,
792                                                        Bitmap zneg) {
793        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
794                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
795                                          USAGE_GRAPHICS_TEXTURE);
796    }
797
798    /**
799     * Creates a renderscript allocation from the bitmap referenced
800     * by resource id
801     *
802     * @param rs Context to which the allocation will belong.
803     * @param res application resources
804     * @param id resource id to load the data from
805     * @param mips specifies desired mipmap behaviour for the
806     *             allocation
807     * @param usage bit field specifying how the allocation is
808     *              utilized
809     *
810     * @return renderscript allocation containing resource data
811     *
812     */
813    static public Allocation createFromBitmapResource(RenderScript rs,
814                                                      Resources res,
815                                                      int id,
816                                                      MipmapControl mips,
817                                                      int usage) {
818
819        rs.validate();
820        Bitmap b = BitmapFactory.decodeResource(res, id);
821        Allocation alloc = createFromBitmap(rs, b, mips, usage);
822        b.recycle();
823        return alloc;
824    }
825
826    /**
827     * Creates a non-mipmapped renderscript allocation to use as a
828     * graphics texture from the bitmap referenced by resource id
829     *
830     * @param rs Context to which the allocation will belong.
831     * @param res application resources
832     * @param id resource id to load the data from
833     *
834     * @return renderscript allocation containing resource data
835     *
836     */
837    static public Allocation createFromBitmapResource(RenderScript rs,
838                                                      Resources res,
839                                                      int id) {
840        return createFromBitmapResource(rs, res, id,
841                                        MipmapControl.MIPMAP_NONE,
842                                        USAGE_GRAPHICS_TEXTURE);
843    }
844
845    /**
846     * Creates a renderscript allocation containing string data
847     * encoded in UTF-8 format
848     *
849     * @param rs Context to which the allocation will belong.
850     * @param str string to create the allocation from
851     * @param usage bit field specifying how the allocaiton is
852     *              utilized
853     *
854     */
855    static public Allocation createFromString(RenderScript rs,
856                                              String str,
857                                              int usage) {
858        rs.validate();
859        byte[] allocArray = null;
860        try {
861            allocArray = str.getBytes("UTF-8");
862            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
863            alloc.copyFrom(allocArray);
864            return alloc;
865        }
866        catch (Exception e) {
867            throw new RSRuntimeException("Could not convert string to utf-8.");
868        }
869    }
870}
871
872
873