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