Allocation.java revision ed5bab93c6851dc4143d6e0d23ebf288e026936b
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    private void validateIsInt32() {
125        if ((mType.mElement.mType == Element.DataType.SIGNED_32) ||
126            (mType.mElement.mType == Element.DataType.UNSIGNED_32)) {
127            return;
128        }
129        throw new RSIllegalArgumentException(
130            "32 bit integer source does not match allocation type " + mType.mElement.mType);
131    }
132
133    private void validateIsInt16() {
134        if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
135            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
136            return;
137        }
138        throw new RSIllegalArgumentException(
139            "16 bit integer source does not match allocation type " + mType.mElement.mType);
140    }
141
142    private void validateIsInt8() {
143        if ((mType.mElement.mType == Element.DataType.SIGNED_8) ||
144            (mType.mElement.mType == Element.DataType.UNSIGNED_8)) {
145            return;
146        }
147        throw new RSIllegalArgumentException(
148            "8 bit integer source does not match allocation type " + mType.mElement.mType);
149    }
150
151    private void validateIsFloat32() {
152        if (mType.mElement.mType == Element.DataType.FLOAT_32) {
153            return;
154        }
155        throw new RSIllegalArgumentException(
156            "32 bit float source does not match allocation type " + mType.mElement.mType);
157    }
158
159    private void validateIsObject() {
160        if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) ||
161            (mType.mElement.mType == Element.DataType.RS_TYPE) ||
162            (mType.mElement.mType == Element.DataType.RS_ALLOCATION) ||
163            (mType.mElement.mType == Element.DataType.RS_SAMPLER) ||
164            (mType.mElement.mType == Element.DataType.RS_SCRIPT) ||
165            (mType.mElement.mType == Element.DataType.RS_MESH) ||
166            (mType.mElement.mType == Element.DataType.RS_PROGRAM_FRAGMENT) ||
167            (mType.mElement.mType == Element.DataType.RS_PROGRAM_VERTEX) ||
168            (mType.mElement.mType == Element.DataType.RS_PROGRAM_RASTER) ||
169            (mType.mElement.mType == Element.DataType.RS_PROGRAM_STORE)) {
170            return;
171        }
172        throw new RSIllegalArgumentException(
173            "Object source does not match allocation type " + mType.mElement.mType);
174    }
175
176    @Override
177    void updateFromNative() {
178        super.updateFromNative();
179        int typeID = mRS.nAllocationGetType(getID());
180        if(typeID != 0) {
181            mType = new Type(typeID, mRS);
182            mType.updateFromNative();
183        }
184    }
185
186    public Type getType() {
187        return mType;
188    }
189
190    public void syncAll(int srcLocation) {
191        switch (srcLocation) {
192        case USAGE_SCRIPT:
193        case USAGE_GRAPHICS_CONSTANTS:
194        case USAGE_GRAPHICS_TEXTURE:
195        case USAGE_GRAPHICS_VERTEX:
196            break;
197        default:
198            throw new RSIllegalArgumentException("Source must be exactly one usage type.");
199        }
200        mRS.validate();
201        mRS.nAllocationSyncAll(getID(), srcLocation);
202    }
203
204    public void copyFrom(BaseObj[] d) {
205        mRS.validate();
206        validateIsObject();
207        if (d.length != mType.getCount()) {
208            throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
209                                                 mType.getCount() + ", array length = " + d.length);
210        }
211        int i[] = new int[d.length];
212        for (int ct=0; ct < d.length; ct++) {
213            i[ct] = d[ct].getID();
214        }
215        copy1DRangeFromUnchecked(0, mType.getCount(), i);
216    }
217
218    private void validateBitmapFormat(Bitmap b) {
219        Bitmap.Config bc = b.getConfig();
220        switch (bc) {
221        case ALPHA_8:
222            if (mType.getElement().mKind != Element.DataKind.PIXEL_A) {
223                throw new RSIllegalArgumentException("Allocation kind is " +
224                                                     mType.getElement().mKind + ", type " +
225                                                     mType.getElement().mType +
226                                                     " of " + mType.getElement().getSizeBytes() +
227                                                     " bytes, passed bitmap was " + bc);
228            }
229            break;
230        case ARGB_8888:
231            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
232                (mType.getElement().getSizeBytes() != 4)) {
233                throw new RSIllegalArgumentException("Allocation kind is " +
234                                                     mType.getElement().mKind + ", type " +
235                                                     mType.getElement().mType +
236                                                     " of " + mType.getElement().getSizeBytes() +
237                                                     " bytes, passed bitmap was " + bc);
238            }
239            break;
240        case RGB_565:
241            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) ||
242                (mType.getElement().getSizeBytes() != 2)) {
243                throw new RSIllegalArgumentException("Allocation kind is " +
244                                                     mType.getElement().mKind + ", type " +
245                                                     mType.getElement().mType +
246                                                     " of " + mType.getElement().getSizeBytes() +
247                                                     " bytes, passed bitmap was " + bc);
248            }
249            break;
250        case ARGB_4444:
251            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
252                (mType.getElement().getSizeBytes() != 2)) {
253                throw new RSIllegalArgumentException("Allocation kind is " +
254                                                     mType.getElement().mKind + ", type " +
255                                                     mType.getElement().mType +
256                                                     " of " + mType.getElement().getSizeBytes() +
257                                                     " bytes, passed bitmap was " + bc);
258            }
259            break;
260
261        }
262    }
263
264    private void validateBitmapSize(Bitmap b) {
265        if(mType.getX() != b.getWidth() ||
266           mType.getY() != b.getHeight()) {
267            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
268        }
269    }
270
271    /**
272     * Copy an allocation from an array.  This variant is not type
273     * checked which allows an application to fill in structured
274     * data from an array.
275     *
276     * @param d the source data array
277     */
278    public void copyFromUnchecked(int[] d) {
279        mRS.validate();
280        copy1DRangeFromUnchecked(0, mType.getCount(), d);
281    }
282    /**
283     * Copy an allocation from an array.  This variant is not type
284     * checked which allows an application to fill in structured
285     * data from an array.
286     *
287     * @param d the source data array
288     */
289    public void copyFromUnchecked(short[] d) {
290        mRS.validate();
291        copy1DRangeFromUnchecked(0, mType.getCount(), d);
292    }
293    /**
294     * Copy an allocation from an array.  This variant is not type
295     * checked which allows an application to fill in structured
296     * data from an array.
297     *
298     * @param d the source data array
299     */
300    public void copyFromUnchecked(byte[] d) {
301        mRS.validate();
302        copy1DRangeFromUnchecked(0, mType.getCount(), d);
303    }
304    /**
305     * Copy an allocation from an array.  This variant is not type
306     * checked which allows an application to fill in structured
307     * data from an array.
308     *
309     * @param d the source data array
310     */
311    public void copyFromUnchecked(float[] d) {
312        mRS.validate();
313        copy1DRangeFromUnchecked(0, mType.getCount(), d);
314    }
315
316    /**
317     * Copy an allocation from an array.  This variant is type
318     * checked and will generate exceptions if the Allocation type
319     * is not a 32 bit integer type.
320     *
321     * @param d the source data array
322     */
323    public void copyFrom(int[] d) {
324        mRS.validate();
325        copy1DRangeFrom(0, mType.getCount(), d);
326    }
327
328    /**
329     * Copy an allocation from an array.  This variant is type
330     * checked and will generate exceptions if the Allocation type
331     * is not a 16 bit integer type.
332     *
333     * @param d the source data array
334     */
335    public void copyFrom(short[] d) {
336        mRS.validate();
337        copy1DRangeFrom(0, mType.getCount(), d);
338    }
339
340    /**
341     * Copy an allocation from an array.  This variant is type
342     * checked and will generate exceptions if the Allocation type
343     * is not a 8 bit integer type.
344     *
345     * @param d the source data array
346     */
347    public void copyFrom(byte[] d) {
348        mRS.validate();
349        copy1DRangeFrom(0, mType.getCount(), d);
350    }
351
352    /**
353     * Copy an allocation from an array.  This variant is type
354     * checked and will generate exceptions if the Allocation type
355     * is not a 32 bit float type.
356     *
357     * @param d the source data array
358     */
359    public void copyFrom(float[] d) {
360        mRS.validate();
361        copy1DRangeFrom(0, mType.getCount(), d);
362    }
363
364    /**
365     * Copy an allocation from a bitmap.  The height, width, and
366     * format of the bitmap must match the existing allocation.
367     *
368     * @param b the source bitmap
369     */
370    public void copyFrom(Bitmap b) {
371        mRS.validate();
372        validateBitmapSize(b);
373        validateBitmapFormat(b);
374        mRS.nAllocationCopyFromBitmap(getID(), b);
375    }
376
377    /**
378     * This is only intended to be used by auto-generate code reflected from the
379     * renderscript script files.
380     *
381     * @param xoff
382     * @param fp
383     */
384    public void setFromFieldPacker(int xoff, FieldPacker fp) {
385        int eSize = mType.mElement.getSizeBytes();
386        final byte[] data = fp.getData();
387
388        int count = data.length / eSize;
389        if ((eSize * count) != data.length) {
390            throw new RSIllegalArgumentException("Field packer length " + data.length +
391                                               " not divisible by element size " + eSize + ".");
392        }
393        data1DChecks(xoff, count, data.length, data.length);
394        mRS.nAllocationData1D(getID(), xoff, 0, count, data, data.length);
395    }
396
397    /**
398     * This is only intended to be used by auto-generate code reflected from the
399     * renderscript script files.
400     *
401     * @param xoff
402     * @param component_number
403     * @param fp
404     */
405    public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
406        if (component_number >= mType.mElement.mElements.length) {
407            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
408        }
409        if(xoff < 0) {
410            throw new RSIllegalArgumentException("Offset must be >= 0.");
411        }
412
413        final byte[] data = fp.getData();
414        int eSize = mType.mElement.mElements[component_number].getSizeBytes();
415
416        if (data.length != eSize) {
417            throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
418                                               " does not match component size " + eSize + ".");
419        }
420
421        mRS.nAllocationElementData1D(getID(), xoff, 0, component_number, data, data.length);
422    }
423
424    private void data1DChecks(int off, int count, int len, int dataSize) {
425        mRS.validate();
426        if(off < 0) {
427            throw new RSIllegalArgumentException("Offset must be >= 0.");
428        }
429        if(count < 1) {
430            throw new RSIllegalArgumentException("Count must be >= 1.");
431        }
432        if((off + count) > mType.getCount()) {
433            throw new RSIllegalArgumentException("Overflow, Available count " + mType.getCount() +
434                                               ", got " + count + " at offset " + off + ".");
435        }
436        if((len) < dataSize) {
437            throw new RSIllegalArgumentException("Array too small for allocation type.");
438        }
439    }
440
441    /**
442     * Generate a mipmap chain.  Requires the type of the allocation
443     * include mipmaps.
444     *
445     * This function will generate a complete set of mipmaps from
446     * the top level lod and place them into the script memoryspace.
447     *
448     * If the allocation is also using other memory spaces a
449     * followup sync will be required.
450     */
451    public void generateMipmaps() {
452        mRS.nAllocationGenerateMipmaps(getID());
453    }
454
455    /**
456     * Copy part of an allocation from an array.  This variant is
457     * not type checked which allows an application to fill in
458     * structured data from an array.
459     *
460     * @param off The offset of the first element to be copied.
461     * @param count The number of elements to be copied.
462     * @param d the source data array
463     */
464    public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
465        int dataSize = mType.mElement.getSizeBytes() * count;
466        data1DChecks(off, count, d.length * 4, dataSize);
467        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
468    }
469    /**
470     * Copy part of an allocation from an array.  This variant is
471     * not type checked which allows an application to fill in
472     * structured data from an array.
473     *
474     * @param off The offset of the first element to be copied.
475     * @param count The number of elements to be copied.
476     * @param d the source data array
477     */
478    public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
479        int dataSize = mType.mElement.getSizeBytes() * count;
480        data1DChecks(off, count, d.length * 2, dataSize);
481        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
482    }
483    /**
484     * Copy part of an allocation from an array.  This variant is
485     * not type checked which allows an application to fill in
486     * structured data from an array.
487     *
488     * @param off The offset of the first element to be copied.
489     * @param count The number of elements to be copied.
490     * @param d the source data array
491     */
492    public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
493        int dataSize = mType.mElement.getSizeBytes() * count;
494        data1DChecks(off, count, d.length, dataSize);
495        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
496    }
497    /**
498     * Copy part of an allocation from an array.  This variant is
499     * not type checked which allows an application to fill in
500     * structured data from an array.
501     *
502     * @param off The offset of the first element to be copied.
503     * @param count The number of elements to be copied.
504     * @param d the source data array
505     */
506    public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
507        int dataSize = mType.mElement.getSizeBytes() * count;
508        data1DChecks(off, count, d.length * 4, dataSize);
509        mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
510    }
511
512    /**
513     * Copy part of an allocation from an array.  This variant is
514     * type checked and will generate exceptions if the Allocation
515     * type is not a 32 bit integer type.
516     *
517     * @param off The offset of the first element to be copied.
518     * @param count The number of elements to be copied.
519     * @param d the source data array
520     */
521    public void copy1DRangeFrom(int off, int count, int[] d) {
522        validateIsInt32();
523        copy1DRangeFromUnchecked(off, count, d);
524    }
525
526    /**
527     * Copy part of an allocation from an array.  This variant is
528     * type checked and will generate exceptions if the Allocation
529     * type is not a 16 bit integer type.
530     *
531     * @param off The offset of the first element to be copied.
532     * @param count The number of elements to be copied.
533     * @param d the source data array
534     */
535    public void copy1DRangeFrom(int off, int count, short[] d) {
536        validateIsInt16();
537        copy1DRangeFromUnchecked(off, count, d);
538    }
539
540    /**
541     * Copy part of an allocation from an array.  This variant is
542     * type checked and will generate exceptions if the Allocation
543     * type is not a 8 bit integer type.
544     *
545     * @param off The offset of the first element to be copied.
546     * @param count The number of elements to be copied.
547     * @param d the source data array
548     */
549    public void copy1DRangeFrom(int off, int count, byte[] d) {
550        validateIsInt8();
551        copy1DRangeFromUnchecked(off, count, d);
552    }
553
554    /**
555     * Copy part of an allocation from an array.  This variant is
556     * type checked and will generate exceptions if the Allocation
557     * type is not a 32 bit float type.
558     *
559     * @param off The offset of the first element to be copied.
560     * @param count The number of elements to be copied.
561     * @param d the source data array
562     */
563    public void copy1DRangeFrom(int off, int count, float[] d) {
564        validateIsFloat32();
565        copy1DRangeFromUnchecked(off, count, d);
566    }
567
568    private void validate2DRange(int xoff, int yoff, int w, int h) {
569        if (xoff < 0 || yoff < 0) {
570            throw new RSIllegalArgumentException("Offset cannot be negative.");
571        }
572        if (h < 0 || w < 0) {
573            throw new RSIllegalArgumentException("Height or width cannot be negative.");
574        }
575        if ((xoff + w) > mType.mDimX ||
576            (yoff + h) > mType.mDimY) {
577            throw new RSIllegalArgumentException("Updated region larger than allocation.");
578        }
579    }
580
581    /**
582     * Copy a rectanglular region from the array into the
583     * allocation.  The incoming array is assumed to be tightly
584     * packed.
585     *
586     * @param xoff X offset of the region to update
587     * @param yoff Y offset of the region to update
588     * @param w Width of the incoming region to update
589     * @param h Height of the incoming region to update
590     * @param data to be placed into the allocation
591     */
592    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
593        mRS.validate();
594        validate2DRange(xoff, yoff, w, h);
595        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length);
596    }
597
598    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
599        mRS.validate();
600        validate2DRange(xoff, yoff, w, h);
601        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 2);
602    }
603
604    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
605        mRS.validate();
606        validate2DRange(xoff, yoff, w, h);
607        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 4);
608    }
609
610    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
611        mRS.validate();
612        validate2DRange(xoff, yoff, w, h);
613        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 4);
614    }
615
616    /**
617     * Copy a bitmap into an allocation.  The height and width of
618     * the update will use the height and width of the incoming
619     * bitmap.
620     *
621     * @param xoff X offset of the region to update
622     * @param yoff Y offset of the region to update
623     * @param data the bitmap to be copied
624     */
625    public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
626        mRS.validate();
627        validateBitmapFormat(data);
628        validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
629        mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, data);
630    }
631
632
633    public void copyTo(Bitmap b) {
634        mRS.validate();
635        validateBitmapFormat(b);
636        validateBitmapSize(b);
637        mRS.nAllocationCopyToBitmap(getID(), b);
638    }
639
640    public void copyTo(byte[] d) {
641        validateIsInt8();
642        mRS.validate();
643        mRS.nAllocationRead(getID(), d);
644    }
645
646    public void copyTo(short[] d) {
647        validateIsInt16();
648        mRS.validate();
649        mRS.nAllocationRead(getID(), d);
650    }
651
652    public void copyTo(int[] d) {
653        validateIsInt32();
654        mRS.validate();
655        mRS.nAllocationRead(getID(), d);
656    }
657
658    public void copyTo(float[] d) {
659        validateIsFloat32();
660        mRS.validate();
661        mRS.nAllocationRead(getID(), d);
662    }
663
664    /**
665     * Resize a 1D allocation.  The contents of the allocation are
666     * preserved.  If new elements are allocated objects are created
667     * with null contents and the new region is otherwise undefined.
668     *
669     * If the new region is smaller the references of any objects
670     * outside the new region will be released.
671     *
672     * A new type will be created with the new dimension.
673     *
674     * @param dimX The new size of the allocation.
675     */
676    public synchronized void resize(int dimX) {
677        if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
678            throw new RSInvalidStateException("Resize only support for 1D allocations at this time.");
679        }
680        mRS.nAllocationResize1D(getID(), dimX);
681        mRS.finish();  // Necessary because resize is fifoed and update is async.
682
683        int typeID = mRS.nAllocationGetType(getID());
684        mType = new Type(typeID, mRS);
685        mType.updateFromNative();
686    }
687
688    /*
689    public void resize(int dimX, int dimY) {
690        if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
691            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
692        }
693        if (mType.getY() == 0) {
694            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
695        }
696        mRS.nAllocationResize2D(getID(), dimX, dimY);
697    }
698    */
699
700
701
702    // creation
703
704    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
705    static {
706        mBitmapOptions.inScaled = false;
707    }
708
709    /**
710     *
711     * @param type renderscript type describing data layout
712     * @param mips specifies desired mipmap behaviour for the
713     *             allocation
714     * @param usage bit field specifying how the allocation is
715     *              utilized
716     */
717    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
718        rs.validate();
719        if (type.getID() == 0) {
720            throw new RSInvalidStateException("Bad Type");
721        }
722        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage);
723        if (id == 0) {
724            throw new RSRuntimeException("Allocation creation failed.");
725        }
726        return new Allocation(id, rs, type, usage);
727    }
728
729    /**
730     * Creates a renderscript allocation with the size specified by
731     * the type and no mipmaps generated by default
732     *
733     * @param rs Context to which the allocation will belong.
734     * @param type renderscript type describing data layout
735     * @param usage bit field specifying how the allocation is
736     *              utilized
737     *
738     * @return allocation
739     */
740    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
741        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
742    }
743
744    /**
745     * Creates a renderscript allocation for use by the script with
746     * the size specified by the type and no mipmaps generated by
747     * default
748     *
749     * @param rs Context to which the allocation will belong.
750     * @param type renderscript type describing data layout
751     *
752     * @return allocation
753     */
754    static public Allocation createTyped(RenderScript rs, Type type) {
755        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
756    }
757
758    /**
759     * Creates a renderscript allocation with a specified number of
760     * given elements
761     *
762     * @param rs Context to which the allocation will belong.
763     * @param e describes what each element of an allocation is
764     * @param count specifies the number of element in the allocation
765     * @param usage bit field specifying how the allocation is
766     *              utilized
767     *
768     * @return allocation
769     */
770    static public Allocation createSized(RenderScript rs, Element e,
771                                         int count, int usage) {
772        rs.validate();
773        Type.Builder b = new Type.Builder(rs, e);
774        b.setX(count);
775        Type t = b.create();
776
777        int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage);
778        if (id == 0) {
779            throw new RSRuntimeException("Allocation creation failed.");
780        }
781        return new Allocation(id, rs, t, usage);
782    }
783
784    /**
785     * Creates a renderscript allocation with a specified number of
786     * given elements
787     *
788     * @param rs Context to which the allocation will belong.
789     * @param e describes what each element of an allocation is
790     * @param count specifies the number of element in the allocation
791     *
792     * @return allocation
793     */
794    static public Allocation createSized(RenderScript rs, Element e, int count) {
795        return createSized(rs, e, count, USAGE_SCRIPT);
796    }
797
798    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
799        final Bitmap.Config bc = b.getConfig();
800        if (bc == Bitmap.Config.ALPHA_8) {
801            return Element.A_8(rs);
802        }
803        if (bc == Bitmap.Config.ARGB_4444) {
804            return Element.RGBA_4444(rs);
805        }
806        if (bc == Bitmap.Config.ARGB_8888) {
807            return Element.RGBA_8888(rs);
808        }
809        if (bc == Bitmap.Config.RGB_565) {
810            return Element.RGB_565(rs);
811        }
812        throw new RSInvalidStateException("Bad bitmap type: " + bc);
813    }
814
815    static Type typeFromBitmap(RenderScript rs, Bitmap b,
816                                       MipmapControl mip) {
817        Element e = elementFromBitmap(rs, b);
818        Type.Builder tb = new Type.Builder(rs, e);
819        tb.setX(b.getWidth());
820        tb.setY(b.getHeight());
821        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
822        return tb.create();
823    }
824
825    /**
826     * Creates a renderscript allocation from a bitmap
827     *
828     * @param rs Context to which the allocation will belong.
829     * @param b bitmap source for the allocation data
830     * @param mips specifies desired mipmap behaviour for the
831     *             allocation
832     * @param usage bit field specifying how the allocation is
833     *              utilized
834     *
835     * @return renderscript allocation containing bitmap data
836     *
837     */
838    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
839                                              MipmapControl mips,
840                                              int usage) {
841        rs.validate();
842        Type t = typeFromBitmap(rs, b, mips);
843
844        int id = rs.nAllocationCreateFromBitmap(t.getID(), mips.mID, b, usage);
845        if (id == 0) {
846            throw new RSRuntimeException("Load failed.");
847        }
848        return new Allocation(id, rs, t, usage);
849    }
850
851    /**
852     * Creates a non-mipmapped renderscript allocation to use as a
853     * graphics texture
854     *
855     * @param rs Context to which the allocation will belong.
856     * @param b bitmap source for the allocation data
857     *
858     * @return renderscript allocation containing bitmap data
859     *
860     */
861    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
862        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
863                                USAGE_GRAPHICS_TEXTURE);
864    }
865
866    /**
867     * Creates a cubemap allocation from a bitmap containing the
868     * horizontal list of cube faces. Each individual face must be
869     * the same size and power of 2
870     *
871     * @param rs Context to which the allocation will belong.
872     * @param b bitmap with cubemap faces layed out in the following
873     *          format: right, left, top, bottom, front, back
874     * @param mips specifies desired mipmap behaviour for the cubemap
875     * @param usage bit field specifying how the cubemap is utilized
876     *
877     * @return allocation containing cubemap data
878     *
879     */
880    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
881                                                     MipmapControl mips,
882                                                     int usage) {
883        rs.validate();
884
885        int height = b.getHeight();
886        int width = b.getWidth();
887
888        if (width % 6 != 0) {
889            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
890        }
891        if (width / 6 != height) {
892            throw new RSIllegalArgumentException("Only square cube map faces supported");
893        }
894        boolean isPow2 = (height & (height - 1)) == 0;
895        if (!isPow2) {
896            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
897        }
898
899        Element e = elementFromBitmap(rs, b);
900        Type.Builder tb = new Type.Builder(rs, e);
901        tb.setX(height);
902        tb.setY(height);
903        tb.setFaces(true);
904        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
905        Type t = tb.create();
906
907        int id = rs.nAllocationCubeCreateFromBitmap(t.getID(), mips.mID, b, usage);
908        if(id == 0) {
909            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
910        }
911        return new Allocation(id, rs, t, usage);
912    }
913
914    /**
915     * Creates a non-mipmapped cubemap allocation for use as a
916     * graphics texture from a bitmap containing the horizontal list
917     * of cube faces. Each individual face must be the same size and
918     * power of 2
919     *
920     * @param rs Context to which the allocation will belong.
921     * @param b bitmap with cubemap faces layed out in the following
922     *          format: right, left, top, bottom, front, back
923     *
924     * @return allocation containing cubemap data
925     *
926     */
927    static public Allocation createCubemapFromBitmap(RenderScript rs,
928                                                     Bitmap b) {
929        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
930                                       USAGE_GRAPHICS_TEXTURE);
931    }
932
933    /**
934     * Creates a cubemap allocation from 6 bitmaps containing
935     * the cube faces. All the faces must be the same size and
936     * power of 2
937     *
938     * @param rs Context to which the allocation will belong.
939     * @param xpos cubemap face in the positive x direction
940     * @param xneg cubemap face in the negative x direction
941     * @param ypos cubemap face in the positive y direction
942     * @param yneg cubemap face in the negative y direction
943     * @param zpos cubemap face in the positive z direction
944     * @param zneg cubemap face in the negative z direction
945     * @param mips specifies desired mipmap behaviour for the cubemap
946     * @param usage bit field specifying how the cubemap is utilized
947     *
948     * @return allocation containing cubemap data
949     *
950     */
951    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
952                                                        Bitmap xpos,
953                                                        Bitmap xneg,
954                                                        Bitmap ypos,
955                                                        Bitmap yneg,
956                                                        Bitmap zpos,
957                                                        Bitmap zneg,
958                                                        MipmapControl mips,
959                                                        int usage) {
960        int height = xpos.getHeight();
961        if (xpos.getWidth() != height ||
962            xneg.getWidth() != height || xneg.getHeight() != height ||
963            ypos.getWidth() != height || ypos.getHeight() != height ||
964            yneg.getWidth() != height || yneg.getHeight() != height ||
965            zpos.getWidth() != height || zpos.getHeight() != height ||
966            zneg.getWidth() != height || zneg.getHeight() != height) {
967            throw new RSIllegalArgumentException("Only square cube map faces supported");
968        }
969        boolean isPow2 = (height & (height - 1)) == 0;
970        if (!isPow2) {
971            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
972        }
973
974        Element e = elementFromBitmap(rs, xpos);
975        Type.Builder tb = new Type.Builder(rs, e);
976        tb.setX(height);
977        tb.setY(height);
978        tb.setFaces(true);
979        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
980        Type t = tb.create();
981        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
982
983        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
984        adapter.setFace(Type.CubemapFace.POSITVE_X);
985        adapter.copyFrom(xpos);
986        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
987        adapter.copyFrom(xneg);
988        adapter.setFace(Type.CubemapFace.POSITVE_Y);
989        adapter.copyFrom(ypos);
990        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
991        adapter.copyFrom(yneg);
992        adapter.setFace(Type.CubemapFace.POSITVE_Z);
993        adapter.copyFrom(zpos);
994        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
995        adapter.copyFrom(zneg);
996
997        return cubemap;
998    }
999
1000    /**
1001     * Creates a non-mipmapped cubemap allocation for use as a
1002     * graphics texture from 6 bitmaps containing
1003     * the cube faces. All the faces must be the same size and
1004     * power of 2
1005     *
1006     * @param rs Context to which the allocation will belong.
1007     * @param xpos cubemap face in the positive x direction
1008     * @param xneg cubemap face in the negative x direction
1009     * @param ypos cubemap face in the positive y direction
1010     * @param yneg cubemap face in the negative y direction
1011     * @param zpos cubemap face in the positive z direction
1012     * @param zneg cubemap face in the negative z direction
1013     *
1014     * @return allocation containing cubemap data
1015     *
1016     */
1017    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
1018                                                        Bitmap xpos,
1019                                                        Bitmap xneg,
1020                                                        Bitmap ypos,
1021                                                        Bitmap yneg,
1022                                                        Bitmap zpos,
1023                                                        Bitmap zneg) {
1024        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
1025                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
1026                                          USAGE_GRAPHICS_TEXTURE);
1027    }
1028
1029    /**
1030     * Creates a renderscript allocation from the bitmap referenced
1031     * by resource id
1032     *
1033     * @param rs Context to which the allocation will belong.
1034     * @param res application resources
1035     * @param id resource id to load the data from
1036     * @param mips specifies desired mipmap behaviour for the
1037     *             allocation
1038     * @param usage bit field specifying how the allocation is
1039     *              utilized
1040     *
1041     * @return renderscript allocation containing resource data
1042     *
1043     */
1044    static public Allocation createFromBitmapResource(RenderScript rs,
1045                                                      Resources res,
1046                                                      int id,
1047                                                      MipmapControl mips,
1048                                                      int usage) {
1049
1050        rs.validate();
1051        Bitmap b = BitmapFactory.decodeResource(res, id);
1052        Allocation alloc = createFromBitmap(rs, b, mips, usage);
1053        b.recycle();
1054        return alloc;
1055    }
1056
1057    /**
1058     * Creates a non-mipmapped renderscript allocation to use as a
1059     * graphics texture from the bitmap referenced by resource id
1060     *
1061     * @param rs Context to which the allocation will belong.
1062     * @param res application resources
1063     * @param id resource id to load the data from
1064     *
1065     * @return renderscript allocation containing resource data
1066     *
1067     */
1068    static public Allocation createFromBitmapResource(RenderScript rs,
1069                                                      Resources res,
1070                                                      int id) {
1071        return createFromBitmapResource(rs, res, id,
1072                                        MipmapControl.MIPMAP_NONE,
1073                                        USAGE_GRAPHICS_TEXTURE);
1074    }
1075
1076    /**
1077     * Creates a renderscript allocation containing string data
1078     * encoded in UTF-8 format
1079     *
1080     * @param rs Context to which the allocation will belong.
1081     * @param str string to create the allocation from
1082     * @param usage bit field specifying how the allocaiton is
1083     *              utilized
1084     *
1085     */
1086    static public Allocation createFromString(RenderScript rs,
1087                                              String str,
1088                                              int usage) {
1089        rs.validate();
1090        byte[] allocArray = null;
1091        try {
1092            allocArray = str.getBytes("UTF-8");
1093            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
1094            alloc.copyFrom(allocArray);
1095            return alloc;
1096        }
1097        catch (Exception e) {
1098            throw new RSRuntimeException("Could not convert string to utf-8.");
1099        }
1100    }
1101}
1102
1103
1104