Allocation.java revision 452a7661e8b06459b75493b441d33244939c1153
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 * <p>
30 * Memory allocation class for renderscript.  An allocation combines a
31 * {@link android.renderscript.Type} with the memory to provide storage for user data and objects.
32 * This implies that all memory in Renderscript is typed.
33 * </p>
34 *
35 * <p>Allocations are the primary way data moves into and out of scripts. Memory is user
36 * synchronized and it's possible for allocations to exist in multiple memory spaces
37 * concurrently. Currently those spaces are:</p>
38 * <ul>
39 * <li>Script: accessable by RS scripts.</li>
40 * <li>Graphics Texture: accessable as a graphics texture.</li>
41 * <li>Graphics Vertex: accessable as graphical vertex data.</li>
42 * <li>Graphics Constants: Accessable as constants in user shaders</li>
43 * </ul>
44 * </p>
45 * <p>
46 * For example, when creating a allocation for a texture, the user can
47 * specify its memory spaces as both script and textures. This means that it can both
48 * be used as script binding and as a GPU texture for rendering. To maintain
49 * synchronization if a script modifies an allocation used by other targets it must
50 * call a synchronizing function to push the updates to the memory, otherwise the results
51 * are undefined.
52 * </p>
53 * <p>By default, Android system side updates are always applied to the script accessable
54 * memory. If this is not present, they are then applied to the various HW
55 * memory types.  A {@link android.renderscript.Allocation#syncAll syncAll()}
56 * call is necessary after the script data is updated to
57 * keep the other memory spaces in sync.</p>
58 *
59 * <p>Allocation data is uploaded in one of two primary ways. For simple
60 * arrays there are copyFrom() functions that take an array from the control code and
61 * copy it to the slave memory store. Both type checked and unchecked copies are provided.
62 * The unchecked variants exist to allow apps to copy over arrays of structures from a
63 * control language that does not support structures.</p>
64 *
65 **/
66public class Allocation extends BaseObj {
67    Type mType;
68    Bitmap mBitmap;
69    int mUsage;
70    Allocation mAdaptedAllocation;
71
72    boolean mConstrainedLOD;
73    boolean mConstrainedFace;
74    boolean mConstrainedY;
75    boolean mConstrainedZ;
76    int mSelectedY;
77    int mSelectedZ;
78    int mSelectedLOD;
79    Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
80
81    int mCurrentDimX;
82    int mCurrentDimY;
83    int mCurrentDimZ;
84    int mCurrentCount;
85
86
87    /**
88     * The usage of the allocation.  These signal to renderscript
89     * where to place the allocation in memory.
90     *
91     * SCRIPT The allocation will be bound to and accessed by
92     * scripts.
93     */
94    public static final int USAGE_SCRIPT = 0x0001;
95
96    /**
97     * GRAPHICS_TEXTURE The allcation will be used as a texture
98     * source by one or more graphics programs.
99     *
100     */
101    public static final int USAGE_GRAPHICS_TEXTURE = 0x0002;
102
103    /**
104     * GRAPHICS_VERTEX The allocation will be used as a graphics
105     * mesh.
106     *
107     */
108    public static final int USAGE_GRAPHICS_VERTEX = 0x0004;
109
110
111    /**
112     * GRAPHICS_CONSTANTS The allocation will be used as the source
113     * of shader constants by one or more programs.
114     *
115     */
116    public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008;
117
118    /**
119     * USAGE_GRAPHICS_RENDER_TARGET The allcation will be used as a
120     * target for offscreen rendering
121     *
122     */
123    public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010;
124
125
126    /**
127     * Controls mipmap behavior when using the bitmap creation and
128     * update functions.
129     */
130    public enum MipmapControl {
131        /**
132         * No mipmaps will be generated and the type generated from the
133         * incoming bitmap will not contain additional LODs.
134         */
135        MIPMAP_NONE(0),
136
137        /**
138         * A Full mipmap chain will be created in script memory.  The
139         * type of the allocation will contain a full mipmap chain.  On
140         * upload to graphics the full chain will be transfered.
141         */
142        MIPMAP_FULL(1),
143
144        /**
145         * The type of the allocation will be the same as MIPMAP_NONE.
146         * It will not contain mipmaps.  On upload to graphics the
147         * graphics copy of the allocation data will contain a full
148         * mipmap chain generated from the top level in script memory.
149         */
150        MIPMAP_ON_SYNC_TO_TEXTURE(2);
151
152        int mID;
153        MipmapControl(int id) {
154            mID = id;
155        }
156    }
157
158    private void updateCacheInfo(Type t) {
159        mCurrentDimX = t.getX();
160        mCurrentDimY = t.getY();
161        mCurrentDimZ = t.getZ();
162        mCurrentCount = mCurrentDimX;
163        if (mCurrentDimY > 1) {
164            mCurrentCount *= mCurrentDimY;
165        }
166        if (mCurrentDimZ > 1) {
167            mCurrentCount *= mCurrentDimZ;
168        }
169    }
170
171    Allocation(int id, RenderScript rs, Type t, int usage) {
172        super(id, rs);
173        if ((usage & ~(USAGE_SCRIPT |
174                       USAGE_GRAPHICS_TEXTURE |
175                       USAGE_GRAPHICS_VERTEX |
176                       USAGE_GRAPHICS_CONSTANTS |
177                       USAGE_GRAPHICS_RENDER_TARGET)) != 0) {
178            throw new RSIllegalArgumentException("Unknown usage specified.");
179        }
180        mType = t;
181
182        if (t != null) {
183            updateCacheInfo(t);
184        }
185    }
186
187    private void validateIsInt32() {
188        if ((mType.mElement.mType == Element.DataType.SIGNED_32) ||
189            (mType.mElement.mType == Element.DataType.UNSIGNED_32)) {
190            return;
191        }
192        throw new RSIllegalArgumentException(
193            "32 bit integer source does not match allocation type " + mType.mElement.mType);
194    }
195
196    private void validateIsInt16() {
197        if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
198            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
199            return;
200        }
201        throw new RSIllegalArgumentException(
202            "16 bit integer source does not match allocation type " + mType.mElement.mType);
203    }
204
205    private void validateIsInt8() {
206        if ((mType.mElement.mType == Element.DataType.SIGNED_8) ||
207            (mType.mElement.mType == Element.DataType.UNSIGNED_8)) {
208            return;
209        }
210        throw new RSIllegalArgumentException(
211            "8 bit integer source does not match allocation type " + mType.mElement.mType);
212    }
213
214    private void validateIsFloat32() {
215        if (mType.mElement.mType == Element.DataType.FLOAT_32) {
216            return;
217        }
218        throw new RSIllegalArgumentException(
219            "32 bit float source does not match allocation type " + mType.mElement.mType);
220    }
221
222    private void validateIsObject() {
223        if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) ||
224            (mType.mElement.mType == Element.DataType.RS_TYPE) ||
225            (mType.mElement.mType == Element.DataType.RS_ALLOCATION) ||
226            (mType.mElement.mType == Element.DataType.RS_SAMPLER) ||
227            (mType.mElement.mType == Element.DataType.RS_SCRIPT) ||
228            (mType.mElement.mType == Element.DataType.RS_MESH) ||
229            (mType.mElement.mType == Element.DataType.RS_PROGRAM_FRAGMENT) ||
230            (mType.mElement.mType == Element.DataType.RS_PROGRAM_VERTEX) ||
231            (mType.mElement.mType == Element.DataType.RS_PROGRAM_RASTER) ||
232            (mType.mElement.mType == Element.DataType.RS_PROGRAM_STORE)) {
233            return;
234        }
235        throw new RSIllegalArgumentException(
236            "Object source does not match allocation type " + mType.mElement.mType);
237    }
238
239    @Override
240    void updateFromNative() {
241        super.updateFromNative();
242        int typeID = mRS.nAllocationGetType(getID());
243        if(typeID != 0) {
244            mType = new Type(typeID, mRS);
245            mType.updateFromNative();
246        }
247    }
248
249    public Type getType() {
250        return mType;
251    }
252
253    public void syncAll(int srcLocation) {
254        switch (srcLocation) {
255        case USAGE_SCRIPT:
256        case USAGE_GRAPHICS_CONSTANTS:
257        case USAGE_GRAPHICS_TEXTURE:
258        case USAGE_GRAPHICS_VERTEX:
259            break;
260        default:
261            throw new RSIllegalArgumentException("Source must be exactly one usage type.");
262        }
263        mRS.validate();
264        mRS.nAllocationSyncAll(getID(), srcLocation);
265    }
266
267    public void copyFrom(BaseObj[] d) {
268        mRS.validate();
269        validateIsObject();
270        if (d.length != mCurrentCount) {
271            throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
272                                                 mCurrentCount + ", array length = " + d.length);
273        }
274        int i[] = new int[d.length];
275        for (int ct=0; ct < d.length; ct++) {
276            i[ct] = d[ct].getID();
277        }
278        copy1DRangeFromUnchecked(0, mCurrentCount, i);
279    }
280
281    private void validateBitmapFormat(Bitmap b) {
282        Bitmap.Config bc = b.getConfig();
283        switch (bc) {
284        case ALPHA_8:
285            if (mType.getElement().mKind != Element.DataKind.PIXEL_A) {
286                throw new RSIllegalArgumentException("Allocation kind is " +
287                                                     mType.getElement().mKind + ", type " +
288                                                     mType.getElement().mType +
289                                                     " of " + mType.getElement().getSizeBytes() +
290                                                     " bytes, passed bitmap was " + bc);
291            }
292            break;
293        case ARGB_8888:
294            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
295                (mType.getElement().getSizeBytes() != 4)) {
296                throw new RSIllegalArgumentException("Allocation kind is " +
297                                                     mType.getElement().mKind + ", type " +
298                                                     mType.getElement().mType +
299                                                     " of " + mType.getElement().getSizeBytes() +
300                                                     " bytes, passed bitmap was " + bc);
301            }
302            break;
303        case RGB_565:
304            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) ||
305                (mType.getElement().getSizeBytes() != 2)) {
306                throw new RSIllegalArgumentException("Allocation kind is " +
307                                                     mType.getElement().mKind + ", type " +
308                                                     mType.getElement().mType +
309                                                     " of " + mType.getElement().getSizeBytes() +
310                                                     " bytes, passed bitmap was " + bc);
311            }
312            break;
313        case ARGB_4444:
314            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
315                (mType.getElement().getSizeBytes() != 2)) {
316                throw new RSIllegalArgumentException("Allocation kind is " +
317                                                     mType.getElement().mKind + ", type " +
318                                                     mType.getElement().mType +
319                                                     " of " + mType.getElement().getSizeBytes() +
320                                                     " bytes, passed bitmap was " + bc);
321            }
322            break;
323
324        }
325    }
326
327    private void validateBitmapSize(Bitmap b) {
328        if((mCurrentDimX != b.getWidth()) || (mCurrentDimY != b.getHeight())) {
329            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
330        }
331    }
332
333    /**
334     * Copy an allocation from an array.  This variant is not type
335     * checked which allows an application to fill in structured
336     * data from an array.
337     *
338     * @param d the source data array
339     */
340    public void copyFromUnchecked(int[] d) {
341        mRS.validate();
342        copy1DRangeFromUnchecked(0, mCurrentCount, d);
343    }
344    /**
345     * Copy an allocation from an array.  This variant is not type
346     * checked which allows an application to fill in structured
347     * data from an array.
348     *
349     * @param d the source data array
350     */
351    public void copyFromUnchecked(short[] d) {
352        mRS.validate();
353        copy1DRangeFromUnchecked(0, mCurrentCount, d);
354    }
355    /**
356     * Copy an allocation from an array.  This variant is not type
357     * checked which allows an application to fill in structured
358     * data from an array.
359     *
360     * @param d the source data array
361     */
362    public void copyFromUnchecked(byte[] d) {
363        mRS.validate();
364        copy1DRangeFromUnchecked(0, mCurrentCount, d);
365    }
366    /**
367     * Copy an allocation from an array.  This variant is not type
368     * checked which allows an application to fill in structured
369     * data from an array.
370     *
371     * @param d the source data array
372     */
373    public void copyFromUnchecked(float[] d) {
374        mRS.validate();
375        copy1DRangeFromUnchecked(0, mCurrentCount, d);
376    }
377
378    /**
379     * Copy an allocation from an array.  This variant is type
380     * checked and will generate exceptions if the Allocation type
381     * is not a 32 bit integer type.
382     *
383     * @param d the source data array
384     */
385    public void copyFrom(int[] d) {
386        mRS.validate();
387        copy1DRangeFrom(0, mCurrentCount, d);
388    }
389
390    /**
391     * Copy an allocation from an array.  This variant is type
392     * checked and will generate exceptions if the Allocation type
393     * is not a 16 bit integer type.
394     *
395     * @param d the source data array
396     */
397    public void copyFrom(short[] d) {
398        mRS.validate();
399        copy1DRangeFrom(0, mCurrentCount, d);
400    }
401
402    /**
403     * Copy an allocation from an array.  This variant is type
404     * checked and will generate exceptions if the Allocation type
405     * is not a 8 bit integer type.
406     *
407     * @param d the source data array
408     */
409    public void copyFrom(byte[] d) {
410        mRS.validate();
411        copy1DRangeFrom(0, mCurrentCount, d);
412    }
413
414    /**
415     * Copy an allocation from an array.  This variant is type
416     * checked and will generate exceptions if the Allocation type
417     * is not a 32 bit float type.
418     *
419     * @param d the source data array
420     */
421    public void copyFrom(float[] d) {
422        mRS.validate();
423        copy1DRangeFrom(0, mCurrentCount, d);
424    }
425
426    /**
427     * Copy an allocation from a bitmap.  The height, width, and
428     * format of the bitmap must match the existing allocation.
429     *
430     * @param b the source bitmap
431     */
432    public void copyFrom(Bitmap b) {
433        mRS.validate();
434        validateBitmapSize(b);
435        validateBitmapFormat(b);
436        mRS.nAllocationCopyFromBitmap(getID(), b);
437    }
438
439    /**
440     * This is only intended to be used by auto-generate code reflected from the
441     * renderscript script files.
442     *
443     * @param xoff
444     * @param fp
445     */
446    public void setFromFieldPacker(int xoff, FieldPacker fp) {
447        int eSize = mType.mElement.getSizeBytes();
448        final byte[] data = fp.getData();
449
450        int count = data.length / eSize;
451        if ((eSize * count) != data.length) {
452            throw new RSIllegalArgumentException("Field packer length " + data.length +
453                                               " not divisible by element size " + eSize + ".");
454        }
455        copy1DRangeFromUnchecked(xoff, count, data);
456    }
457
458    /**
459     * This is only intended to be used by auto-generate code reflected from the
460     * renderscript script files.
461     *
462     * @param xoff
463     * @param component_number
464     * @param fp
465     */
466    public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
467        if (component_number >= mType.mElement.mElements.length) {
468            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
469        }
470        if(xoff < 0) {
471            throw new RSIllegalArgumentException("Offset must be >= 0.");
472        }
473
474        final byte[] data = fp.getData();
475        int eSize = mType.mElement.mElements[component_number].getSizeBytes();
476
477        if (data.length != eSize) {
478            throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
479                                               " does not match component size " + eSize + ".");
480        }
481
482        mRS.nAllocationElementData1D(getID(), xoff, mSelectedLOD,
483                                     component_number, data, data.length);
484    }
485
486    private void data1DChecks(int off, int count, int len, int dataSize) {
487        mRS.validate();
488        if(off < 0) {
489            throw new RSIllegalArgumentException("Offset must be >= 0.");
490        }
491        if(count < 1) {
492            throw new RSIllegalArgumentException("Count must be >= 1.");
493        }
494        if((off + count) > mCurrentCount) {
495            throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
496                                               ", got " + count + " at offset " + off + ".");
497        }
498        if(len < dataSize) {
499            throw new RSIllegalArgumentException("Array too small for allocation type.");
500        }
501    }
502
503    /**
504     * Generate a mipmap chain.  Requires the type of the allocation
505     * include mipmaps.
506     *
507     * This function will generate a complete set of mipmaps from
508     * the top level lod and place them into the script memoryspace.
509     *
510     * If the allocation is also using other memory spaces a
511     * followup sync will be required.
512     */
513    public void generateMipmaps() {
514        mRS.nAllocationGenerateMipmaps(getID());
515    }
516
517    /**
518     * Copy part of an allocation from an array.  This variant is
519     * not type checked which allows an application to fill in
520     * structured data from an array.
521     *
522     * @param off The offset of the first element to be copied.
523     * @param count The number of elements to be copied.
524     * @param d the source data array
525     */
526    public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
527        int dataSize = mType.mElement.getSizeBytes() * count;
528        data1DChecks(off, count, d.length * 4, dataSize);
529        mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
530    }
531    /**
532     * Copy part of an allocation from an array.  This variant is
533     * not type checked which allows an application to fill in
534     * structured data from an array.
535     *
536     * @param off The offset of the first element to be copied.
537     * @param count The number of elements to be copied.
538     * @param d the source data array
539     */
540    public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
541        int dataSize = mType.mElement.getSizeBytes() * count;
542        data1DChecks(off, count, d.length * 2, dataSize);
543        mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
544    }
545    /**
546     * Copy part of an allocation from an array.  This variant is
547     * not type checked which allows an application to fill in
548     * structured data from an array.
549     *
550     * @param off The offset of the first element to be copied.
551     * @param count The number of elements to be copied.
552     * @param d the source data array
553     */
554    public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
555        int dataSize = mType.mElement.getSizeBytes() * count;
556        data1DChecks(off, count, d.length, dataSize);
557        mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
558    }
559    /**
560     * Copy part of an allocation from an array.  This variant is
561     * not type checked which allows an application to fill in
562     * structured data from an array.
563     *
564     * @param off The offset of the first element to be copied.
565     * @param count The number of elements to be copied.
566     * @param d the source data array
567     */
568    public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
569        int dataSize = mType.mElement.getSizeBytes() * count;
570        data1DChecks(off, count, d.length * 4, dataSize);
571        mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
572    }
573
574    /**
575     * Copy part of an allocation from an array.  This variant is
576     * type checked and will generate exceptions if the Allocation
577     * type is not a 32 bit integer type.
578     *
579     * @param off The offset of the first element to be copied.
580     * @param count The number of elements to be copied.
581     * @param d the source data array
582     */
583    public void copy1DRangeFrom(int off, int count, int[] d) {
584        validateIsInt32();
585        copy1DRangeFromUnchecked(off, count, d);
586    }
587
588    /**
589     * Copy part of an allocation from an array.  This variant is
590     * type checked and will generate exceptions if the Allocation
591     * type is not a 16 bit integer type.
592     *
593     * @param off The offset of the first element to be copied.
594     * @param count The number of elements to be copied.
595     * @param d the source data array
596     */
597    public void copy1DRangeFrom(int off, int count, short[] d) {
598        validateIsInt16();
599        copy1DRangeFromUnchecked(off, count, d);
600    }
601
602    /**
603     * Copy part of an allocation from an array.  This variant is
604     * type checked and will generate exceptions if the Allocation
605     * type is not a 8 bit integer type.
606     *
607     * @param off The offset of the first element to be copied.
608     * @param count The number of elements to be copied.
609     * @param d the source data array
610     */
611    public void copy1DRangeFrom(int off, int count, byte[] d) {
612        validateIsInt8();
613        copy1DRangeFromUnchecked(off, count, d);
614    }
615
616    /**
617     * Copy part of an allocation from an array.  This variant is
618     * type checked and will generate exceptions if the Allocation
619     * type is not a 32 bit float type.
620     *
621     * @param off The offset of the first element to be copied.
622     * @param count The number of elements to be copied.
623     * @param d the source data array.
624     */
625    public void copy1DRangeFrom(int off, int count, float[] d) {
626        validateIsFloat32();
627        copy1DRangeFromUnchecked(off, count, d);
628    }
629
630     /**
631     * Copy part of an allocation from another allocation.
632     *
633     * @param off The offset of the first element to be copied.
634     * @param count The number of elements to be copied.
635     * @param data the source data allocation.
636     * @param dataOff off The offset of the first element in data to
637     *          be copied.
638     */
639    public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
640        mRS.nAllocationData2D(getID(), off, 0,
641                              mSelectedLOD, mSelectedFace.mID,
642                              count, 1, data.getID(), dataOff, 0,
643                              data.mSelectedLOD, data.mSelectedFace.mID);
644    }
645
646    private void validate2DRange(int xoff, int yoff, int w, int h) {
647        if (mAdaptedAllocation != null) {
648
649        } else {
650
651            if (xoff < 0 || yoff < 0) {
652                throw new RSIllegalArgumentException("Offset cannot be negative.");
653            }
654            if (h < 0 || w < 0) {
655                throw new RSIllegalArgumentException("Height or width cannot be negative.");
656            }
657            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
658                throw new RSIllegalArgumentException("Updated region larger than allocation.");
659            }
660        }
661    }
662
663    /**
664     * Copy a rectangular region from the array into the allocation.
665     * The incoming array is assumed to be tightly packed.
666     *
667     * @param xoff X offset of the region to update
668     * @param yoff Y offset of the region to update
669     * @param w Width of the incoming region to update
670     * @param h Height of the incoming region to update
671     * @param data to be placed into the allocation
672     */
673    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
674        mRS.validate();
675        validate2DRange(xoff, yoff, w, h);
676        mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
677                              w, h, data, data.length);
678    }
679
680    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
681        mRS.validate();
682        validate2DRange(xoff, yoff, w, h);
683        mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
684                              w, h, data, data.length * 2);
685    }
686
687    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
688        mRS.validate();
689        validate2DRange(xoff, yoff, w, h);
690        mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
691                              w, h, data, data.length * 4);
692    }
693
694    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
695        mRS.validate();
696        validate2DRange(xoff, yoff, w, h);
697        mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
698                              w, h, data, data.length * 4);
699    }
700
701    /**
702     * Copy a rectangular region into the allocation from another
703     * allocation.
704     *
705     * @param xoff X offset of the region to update.
706     * @param yoff Y offset of the region to update.
707     * @param w Width of the incoming region to update.
708     * @param h Height of the incoming region to update.
709     * @param data source allocation.
710     * @param dataXoff X offset in data of the region to update.
711     * @param dataYoff Y offset in data of the region to update.
712     */
713    public void copy2DRangeFrom(int xoff, int yoff, int w, int h,
714                                Allocation data, int dataXoff, int dataYoff) {
715        mRS.validate();
716        validate2DRange(xoff, yoff, w, h);
717        mRS.nAllocationData2D(getID(), xoff, yoff,
718                              mSelectedLOD, mSelectedFace.mID,
719                              w, h, data.getID(), dataXoff, dataYoff,
720                              data.mSelectedLOD, data.mSelectedFace.mID);
721    }
722
723    /**
724     * Copy a bitmap into an allocation.  The height and width of
725     * the update will use the height and width of the incoming
726     * bitmap.
727     *
728     * @param xoff X offset of the region to update
729     * @param yoff Y offset of the region to update
730     * @param data the bitmap to be copied
731     */
732    public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
733        mRS.validate();
734        validateBitmapFormat(data);
735        validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
736        mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
737    }
738
739
740    public void copyTo(Bitmap b) {
741        mRS.validate();
742        validateBitmapFormat(b);
743        validateBitmapSize(b);
744        mRS.nAllocationCopyToBitmap(getID(), b);
745    }
746
747    public void copyTo(byte[] d) {
748        validateIsInt8();
749        mRS.validate();
750        mRS.nAllocationRead(getID(), d);
751    }
752
753    public void copyTo(short[] d) {
754        validateIsInt16();
755        mRS.validate();
756        mRS.nAllocationRead(getID(), d);
757    }
758
759    public void copyTo(int[] d) {
760        validateIsInt32();
761        mRS.validate();
762        mRS.nAllocationRead(getID(), d);
763    }
764
765    public void copyTo(float[] d) {
766        validateIsFloat32();
767        mRS.validate();
768        mRS.nAllocationRead(getID(), d);
769    }
770
771    /**
772     * Resize a 1D allocation.  The contents of the allocation are
773     * preserved.  If new elements are allocated objects are created
774     * with null contents and the new region is otherwise undefined.
775     *
776     * If the new region is smaller the references of any objects
777     * outside the new region will be released.
778     *
779     * A new type will be created with the new dimension.
780     *
781     * @param dimX The new size of the allocation.
782     */
783    public synchronized void resize(int dimX) {
784        if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
785            throw new RSInvalidStateException("Resize only support for 1D allocations at this time.");
786        }
787        mRS.nAllocationResize1D(getID(), dimX);
788        mRS.finish();  // Necessary because resize is fifoed and update is async.
789
790        int typeID = mRS.nAllocationGetType(getID());
791        mType = new Type(typeID, mRS);
792        mType.updateFromNative();
793        updateCacheInfo(mType);
794    }
795
796    /*
797    public void resize(int dimX, int dimY) {
798        if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
799            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
800        }
801        if (mType.getY() == 0) {
802            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
803        }
804        mRS.nAllocationResize2D(getID(), dimX, dimY);
805    }
806    */
807
808
809
810    // creation
811
812    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
813    static {
814        mBitmapOptions.inScaled = false;
815    }
816
817    /**
818     *
819     * @param type renderscript type describing data layout
820     * @param mips specifies desired mipmap behaviour for the
821     *             allocation
822     * @param usage bit field specifying how the allocation is
823     *              utilized
824     */
825    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
826        rs.validate();
827        if (type.getID() == 0) {
828            throw new RSInvalidStateException("Bad Type");
829        }
830        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage);
831        if (id == 0) {
832            throw new RSRuntimeException("Allocation creation failed.");
833        }
834        return new Allocation(id, rs, type, usage);
835    }
836
837    /**
838     * Creates a renderscript allocation with the size specified by
839     * the type and no mipmaps generated by default
840     *
841     * @param rs Context to which the allocation will belong.
842     * @param type renderscript type describing data layout
843     * @param usage bit field specifying how the allocation is
844     *              utilized
845     *
846     * @return allocation
847     */
848    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
849        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
850    }
851
852    /**
853     * Creates a renderscript allocation for use by the script with
854     * the size specified by the type and no mipmaps generated by
855     * default
856     *
857     * @param rs Context to which the allocation will belong.
858     * @param type renderscript type describing data layout
859     *
860     * @return allocation
861     */
862    static public Allocation createTyped(RenderScript rs, Type type) {
863        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
864    }
865
866    /**
867     * Creates a renderscript allocation with a specified number of
868     * given elements
869     *
870     * @param rs Context to which the allocation will belong.
871     * @param e describes what each element of an allocation is
872     * @param count specifies the number of element in the allocation
873     * @param usage bit field specifying how the allocation is
874     *              utilized
875     *
876     * @return allocation
877     */
878    static public Allocation createSized(RenderScript rs, Element e,
879                                         int count, int usage) {
880        rs.validate();
881        Type.Builder b = new Type.Builder(rs, e);
882        b.setX(count);
883        Type t = b.create();
884
885        int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage);
886        if (id == 0) {
887            throw new RSRuntimeException("Allocation creation failed.");
888        }
889        return new Allocation(id, rs, t, usage);
890    }
891
892    /**
893     * Creates a renderscript allocation with a specified number of
894     * given elements
895     *
896     * @param rs Context to which the allocation will belong.
897     * @param e describes what each element of an allocation is
898     * @param count specifies the number of element in the allocation
899     *
900     * @return allocation
901     */
902    static public Allocation createSized(RenderScript rs, Element e, int count) {
903        return createSized(rs, e, count, USAGE_SCRIPT);
904    }
905
906    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
907        final Bitmap.Config bc = b.getConfig();
908        if (bc == Bitmap.Config.ALPHA_8) {
909            return Element.A_8(rs);
910        }
911        if (bc == Bitmap.Config.ARGB_4444) {
912            return Element.RGBA_4444(rs);
913        }
914        if (bc == Bitmap.Config.ARGB_8888) {
915            return Element.RGBA_8888(rs);
916        }
917        if (bc == Bitmap.Config.RGB_565) {
918            return Element.RGB_565(rs);
919        }
920        throw new RSInvalidStateException("Bad bitmap type: " + bc);
921    }
922
923    static Type typeFromBitmap(RenderScript rs, Bitmap b,
924                                       MipmapControl mip) {
925        Element e = elementFromBitmap(rs, b);
926        Type.Builder tb = new Type.Builder(rs, e);
927        tb.setX(b.getWidth());
928        tb.setY(b.getHeight());
929        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
930        return tb.create();
931    }
932
933    /**
934     * Creates a renderscript allocation from a bitmap
935     *
936     * @param rs Context to which the allocation will belong.
937     * @param b bitmap source for the allocation data
938     * @param mips specifies desired mipmap behaviour for the
939     *             allocation
940     * @param usage bit field specifying how the allocation is
941     *              utilized
942     *
943     * @return renderscript allocation containing bitmap data
944     *
945     */
946    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
947                                              MipmapControl mips,
948                                              int usage) {
949        rs.validate();
950        Type t = typeFromBitmap(rs, b, mips);
951
952        int id = rs.nAllocationCreateFromBitmap(t.getID(), mips.mID, b, usage);
953        if (id == 0) {
954            throw new RSRuntimeException("Load failed.");
955        }
956        return new Allocation(id, rs, t, usage);
957    }
958
959    /**
960     * Creates a non-mipmapped renderscript allocation to use as a
961     * graphics texture
962     *
963     * @param rs Context to which the allocation will belong.
964     * @param b bitmap source for the allocation data
965     *
966     * @return renderscript allocation containing bitmap data
967     *
968     */
969    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
970        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
971                                USAGE_GRAPHICS_TEXTURE);
972    }
973
974    /**
975     * Creates a cubemap allocation from a bitmap containing the
976     * horizontal list of cube faces. Each individual face must be
977     * the same size and power of 2
978     *
979     * @param rs Context to which the allocation will belong.
980     * @param b bitmap with cubemap faces layed out in the following
981     *          format: right, left, top, bottom, front, back
982     * @param mips specifies desired mipmap behaviour for the cubemap
983     * @param usage bit field specifying how the cubemap is utilized
984     *
985     * @return allocation containing cubemap data
986     *
987     */
988    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
989                                                     MipmapControl mips,
990                                                     int usage) {
991        rs.validate();
992
993        int height = b.getHeight();
994        int width = b.getWidth();
995
996        if (width % 6 != 0) {
997            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
998        }
999        if (width / 6 != height) {
1000            throw new RSIllegalArgumentException("Only square cube map faces supported");
1001        }
1002        boolean isPow2 = (height & (height - 1)) == 0;
1003        if (!isPow2) {
1004            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
1005        }
1006
1007        Element e = elementFromBitmap(rs, b);
1008        Type.Builder tb = new Type.Builder(rs, e);
1009        tb.setX(height);
1010        tb.setY(height);
1011        tb.setFaces(true);
1012        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
1013        Type t = tb.create();
1014
1015        int id = rs.nAllocationCubeCreateFromBitmap(t.getID(), mips.mID, b, usage);
1016        if(id == 0) {
1017            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
1018        }
1019        return new Allocation(id, rs, t, usage);
1020    }
1021
1022    /**
1023     * Creates a non-mipmapped cubemap allocation for use as a
1024     * graphics texture from a bitmap containing the horizontal list
1025     * of cube faces. Each individual face must be the same size and
1026     * power of 2
1027     *
1028     * @param rs Context to which the allocation will belong.
1029     * @param b bitmap with cubemap faces layed out in the following
1030     *          format: right, left, top, bottom, front, back
1031     *
1032     * @return allocation containing cubemap data
1033     *
1034     */
1035    static public Allocation createCubemapFromBitmap(RenderScript rs,
1036                                                     Bitmap b) {
1037        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
1038                                       USAGE_GRAPHICS_TEXTURE);
1039    }
1040
1041    /**
1042     * Creates a cubemap allocation from 6 bitmaps containing
1043     * the cube faces. All the faces must be the same size and
1044     * power of 2
1045     *
1046     * @param rs Context to which the allocation will belong.
1047     * @param xpos cubemap face in the positive x direction
1048     * @param xneg cubemap face in the negative x direction
1049     * @param ypos cubemap face in the positive y direction
1050     * @param yneg cubemap face in the negative y direction
1051     * @param zpos cubemap face in the positive z direction
1052     * @param zneg cubemap face in the negative z direction
1053     * @param mips specifies desired mipmap behaviour for the cubemap
1054     * @param usage bit field specifying how the cubemap is utilized
1055     *
1056     * @return allocation containing cubemap data
1057     *
1058     */
1059    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
1060                                                        Bitmap xpos,
1061                                                        Bitmap xneg,
1062                                                        Bitmap ypos,
1063                                                        Bitmap yneg,
1064                                                        Bitmap zpos,
1065                                                        Bitmap zneg,
1066                                                        MipmapControl mips,
1067                                                        int usage) {
1068        int height = xpos.getHeight();
1069        if (xpos.getWidth() != height ||
1070            xneg.getWidth() != height || xneg.getHeight() != height ||
1071            ypos.getWidth() != height || ypos.getHeight() != height ||
1072            yneg.getWidth() != height || yneg.getHeight() != height ||
1073            zpos.getWidth() != height || zpos.getHeight() != height ||
1074            zneg.getWidth() != height || zneg.getHeight() != height) {
1075            throw new RSIllegalArgumentException("Only square cube map faces supported");
1076        }
1077        boolean isPow2 = (height & (height - 1)) == 0;
1078        if (!isPow2) {
1079            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
1080        }
1081
1082        Element e = elementFromBitmap(rs, xpos);
1083        Type.Builder tb = new Type.Builder(rs, e);
1084        tb.setX(height);
1085        tb.setY(height);
1086        tb.setFaces(true);
1087        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
1088        Type t = tb.create();
1089        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
1090
1091        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
1092        adapter.setFace(Type.CubemapFace.POSITIVE_X);
1093        adapter.copyFrom(xpos);
1094        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
1095        adapter.copyFrom(xneg);
1096        adapter.setFace(Type.CubemapFace.POSITIVE_Y);
1097        adapter.copyFrom(ypos);
1098        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
1099        adapter.copyFrom(yneg);
1100        adapter.setFace(Type.CubemapFace.POSITIVE_Z);
1101        adapter.copyFrom(zpos);
1102        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
1103        adapter.copyFrom(zneg);
1104
1105        return cubemap;
1106    }
1107
1108    /**
1109     * Creates a non-mipmapped cubemap allocation for use as a
1110     * graphics texture from 6 bitmaps containing
1111     * the cube faces. All the faces must be the same size and
1112     * power of 2
1113     *
1114     * @param rs Context to which the allocation will belong.
1115     * @param xpos cubemap face in the positive x direction
1116     * @param xneg cubemap face in the negative x direction
1117     * @param ypos cubemap face in the positive y direction
1118     * @param yneg cubemap face in the negative y direction
1119     * @param zpos cubemap face in the positive z direction
1120     * @param zneg cubemap face in the negative z direction
1121     *
1122     * @return allocation containing cubemap data
1123     *
1124     */
1125    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
1126                                                        Bitmap xpos,
1127                                                        Bitmap xneg,
1128                                                        Bitmap ypos,
1129                                                        Bitmap yneg,
1130                                                        Bitmap zpos,
1131                                                        Bitmap zneg) {
1132        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
1133                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
1134                                          USAGE_GRAPHICS_TEXTURE);
1135    }
1136
1137    /**
1138     * Creates a renderscript allocation from the bitmap referenced
1139     * by resource id
1140     *
1141     * @param rs Context to which the allocation will belong.
1142     * @param res application resources
1143     * @param id resource id to load the data from
1144     * @param mips specifies desired mipmap behaviour for the
1145     *             allocation
1146     * @param usage bit field specifying how the allocation is
1147     *              utilized
1148     *
1149     * @return renderscript allocation containing resource data
1150     *
1151     */
1152    static public Allocation createFromBitmapResource(RenderScript rs,
1153                                                      Resources res,
1154                                                      int id,
1155                                                      MipmapControl mips,
1156                                                      int usage) {
1157
1158        rs.validate();
1159        Bitmap b = BitmapFactory.decodeResource(res, id);
1160        Allocation alloc = createFromBitmap(rs, b, mips, usage);
1161        b.recycle();
1162        return alloc;
1163    }
1164
1165    /**
1166     * Creates a non-mipmapped renderscript allocation to use as a
1167     * graphics texture from the bitmap referenced by resource id
1168     *
1169     * @param rs Context to which the allocation will belong.
1170     * @param res application resources
1171     * @param id resource id to load the data from
1172     *
1173     * @return renderscript allocation containing resource data
1174     *
1175     */
1176    static public Allocation createFromBitmapResource(RenderScript rs,
1177                                                      Resources res,
1178                                                      int id) {
1179        return createFromBitmapResource(rs, res, id,
1180                                        MipmapControl.MIPMAP_NONE,
1181                                        USAGE_GRAPHICS_TEXTURE);
1182    }
1183
1184    /**
1185     * Creates a renderscript allocation containing string data
1186     * encoded in UTF-8 format
1187     *
1188     * @param rs Context to which the allocation will belong.
1189     * @param str string to create the allocation from
1190     * @param usage bit field specifying how the allocaiton is
1191     *              utilized
1192     *
1193     */
1194    static public Allocation createFromString(RenderScript rs,
1195                                              String str,
1196                                              int usage) {
1197        rs.validate();
1198        byte[] allocArray = null;
1199        try {
1200            allocArray = str.getBytes("UTF-8");
1201            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
1202            alloc.copyFrom(allocArray);
1203            return alloc;
1204        }
1205        catch (Exception e) {
1206            throw new RSRuntimeException("Could not convert string to utf-8.");
1207        }
1208    }
1209}
1210
1211
1212