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