1/*
2 * Copyright (C) 2008-2012 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.util.HashMap;
20import android.content.res.Resources;
21import android.graphics.Bitmap;
22import android.graphics.BitmapFactory;
23import android.view.Surface;
24import android.util.Log;
25import android.graphics.Canvas;
26import android.os.Trace;
27
28/**
29 * <p> This class provides the primary method through which data is passed to
30 * and from RenderScript kernels.  An Allocation provides the backing store for
31 * a given {@link android.renderscript.Type}.  </p>
32 *
33 * <p>An Allocation also contains a set of usage flags that denote how the
34 * Allocation could be used. For example, an Allocation may have usage flags
35 * specifying that it can be used from a script as well as input to a {@link
36 * android.renderscript.Sampler}. A developer must synchronize across these
37 * different usages using {@link android.renderscript.Allocation#syncAll} in
38 * order to ensure that different users of the Allocation have a consistent view
39 * of memory. For example, in the case where an Allocation is used as the output
40 * of one kernel and as Sampler input in a later kernel, a developer must call
41 * {@link #syncAll syncAll(Allocation.USAGE_SCRIPT)} prior to launching the
42 * second kernel to ensure correctness.
43 *
44 * <p>An Allocation can be populated with the {@link #copyFrom} routines. For
45 * more complex Element types, the {@link #copyFromUnchecked} methods can be
46 * used to copy from byte arrays or similar constructs.</p>
47 *
48 * <div class="special reference">
49 * <h3>Developer Guides</h3>
50 * <p>For more information about creating an application that uses RenderScript, read the
51 * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p>
52 * </div>
53 **/
54
55public class Allocation extends BaseObj {
56    Type mType;
57    Bitmap mBitmap;
58    int mUsage;
59    Allocation mAdaptedAllocation;
60    int mSize;
61
62    boolean mReadAllowed = true;
63    boolean mWriteAllowed = true;
64    boolean mAutoPadding = false;
65    int mSelectedX;
66    int mSelectedY;
67    int mSelectedZ;
68    int mSelectedLOD;
69    int mSelectedArray[];
70    Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
71
72    int mCurrentDimX;
73    int mCurrentDimY;
74    int mCurrentDimZ;
75    int mCurrentCount;
76    static HashMap<Long, Allocation> mAllocationMap =
77            new HashMap<Long, Allocation>();
78    OnBufferAvailableListener mBufferNotifier;
79
80    private Surface mGetSurfaceSurface = null;
81
82    private Element.DataType validateObjectIsPrimitiveArray(Object d, boolean checkType) {
83        final Class c = d.getClass();
84        if (!c.isArray()) {
85            throw new RSIllegalArgumentException("Object passed is not an array of primitives.");
86        }
87        final Class cmp = c.getComponentType();
88        if (!cmp.isPrimitive()) {
89            throw new RSIllegalArgumentException("Object passed is not an Array of primitives.");
90        }
91
92        if (cmp == Long.TYPE) {
93            if (checkType) {
94                validateIsInt64();
95                return mType.mElement.mType;
96            }
97            return Element.DataType.SIGNED_64;
98        }
99
100        if (cmp == Integer.TYPE) {
101            if (checkType) {
102                validateIsInt32();
103                return mType.mElement.mType;
104            }
105            return Element.DataType.SIGNED_32;
106        }
107
108        if (cmp == Short.TYPE) {
109            if (checkType) {
110                validateIsInt16();
111                return mType.mElement.mType;
112            }
113            return Element.DataType.SIGNED_16;
114        }
115
116        if (cmp == Byte.TYPE) {
117            if (checkType) {
118                validateIsInt8();
119                return mType.mElement.mType;
120            }
121            return Element.DataType.SIGNED_8;
122        }
123
124        if (cmp == Float.TYPE) {
125            if (checkType) {
126                validateIsFloat32();
127            }
128            return Element.DataType.FLOAT_32;
129        }
130
131        if (cmp == Double.TYPE) {
132            if (checkType) {
133                validateIsFloat64();
134            }
135            return Element.DataType.FLOAT_64;
136        }
137        return null;
138    }
139
140
141    /**
142     * The usage of the Allocation.  These signal to RenderScript where to place
143     * the Allocation in memory.
144     *
145     */
146
147    /**
148     * The Allocation will be bound to and accessed by scripts.
149     */
150    public static final int USAGE_SCRIPT = 0x0001;
151
152    /**
153     * The Allocation will be used as a texture source by one or more graphics
154     * programs.
155     *
156     */
157    public static final int USAGE_GRAPHICS_TEXTURE = 0x0002;
158
159    /**
160     * The Allocation will be used as a graphics mesh.
161     *
162     * This was deprecated in API level 16.
163     *
164     */
165    public static final int USAGE_GRAPHICS_VERTEX = 0x0004;
166
167
168    /**
169     * The Allocation will be used as the source of shader constants by one or
170     * more programs.
171     *
172     * This was deprecated in API level 16.
173     *
174     */
175    public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008;
176
177    /**
178     * The Allocation will be used as a target for offscreen rendering
179     *
180     * This was deprecated in API level 16.
181     *
182     */
183    public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010;
184
185    /**
186     * The Allocation will be used as a {@link android.view.Surface}
187     * consumer.  This usage will cause the Allocation to be created
188     * as read-only.
189     *
190     */
191    public static final int USAGE_IO_INPUT = 0x0020;
192
193    /**
194     * The Allocation will be used as a {@link android.view.Surface}
195     * producer.  The dimensions and format of the {@link
196     * android.view.Surface} will be forced to those of the
197     * Allocation.
198     *
199     */
200    public static final int USAGE_IO_OUTPUT = 0x0040;
201
202    /**
203     * The Allocation's backing store will be inherited from another object
204     * (usually a {@link android.graphics.Bitmap}); copying to or from the
205     * original source Bitmap will cause a synchronization rather than a full
206     * copy.  {@link #syncAll} may also be used to synchronize the Allocation
207     * and the source Bitmap.
208     *
209     * <p>This is set by default for allocations created with {@link
210     * #createFromBitmap} in API version 18 and higher.</p>
211     *
212     */
213    public static final int USAGE_SHARED = 0x0080;
214
215    /**
216     * Controls mipmap behavior when using the bitmap creation and update
217     * functions.
218     */
219    public enum MipmapControl {
220        /**
221         * No mipmaps will be generated and the type generated from the incoming
222         * bitmap will not contain additional LODs.
223         */
224        MIPMAP_NONE(0),
225
226        /**
227         * A full mipmap chain will be created in script memory.  The Type of
228         * the Allocation will contain a full mipmap chain.  On upload, the full
229         * chain will be transferred.
230         */
231        MIPMAP_FULL(1),
232
233        /**
234         * The Type of the Allocation will be the same as MIPMAP_NONE.  It will
235         * not contain mipmaps.  On upload, the allocation data will contain a
236         * full mipmap chain generated from the top level in script memory.
237         */
238        MIPMAP_ON_SYNC_TO_TEXTURE(2);
239
240        int mID;
241        MipmapControl(int id) {
242            mID = id;
243        }
244    }
245
246
247    private long getIDSafe() {
248        if (mAdaptedAllocation != null) {
249            return mAdaptedAllocation.getID(mRS);
250        }
251        return getID(mRS);
252    }
253
254
255   /**
256     * Get the {@link android.renderscript.Element} of the {@link
257     * android.renderscript.Type} of the Allocation.
258     *
259     * @return Element
260     *
261     */
262    public Element getElement() {
263        return mType.getElement();
264    }
265
266    /**
267     * Get the usage flags of the Allocation.
268     *
269     * @return usage this Allocation's set of the USAGE_* flags OR'd together
270     *
271     */
272    public int getUsage() {
273        return mUsage;
274    }
275
276    /**
277     * Enable/Disable AutoPadding for Vec3 elements.
278     * By default: Diabled.
279     *
280     * @param useAutoPadding True: enable AutoPadding; False: disable AutoPadding
281     *
282     */
283    public void setAutoPadding(boolean useAutoPadding) {
284        mAutoPadding = useAutoPadding;
285    }
286
287    /**
288     * Get the size of the Allocation in bytes.
289     *
290     * @return size of the Allocation in bytes.
291     *
292     */
293    public int getBytesSize() {
294        if (mType.mDimYuv != 0) {
295            return (int)Math.ceil(mType.getCount() * mType.getElement().getBytesSize() * 1.5);
296        }
297        return mType.getCount() * mType.getElement().getBytesSize();
298    }
299
300    private void updateCacheInfo(Type t) {
301        mCurrentDimX = t.getX();
302        mCurrentDimY = t.getY();
303        mCurrentDimZ = t.getZ();
304        mCurrentCount = mCurrentDimX;
305        if (mCurrentDimY > 1) {
306            mCurrentCount *= mCurrentDimY;
307        }
308        if (mCurrentDimZ > 1) {
309            mCurrentCount *= mCurrentDimZ;
310        }
311    }
312
313    private void setBitmap(Bitmap b) {
314        mBitmap = b;
315    }
316
317    Allocation(long id, RenderScript rs, Type t, int usage) {
318        super(id, rs);
319        if ((usage & ~(USAGE_SCRIPT |
320                       USAGE_GRAPHICS_TEXTURE |
321                       USAGE_GRAPHICS_VERTEX |
322                       USAGE_GRAPHICS_CONSTANTS |
323                       USAGE_GRAPHICS_RENDER_TARGET |
324                       USAGE_IO_INPUT |
325                       USAGE_IO_OUTPUT |
326                       USAGE_SHARED)) != 0) {
327            throw new RSIllegalArgumentException("Unknown usage specified.");
328        }
329
330        if ((usage & USAGE_IO_INPUT) != 0) {
331            mWriteAllowed = false;
332
333            if ((usage & ~(USAGE_IO_INPUT |
334                           USAGE_GRAPHICS_TEXTURE |
335                           USAGE_SCRIPT)) != 0) {
336                throw new RSIllegalArgumentException("Invalid usage combination.");
337            }
338        }
339
340        mType = t;
341        mUsage = usage;
342
343        if (t != null) {
344            // TODO: A3D doesn't have Type info during creation, so we can't
345            // calculate the size ahead of time. We can possibly add a method
346            // to update the size in the future if it seems reasonable.
347            mSize = mType.getCount() * mType.getElement().getBytesSize();
348            updateCacheInfo(t);
349        }
350        try {
351            RenderScript.registerNativeAllocation.invoke(RenderScript.sRuntime, mSize);
352        } catch (Exception e) {
353            Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
354            throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
355        }
356    }
357
358    protected void finalize() throws Throwable {
359        RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
360        super.finalize();
361    }
362
363    private void validateIsInt64() {
364        if ((mType.mElement.mType == Element.DataType.SIGNED_64) ||
365            (mType.mElement.mType == Element.DataType.UNSIGNED_64)) {
366            return;
367        }
368        throw new RSIllegalArgumentException(
369            "64 bit integer source does not match allocation type " + mType.mElement.mType);
370    }
371
372    private void validateIsInt32() {
373        if ((mType.mElement.mType == Element.DataType.SIGNED_32) ||
374            (mType.mElement.mType == Element.DataType.UNSIGNED_32)) {
375            return;
376        }
377        throw new RSIllegalArgumentException(
378            "32 bit integer source does not match allocation type " + mType.mElement.mType);
379    }
380
381    private void validateIsInt16() {
382        if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
383            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
384            return;
385        }
386        throw new RSIllegalArgumentException(
387            "16 bit integer source does not match allocation type " + mType.mElement.mType);
388    }
389
390    private void validateIsInt8() {
391        if ((mType.mElement.mType == Element.DataType.SIGNED_8) ||
392            (mType.mElement.mType == Element.DataType.UNSIGNED_8)) {
393            return;
394        }
395        throw new RSIllegalArgumentException(
396            "8 bit integer source does not match allocation type " + mType.mElement.mType);
397    }
398
399    private void validateIsFloat32() {
400        if (mType.mElement.mType == Element.DataType.FLOAT_32) {
401            return;
402        }
403        throw new RSIllegalArgumentException(
404            "32 bit float source does not match allocation type " + mType.mElement.mType);
405    }
406
407    private void validateIsFloat64() {
408        if (mType.mElement.mType == Element.DataType.FLOAT_64) {
409            return;
410        }
411        throw new RSIllegalArgumentException(
412            "64 bit float source does not match allocation type " + mType.mElement.mType);
413    }
414
415    private void validateIsObject() {
416        if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) ||
417            (mType.mElement.mType == Element.DataType.RS_TYPE) ||
418            (mType.mElement.mType == Element.DataType.RS_ALLOCATION) ||
419            (mType.mElement.mType == Element.DataType.RS_SAMPLER) ||
420            (mType.mElement.mType == Element.DataType.RS_SCRIPT) ||
421            (mType.mElement.mType == Element.DataType.RS_MESH) ||
422            (mType.mElement.mType == Element.DataType.RS_PROGRAM_FRAGMENT) ||
423            (mType.mElement.mType == Element.DataType.RS_PROGRAM_VERTEX) ||
424            (mType.mElement.mType == Element.DataType.RS_PROGRAM_RASTER) ||
425            (mType.mElement.mType == Element.DataType.RS_PROGRAM_STORE)) {
426            return;
427        }
428        throw new RSIllegalArgumentException(
429            "Object source does not match allocation type " + mType.mElement.mType);
430    }
431
432    @Override
433    void updateFromNative() {
434        super.updateFromNative();
435        long typeID = mRS.nAllocationGetType(getID(mRS));
436        if(typeID != 0) {
437            mType = new Type(typeID, mRS);
438            mType.updateFromNative();
439            updateCacheInfo(mType);
440        }
441    }
442
443    /**
444     * Get the {@link android.renderscript.Type} of the Allocation.
445     *
446     * @return Type
447     *
448     */
449    public Type getType() {
450        return mType;
451    }
452
453    /**
454     * Propagate changes from one usage of the Allocation to the
455     * other usages of the Allocation.
456     *
457     */
458    public void syncAll(int srcLocation) {
459        try {
460            Trace.traceBegin(RenderScript.TRACE_TAG, "syncAll");
461            switch (srcLocation) {
462                case USAGE_GRAPHICS_TEXTURE:
463                case USAGE_SCRIPT:
464                    if ((mUsage & USAGE_SHARED) != 0) {
465                        copyFrom(mBitmap);
466                    }
467                    break;
468                case USAGE_GRAPHICS_CONSTANTS:
469                case USAGE_GRAPHICS_VERTEX:
470                    break;
471                case USAGE_SHARED:
472                    if ((mUsage & USAGE_SHARED) != 0) {
473                        copyTo(mBitmap);
474                    }
475                    break;
476                default:
477                    throw new RSIllegalArgumentException("Source must be exactly one usage type.");
478            }
479            mRS.validate();
480            mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
481        } finally {
482            Trace.traceEnd(RenderScript.TRACE_TAG);
483        }
484    }
485
486    /**
487     * Send a buffer to the output stream.  The contents of the Allocation will
488     * be undefined after this operation. This operation is only valid if {@link
489     * #USAGE_IO_OUTPUT} is set on the Allocation.
490     *
491     *
492     */
493    public void ioSend() {
494        try {
495            Trace.traceBegin(RenderScript.TRACE_TAG, "ioSend");
496            if ((mUsage & USAGE_IO_OUTPUT) == 0) {
497                throw new RSIllegalArgumentException(
498                    "Can only send buffer if IO_OUTPUT usage specified.");
499            }
500            mRS.validate();
501            mRS.nAllocationIoSend(getID(mRS));
502        } finally {
503            Trace.traceEnd(RenderScript.TRACE_TAG);
504        }
505    }
506
507    /**
508     * Receive the latest input into the Allocation. This operation
509     * is only valid if {@link #USAGE_IO_INPUT} is set on the Allocation.
510     *
511     */
512    public void ioReceive() {
513        try {
514            Trace.traceBegin(RenderScript.TRACE_TAG, "ioReceive");
515            if ((mUsage & USAGE_IO_INPUT) == 0) {
516                throw new RSIllegalArgumentException(
517                    "Can only receive if IO_INPUT usage specified.");
518            }
519            mRS.validate();
520            mRS.nAllocationIoReceive(getID(mRS));
521        } finally {
522            Trace.traceEnd(RenderScript.TRACE_TAG);
523        }
524    }
525
526    /**
527     * Copy an array of RS objects to the Allocation.
528     *
529     * @param d Source array.
530     */
531    public void copyFrom(BaseObj[] d) {
532        try {
533            Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
534            mRS.validate();
535            validateIsObject();
536            if (d.length != mCurrentCount) {
537                throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
538                                                      mCurrentCount + ", array length = " + d.length);
539            }
540
541            if (RenderScript.sPointerSize == 8) {
542                long i[] = new long[d.length * 4];
543                for (int ct=0; ct < d.length; ct++) {
544                    i[ct * 4] = d[ct].getID(mRS);
545                }
546                copy1DRangeFromUnchecked(0, mCurrentCount, i);
547            } else {
548                int i[] = new int[d.length];
549                for (int ct=0; ct < d.length; ct++) {
550                    i[ct] = (int) d[ct].getID(mRS);
551                }
552                copy1DRangeFromUnchecked(0, mCurrentCount, i);
553            }
554        } finally {
555            Trace.traceEnd(RenderScript.TRACE_TAG);
556        }
557    }
558
559    private void validateBitmapFormat(Bitmap b) {
560        Bitmap.Config bc = b.getConfig();
561        if (bc == null) {
562            throw new RSIllegalArgumentException("Bitmap has an unsupported format for this operation");
563        }
564        switch (bc) {
565        case ALPHA_8:
566            if (mType.getElement().mKind != Element.DataKind.PIXEL_A) {
567                throw new RSIllegalArgumentException("Allocation kind is " +
568                                                     mType.getElement().mKind + ", type " +
569                                                     mType.getElement().mType +
570                                                     " of " + mType.getElement().getBytesSize() +
571                                                     " bytes, passed bitmap was " + bc);
572            }
573            break;
574        case ARGB_8888:
575            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
576                (mType.getElement().getBytesSize() != 4)) {
577                throw new RSIllegalArgumentException("Allocation kind is " +
578                                                     mType.getElement().mKind + ", type " +
579                                                     mType.getElement().mType +
580                                                     " of " + mType.getElement().getBytesSize() +
581                                                     " bytes, passed bitmap was " + bc);
582            }
583            break;
584        case RGB_565:
585            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) ||
586                (mType.getElement().getBytesSize() != 2)) {
587                throw new RSIllegalArgumentException("Allocation kind is " +
588                                                     mType.getElement().mKind + ", type " +
589                                                     mType.getElement().mType +
590                                                     " of " + mType.getElement().getBytesSize() +
591                                                     " bytes, passed bitmap was " + bc);
592            }
593            break;
594        case ARGB_4444:
595            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
596                (mType.getElement().getBytesSize() != 2)) {
597                throw new RSIllegalArgumentException("Allocation kind is " +
598                                                     mType.getElement().mKind + ", type " +
599                                                     mType.getElement().mType +
600                                                     " of " + mType.getElement().getBytesSize() +
601                                                     " bytes, passed bitmap was " + bc);
602            }
603            break;
604
605        }
606    }
607
608    private void validateBitmapSize(Bitmap b) {
609        if((mCurrentDimX != b.getWidth()) || (mCurrentDimY != b.getHeight())) {
610            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
611        }
612    }
613
614    private void copyFromUnchecked(Object array, Element.DataType dt, int arrayLen) {
615        try {
616            Trace.traceBegin(RenderScript.TRACE_TAG, "copyFromUnchecked");
617            mRS.validate();
618            if (mCurrentDimZ > 0) {
619                copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, array, dt, arrayLen);
620            } else if (mCurrentDimY > 0) {
621                copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, array, dt, arrayLen);
622            } else {
623                copy1DRangeFromUnchecked(0, mCurrentCount, array, dt, arrayLen);
624            }
625        } finally {
626            Trace.traceEnd(RenderScript.TRACE_TAG);
627        }
628    }
629
630    /**
631     * Copy into this Allocation from an array. This method does not guarantee
632     * that the Allocation is compatible with the input buffer; it copies memory
633     * without reinterpretation.
634     *
635     * @param array The source data array
636     */
637    public void copyFromUnchecked(Object array) {
638        try {
639            Trace.traceBegin(RenderScript.TRACE_TAG, "copyFromUnchecked");
640            copyFromUnchecked(array, validateObjectIsPrimitiveArray(array, false),
641                              java.lang.reflect.Array.getLength(array));
642        } finally {
643            Trace.traceEnd(RenderScript.TRACE_TAG);
644        }
645    }
646
647    /**
648     * Copy into this Allocation from an array. This method does not guarantee
649     * that the Allocation is compatible with the input buffer; it copies memory
650     * without reinterpretation.
651     *
652     * @param d the source data array
653     */
654    public void copyFromUnchecked(int[] d) {
655        copyFromUnchecked(d, Element.DataType.SIGNED_32, d.length);
656    }
657
658    /**
659     * Copy into this Allocation from an array. This method does not guarantee
660     * that the Allocation is compatible with the input buffer; it copies memory
661     * without reinterpretation.
662     *
663     * @param d the source data array
664     */
665    public void copyFromUnchecked(short[] d) {
666        copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
667    }
668
669    /**
670     * Copy into this Allocation from an array. This method does not guarantee
671     * that the Allocation is compatible with the input buffer; it copies memory
672     * without reinterpretation.
673     *
674     * @param d the source data array
675     */
676    public void copyFromUnchecked(byte[] d) {
677        copyFromUnchecked(d, Element.DataType.SIGNED_8, d.length);
678    }
679
680    /**
681     * Copy into this Allocation from an array. This method does not guarantee
682     * that the Allocation is compatible with the input buffer; it copies memory
683     * without reinterpretation.
684     *
685     * @param d the source data array
686     */
687    public void copyFromUnchecked(float[] d) {
688        copyFromUnchecked(d, Element.DataType.FLOAT_32, d.length);
689    }
690
691
692    /**
693     * Copy into this Allocation from an array.  This variant is type checked
694     * and will generate exceptions if the Allocation's {@link
695     * android.renderscript.Element} does not match the array's
696     * primitive type.
697     *
698     * @param array The source data array
699     */
700    public void copyFrom(Object array) {
701        try {
702            Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
703            copyFromUnchecked(array, validateObjectIsPrimitiveArray(array, true),
704                              java.lang.reflect.Array.getLength(array));
705        } finally {
706            Trace.traceEnd(RenderScript.TRACE_TAG);
707        }
708    }
709
710    /**
711     * Copy into this Allocation from an array.  This variant is type checked
712     * and will generate exceptions if the Allocation's {@link
713     * android.renderscript.Element} is not a 32 bit integer type.
714     *
715     * @param d the source data array
716     */
717    public void copyFrom(int[] d) {
718        validateIsInt32();
719        copyFromUnchecked(d, Element.DataType.SIGNED_32, d.length);
720    }
721
722    /**
723     * Copy into this Allocation from an array.  This variant is type checked
724     * and will generate exceptions if the Allocation's {@link
725     * android.renderscript.Element} is not a 16 bit integer type.
726     *
727     * @param d the source data array
728     */
729    public void copyFrom(short[] d) {
730        validateIsInt16();
731        copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
732    }
733
734    /**
735     * Copy into this Allocation from an array.  This variant is type checked
736     * and will generate exceptions if the Allocation's {@link
737     * android.renderscript.Element} is not an 8 bit integer type.
738     *
739     * @param d the source data array
740     */
741    public void copyFrom(byte[] d) {
742        validateIsInt8();
743        copyFromUnchecked(d, Element.DataType.SIGNED_8, d.length);
744    }
745
746    /**
747     * Copy into this Allocation from an array.  This variant is type checked
748     * and will generate exceptions if the Allocation's {@link
749     * android.renderscript.Element} is not a 32 bit float type.
750     *
751     * @param d the source data array
752     */
753    public void copyFrom(float[] d) {
754        validateIsFloat32();
755        copyFromUnchecked(d, Element.DataType.FLOAT_32, d.length);
756    }
757
758    /**
759     * Copy into an Allocation from a {@link android.graphics.Bitmap}.  The
760     * height, width, and format of the bitmap must match the existing
761     * allocation.
762     *
763     * <p>If the {@link android.graphics.Bitmap} is the same as the {@link
764     * android.graphics.Bitmap} used to create the Allocation with {@link
765     * #createFromBitmap} and {@link #USAGE_SHARED} is set on the Allocation,
766     * this will synchronize the Allocation with the latest data from the {@link
767     * android.graphics.Bitmap}, potentially avoiding the actual copy.</p>
768     *
769     * @param b the source bitmap
770     */
771    public void copyFrom(Bitmap b) {
772        try {
773            Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
774            mRS.validate();
775            if (b.getConfig() == null) {
776                Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
777                Canvas c = new Canvas(newBitmap);
778                c.drawBitmap(b, 0, 0, null);
779                copyFrom(newBitmap);
780                return;
781            }
782            validateBitmapSize(b);
783            validateBitmapFormat(b);
784            mRS.nAllocationCopyFromBitmap(getID(mRS), b);
785        } finally {
786            Trace.traceEnd(RenderScript.TRACE_TAG);
787        }
788    }
789
790    /**
791     * Copy an Allocation from an Allocation.  The types of both allocations
792     * must be identical.
793     *
794     * @param a the source allocation
795     */
796    public void copyFrom(Allocation a) {
797        try {
798            Trace.traceBegin(RenderScript.TRACE_TAG, "copyFrom");
799            mRS.validate();
800            if (!mType.equals(a.getType())) {
801                throw new RSIllegalArgumentException("Types of allocations must match.");
802            }
803            copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, a, 0, 0);
804        } finally {
805            Trace.traceEnd(RenderScript.TRACE_TAG);
806        }
807    }
808
809    /**
810     * This is only intended to be used by auto-generated code reflected from
811     * the RenderScript script files and should not be used by developers.
812     *
813     * @param xoff
814     * @param fp
815     */
816    public void setFromFieldPacker(int xoff, FieldPacker fp) {
817        mRS.validate();
818        int eSize = mType.mElement.getBytesSize();
819        final byte[] data = fp.getData();
820        int data_length = fp.getPos();
821
822        int count = data_length / eSize;
823        if ((eSize * count) != data_length) {
824            throw new RSIllegalArgumentException("Field packer length " + data_length +
825                                               " not divisible by element size " + eSize + ".");
826        }
827        copy1DRangeFromUnchecked(xoff, count, data);
828    }
829
830
831    /**
832     * This is only intended to be used by auto-generated code reflected from
833     * the RenderScript script files and should not be used by developers.
834     *
835     * @param xoff
836     * @param component_number
837     * @param fp
838     */
839    public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
840        setFromFieldPacker(xoff, 0, 0, component_number, fp);
841    }
842
843    /**
844     * This is only intended to be used by auto-generated code reflected from
845     * the RenderScript script files and should not be used by developers.
846     *
847     * @param xoff
848     * @param yoff
849     * @param zoff
850     * @param component_number
851     * @param fp
852     */
853    public void setFromFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
854        mRS.validate();
855        if (component_number >= mType.mElement.mElements.length) {
856            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
857        }
858        if(xoff < 0) {
859            throw new RSIllegalArgumentException("Offset x must be >= 0.");
860        }
861        if(yoff < 0) {
862            throw new RSIllegalArgumentException("Offset y must be >= 0.");
863        }
864        if(zoff < 0) {
865            throw new RSIllegalArgumentException("Offset z must be >= 0.");
866        }
867
868        final byte[] data = fp.getData();
869        int data_length = fp.getPos();
870        int eSize = mType.mElement.mElements[component_number].getBytesSize();
871        eSize *= mType.mElement.mArraySizes[component_number];
872
873        if (data_length != eSize) {
874            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
875                                               " does not match component size " + eSize + ".");
876        }
877
878        mRS.nAllocationElementData(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
879                                   component_number, data, data_length);
880    }
881
882    private void data1DChecks(int off, int count, int len, int dataSize, boolean usePadding) {
883        mRS.validate();
884        if(off < 0) {
885            throw new RSIllegalArgumentException("Offset must be >= 0.");
886        }
887        if(count < 1) {
888            throw new RSIllegalArgumentException("Count must be >= 1.");
889        }
890        if((off + count) > mCurrentCount) {
891            throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
892                                               ", got " + count + " at offset " + off + ".");
893        }
894        if(usePadding) {
895            if(len < dataSize / 4 * 3) {
896                throw new RSIllegalArgumentException("Array too small for allocation type.");
897            }
898        } else {
899            if(len < dataSize) {
900                throw new RSIllegalArgumentException("Array too small for allocation type.");
901            }
902        }
903    }
904
905    /**
906     * Generate a mipmap chain. This is only valid if the Type of the Allocation
907     * includes mipmaps.
908     *
909     * <p>This function will generate a complete set of mipmaps from the top
910     * level LOD and place them into the script memory space.</p>
911     *
912     * <p>If the Allocation is also using other memory spaces, a call to {@link
913     * #syncAll syncAll(Allocation.USAGE_SCRIPT)} is required.</p>
914     */
915    public void generateMipmaps() {
916        mRS.nAllocationGenerateMipmaps(getID(mRS));
917    }
918
919    private void copy1DRangeFromUnchecked(int off, int count, Object array,
920                                          Element.DataType dt, int arrayLen) {
921        try {
922            Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
923            final int dataSize = mType.mElement.getBytesSize() * count;
924            // AutoPadding for Vec3 Element
925            boolean usePadding = false;
926            if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
927                usePadding = true;
928            }
929            data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
930            mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
931                                  mType.mElement.mType.mSize, usePadding);
932        } finally {
933            Trace.traceEnd(RenderScript.TRACE_TAG);
934        }
935    }
936
937    /**
938     * Copy an array into part of this Allocation.  This method does not
939     * guarantee that the Allocation is compatible with the input buffer.
940     *
941     * @param off The offset of the first element to be copied.
942     * @param count The number of elements to be copied.
943     * @param array The source data array
944     */
945    public void copy1DRangeFromUnchecked(int off, int count, Object array) {
946        copy1DRangeFromUnchecked(off, count, array,
947                                 validateObjectIsPrimitiveArray(array, false),
948                                 java.lang.reflect.Array.getLength(array));
949    }
950
951    /**
952     * Copy an array into part of this Allocation.  This method does not
953     * guarantee that the Allocation is compatible with the input buffer.
954     *
955     * @param off The offset of the first element to be copied.
956     * @param count The number of elements to be copied.
957     * @param d the source data array
958     */
959    public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
960        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
961    }
962
963    /**
964     * Copy an array into part of this Allocation.  This method does not
965     * guarantee that the Allocation is compatible with the input buffer.
966     *
967     * @param off The offset of the first element to be copied.
968     * @param count The number of elements to be copied.
969     * @param d the source data array
970     */
971    public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
972        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
973    }
974
975    /**
976     * Copy an array into part of this Allocation.  This method does not
977     * guarantee that the Allocation is compatible with the input buffer.
978     *
979     * @param off The offset of the first element to be copied.
980     * @param count The number of elements to be copied.
981     * @param d the source data array
982     */
983    public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
984        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
985    }
986
987    /**
988     * Copy an array into part of this Allocation.  This method does not
989     * guarantee that the Allocation is compatible with the input buffer.
990     *
991     * @param off The offset of the first element to be copied.
992     * @param count The number of elements to be copied.
993     * @param d the source data array
994     */
995    public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
996        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
997    }
998
999
1000    /**
1001     * Copy an array into part of this Allocation.  This variant is type checked
1002     * and will generate exceptions if the Allocation type does not
1003     * match the component type of the array passed in.
1004     *
1005     * @param off The offset of the first element to be copied.
1006     * @param count The number of elements to be copied.
1007     * @param array The source data array.
1008     */
1009    public void copy1DRangeFrom(int off, int count, Object array) {
1010        copy1DRangeFromUnchecked(off, count, array,
1011                                 validateObjectIsPrimitiveArray(array, true),
1012                                 java.lang.reflect.Array.getLength(array));
1013    }
1014
1015    /**
1016     * Copy an array into part of this Allocation.  This variant is type checked
1017     * and will generate exceptions if the Allocation type is not a 32 bit
1018     * integer type.
1019     *
1020     * @param off The offset of the first element to be copied.
1021     * @param count The number of elements to be copied.
1022     * @param d the source data array
1023     */
1024    public void copy1DRangeFrom(int off, int count, int[] d) {
1025        validateIsInt32();
1026        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
1027    }
1028
1029    /**
1030     * Copy an array into part of this Allocation.  This variant is type checked
1031     * and will generate exceptions if the Allocation type is not a 16 bit
1032     * integer type.
1033     *
1034     * @param off The offset of the first element to be copied.
1035     * @param count The number of elements to be copied.
1036     * @param d the source data array
1037     */
1038    public void copy1DRangeFrom(int off, int count, short[] d) {
1039        validateIsInt16();
1040        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
1041    }
1042
1043    /**
1044     * Copy an array into part of this Allocation.  This variant is type checked
1045     * and will generate exceptions if the Allocation type is not an 8 bit
1046     * integer type.
1047     *
1048     * @param off The offset of the first element to be copied.
1049     * @param count The number of elements to be copied.
1050     * @param d the source data array
1051     */
1052    public void copy1DRangeFrom(int off, int count, byte[] d) {
1053        validateIsInt8();
1054        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
1055    }
1056
1057    /**
1058     * Copy an array into part of this Allocation.  This variant is type checked
1059     * and will generate exceptions if the Allocation type is not a 32 bit float
1060     * type.
1061     *
1062     * @param off The offset of the first element to be copied.
1063     * @param count The number of elements to be copied.
1064     * @param d the source data array.
1065     */
1066    public void copy1DRangeFrom(int off, int count, float[] d) {
1067        validateIsFloat32();
1068        copy1DRangeFromUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
1069    }
1070
1071     /**
1072     * Copy part of an Allocation into this Allocation.
1073     *
1074     * @param off The offset of the first element to be copied.
1075     * @param count The number of elements to be copied.
1076     * @param data the source data allocation.
1077     * @param dataOff off The offset of the first element in data to
1078     *          be copied.
1079     */
1080    public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
1081        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFrom");
1082        mRS.nAllocationData2D(getIDSafe(), off, 0,
1083                              mSelectedLOD, mSelectedFace.mID,
1084                              count, 1, data.getID(mRS), dataOff, 0,
1085                              data.mSelectedLOD, data.mSelectedFace.mID);
1086        Trace.traceEnd(RenderScript.TRACE_TAG);
1087    }
1088
1089    private void validate2DRange(int xoff, int yoff, int w, int h) {
1090        if (mAdaptedAllocation != null) {
1091
1092        } else {
1093
1094            if (xoff < 0 || yoff < 0) {
1095                throw new RSIllegalArgumentException("Offset cannot be negative.");
1096            }
1097            if (h < 0 || w < 0) {
1098                throw new RSIllegalArgumentException("Height or width cannot be negative.");
1099            }
1100            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
1101                throw new RSIllegalArgumentException("Updated region larger than allocation.");
1102            }
1103        }
1104    }
1105
1106    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, Object array,
1107                                  Element.DataType dt, int arrayLen) {
1108        try {
1109            Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFromUnchecked");
1110            mRS.validate();
1111            validate2DRange(xoff, yoff, w, h);
1112            final int dataSize = mType.mElement.getBytesSize() * w * h;
1113            // AutoPadding for Vec3 Element
1114            boolean usePadding = false;
1115            int sizeBytes = arrayLen * dt.mSize;
1116            if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1117                if (dataSize / 4 * 3 > sizeBytes) {
1118                    throw new RSIllegalArgumentException("Array too small for allocation type.");
1119                }
1120                usePadding = true;
1121                sizeBytes = dataSize;
1122            } else {
1123                if (dataSize > sizeBytes) {
1124                    throw new RSIllegalArgumentException("Array too small for allocation type.");
1125                }
1126            }
1127            mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
1128                                  array, sizeBytes, dt,
1129                                  mType.mElement.mType.mSize, usePadding);
1130        } finally {
1131            Trace.traceEnd(RenderScript.TRACE_TAG);
1132        }
1133    }
1134
1135    /**
1136     * Copy from an array into a rectangular region in this Allocation.  The
1137     * array is assumed to be tightly packed.
1138     *
1139     * @param xoff X offset of the region to update in this Allocation
1140     * @param yoff Y offset of the region to update in this Allocation
1141     * @param w Width of the region to update
1142     * @param h Height of the region to update
1143     * @param array Data to be placed into the Allocation
1144     */
1145    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, Object array) {
1146        try {
1147            Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFrom");
1148            copy2DRangeFromUnchecked(xoff, yoff, w, h, array,
1149                                     validateObjectIsPrimitiveArray(array, true),
1150                                     java.lang.reflect.Array.getLength(array));
1151        } finally {
1152            Trace.traceEnd(RenderScript.TRACE_TAG);
1153        }
1154    }
1155
1156    /**
1157     * Copy from an array into a rectangular region in this Allocation.  The
1158     * array is assumed to be tightly packed.
1159     *
1160     * @param xoff X offset of the region to update in this Allocation
1161     * @param yoff Y offset of the region to update in this Allocation
1162     * @param w Width of the region to update
1163     * @param h Height of the region to update
1164     * @param data to be placed into the Allocation
1165     */
1166    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
1167        validateIsInt8();
1168        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
1169                                 Element.DataType.SIGNED_8, data.length);
1170    }
1171
1172    /**
1173     * Copy from an array into a rectangular region in this Allocation.  The
1174     * array is assumed to be tightly packed.
1175     *
1176     * @param xoff X offset of the region to update in this Allocation
1177     * @param yoff Y offset of the region to update in this Allocation
1178     * @param w Width of the region to update
1179     * @param h Height of the region to update
1180     * @param data to be placed into the Allocation
1181     */
1182    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
1183        validateIsInt16();
1184        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
1185                                 Element.DataType.SIGNED_16, data.length);
1186    }
1187
1188    /**
1189     * Copy from an array into a rectangular region in this Allocation.  The
1190     * array is assumed to be tightly packed.
1191     *
1192     * @param xoff X offset of the region to update in this Allocation
1193     * @param yoff Y offset of the region to update in this Allocation
1194     * @param w Width of the region to update
1195     * @param h Height of the region to update
1196     * @param data to be placed into the Allocation
1197     */
1198    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
1199        validateIsInt32();
1200        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
1201                                 Element.DataType.SIGNED_32, data.length);
1202    }
1203
1204    /**
1205     * Copy from an array into a rectangular region in this Allocation.  The
1206     * array is assumed to be tightly packed.
1207     *
1208     * @param xoff X offset of the region to update in this Allocation
1209     * @param yoff Y offset of the region to update in this Allocation
1210     * @param w Width of the region to update
1211     * @param h Height of the region to update
1212     * @param data to be placed into the Allocation
1213     */
1214    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
1215        validateIsFloat32();
1216        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
1217                                 Element.DataType.FLOAT_32, data.length);
1218    }
1219
1220    /**
1221     * Copy a rectangular region from an Allocation into a rectangular region in
1222     * this Allocation.
1223     *
1224     * @param xoff X offset of the region in this Allocation
1225     * @param yoff Y offset of the region in this Allocation
1226     * @param w Width of the region to update.
1227     * @param h Height of the region to update.
1228     * @param data source Allocation.
1229     * @param dataXoff X offset in source Allocation
1230     * @param dataYoff Y offset in source Allocation
1231     */
1232    public void copy2DRangeFrom(int xoff, int yoff, int w, int h,
1233                                Allocation data, int dataXoff, int dataYoff) {
1234        try {
1235            Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFrom");
1236            mRS.validate();
1237            validate2DRange(xoff, yoff, w, h);
1238            mRS.nAllocationData2D(getIDSafe(), xoff, yoff,
1239                                  mSelectedLOD, mSelectedFace.mID,
1240                                  w, h, data.getID(mRS), dataXoff, dataYoff,
1241                                  data.mSelectedLOD, data.mSelectedFace.mID);
1242        } finally {
1243            Trace.traceEnd(RenderScript.TRACE_TAG);
1244        }
1245    }
1246
1247    /**
1248     * Copy a {@link android.graphics.Bitmap} into an Allocation.  The height
1249     * and width of the update will use the height and width of the {@link
1250     * android.graphics.Bitmap}.
1251     *
1252     * @param xoff X offset of the region to update in this Allocation
1253     * @param yoff Y offset of the region to update in this Allocation
1254     * @param data the Bitmap to be copied
1255     */
1256    public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
1257        try {
1258            Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFrom");
1259            mRS.validate();
1260            if (data.getConfig() == null) {
1261                Bitmap newBitmap = Bitmap.createBitmap(data.getWidth(), data.getHeight(), Bitmap.Config.ARGB_8888);
1262                Canvas c = new Canvas(newBitmap);
1263                c.drawBitmap(data, 0, 0, null);
1264                copy2DRangeFrom(xoff, yoff, newBitmap);
1265                return;
1266            }
1267            validateBitmapFormat(data);
1268            validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
1269            mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
1270        } finally {
1271            Trace.traceEnd(RenderScript.TRACE_TAG);
1272        }
1273    }
1274
1275    private void validate3DRange(int xoff, int yoff, int zoff, int w, int h, int d) {
1276        if (mAdaptedAllocation != null) {
1277
1278        } else {
1279
1280            if (xoff < 0 || yoff < 0 || zoff < 0) {
1281                throw new RSIllegalArgumentException("Offset cannot be negative.");
1282            }
1283            if (h < 0 || w < 0 || d < 0) {
1284                throw new RSIllegalArgumentException("Height or width cannot be negative.");
1285            }
1286            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) {
1287                throw new RSIllegalArgumentException("Updated region larger than allocation.");
1288            }
1289        }
1290    }
1291
1292    /**
1293     * Copy a rectangular region from the array into the allocation.
1294     * The array is assumed to be tightly packed.
1295     *
1296     * The data type of the array is not required to be the same as
1297     * the element data type.
1298     */
1299    private void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
1300                                          Object array, Element.DataType dt, int arrayLen) {
1301        try {
1302            Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeFromUnchecked");
1303            mRS.validate();
1304            validate3DRange(xoff, yoff, zoff, w, h, d);
1305            final int dataSize = mType.mElement.getBytesSize() * w * h * d;
1306            // AutoPadding for Vec3 Element
1307            boolean usePadding = false;
1308            int sizeBytes = arrayLen * dt.mSize;
1309            if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1310                if (dataSize / 4 * 3 > sizeBytes) {
1311                    throw new RSIllegalArgumentException("Array too small for allocation type.");
1312                }
1313                usePadding = true;
1314                sizeBytes = dataSize;
1315            } else {
1316                if (dataSize > sizeBytes) {
1317                    throw new RSIllegalArgumentException("Array too small for allocation type.");
1318                }
1319            }
1320            mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
1321                                  array, sizeBytes, dt,
1322                                  mType.mElement.mType.mSize, usePadding);
1323        } finally {
1324            Trace.traceEnd(RenderScript.TRACE_TAG);
1325        }
1326    }
1327
1328    /**
1329     * Copy a rectangular region from the array into the allocation.
1330     * The array is assumed to be tightly packed.
1331     *
1332     * @param xoff X offset of the region to update in this Allocation
1333     * @param yoff Y offset of the region to update in this Allocation
1334     * @param zoff Z offset of the region to update in this Allocation
1335     * @param w Width of the region to update
1336     * @param h Height of the region to update
1337     * @param d Depth of the region to update
1338     * @param array to be placed into the allocation
1339     */
1340    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
1341        try {
1342            Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeFrom");
1343            copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, array,
1344                                     validateObjectIsPrimitiveArray(array, true),
1345                                     java.lang.reflect.Array.getLength(array));
1346        } finally {
1347            Trace.traceEnd(RenderScript.TRACE_TAG);
1348        }
1349    }
1350
1351    /**
1352     * Copy a rectangular region into the allocation from another
1353     * allocation.
1354     *
1355     * @param xoff X offset of the region to update in this Allocation
1356     * @param yoff Y offset of the region to update in this Allocation
1357     * @param zoff Z offset of the region to update in this Allocation
1358     * @param w Width of the region to update.
1359     * @param h Height of the region to update.
1360     * @param d Depth of the region to update.
1361     * @param data source allocation.
1362     * @param dataXoff X offset of the region in the source Allocation
1363     * @param dataYoff Y offset of the region in the source Allocation
1364     * @param dataZoff Z offset of the region in the source Allocation
1365     */
1366    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d,
1367                                Allocation data, int dataXoff, int dataYoff, int dataZoff) {
1368        mRS.validate();
1369        validate3DRange(xoff, yoff, zoff, w, h, d);
1370        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
1371                              w, h, d, data.getID(mRS), dataXoff, dataYoff, dataZoff,
1372                              data.mSelectedLOD);
1373    }
1374
1375
1376    /**
1377     * Copy from the Allocation into a {@link android.graphics.Bitmap}.  The
1378     * bitmap must match the dimensions of the Allocation.
1379     *
1380     * @param b The bitmap to be set from the Allocation.
1381     */
1382    public void copyTo(Bitmap b) {
1383        try {
1384            Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
1385            mRS.validate();
1386            validateBitmapFormat(b);
1387            validateBitmapSize(b);
1388            mRS.nAllocationCopyToBitmap(getID(mRS), b);
1389        } finally {
1390            Trace.traceEnd(RenderScript.TRACE_TAG);
1391        }
1392    }
1393
1394    private void copyTo(Object array, Element.DataType dt, int arrayLen) {
1395        try {
1396            Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
1397            mRS.validate();
1398            boolean usePadding = false;
1399            if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1400                usePadding = true;
1401            }
1402            if (usePadding) {
1403                if (dt.mSize * arrayLen < mSize / 4 * 3) {
1404                    throw new RSIllegalArgumentException(
1405                        "Size of output array cannot be smaller than size of allocation.");
1406                }
1407            } else {
1408                if (dt.mSize * arrayLen < mSize) {
1409                    throw new RSIllegalArgumentException(
1410                        "Size of output array cannot be smaller than size of allocation.");
1411                }
1412            }
1413            mRS.nAllocationRead(getID(mRS), array, dt, mType.mElement.mType.mSize, usePadding);
1414        } finally {
1415            Trace.traceEnd(RenderScript.TRACE_TAG);
1416        }
1417    }
1418
1419    /**
1420     * Copy from the Allocation into an array.  The array must be at
1421     * least as large as the Allocation.  The
1422     * {@link android.renderscript.Element} must match the component
1423     * type of the array passed in.
1424     *
1425     * @param array The array to be set from the Allocation.
1426     */
1427    public void copyTo(Object array) {
1428        copyTo(array, validateObjectIsPrimitiveArray(array, true),
1429               java.lang.reflect.Array.getLength(array));
1430    }
1431
1432    /**
1433     * Copy from the Allocation into a byte array.  The array must be at least
1434     * as large as the Allocation.  The allocation must be of an 8 bit integer
1435     * {@link android.renderscript.Element} type.
1436     *
1437     * @param d The array to be set from the Allocation.
1438     */
1439    public void copyTo(byte[] d) {
1440        validateIsInt8();
1441        copyTo(d, Element.DataType.SIGNED_8, d.length);
1442    }
1443
1444    /**
1445     * Copy from the Allocation into a short array.  The array must be at least
1446     * as large as the Allocation.  The allocation must be of an 16 bit integer
1447     * {@link android.renderscript.Element} type.
1448     *
1449     * @param d The array to be set from the Allocation.
1450     */
1451    public void copyTo(short[] d) {
1452        validateIsInt16();
1453        copyTo(d, Element.DataType.SIGNED_16, d.length);
1454    }
1455
1456    /**
1457     * Copy from the Allocation into a int array.  The array must be at least as
1458     * large as the Allocation.  The allocation must be of an 32 bit integer
1459     * {@link android.renderscript.Element} type.
1460     *
1461     * @param d The array to be set from the Allocation.
1462     */
1463    public void copyTo(int[] d) {
1464        validateIsInt32();
1465        copyTo(d, Element.DataType.SIGNED_32, d.length);
1466    }
1467
1468    /**
1469     * Copy from the Allocation into a float array.  The array must be at least
1470     * as large as the Allocation.  The allocation must be of an 32 bit float
1471     * {@link android.renderscript.Element} type.
1472     *
1473     * @param d The array to be set from the Allocation.
1474     */
1475    public void copyTo(float[] d) {
1476        validateIsFloat32();
1477        copyTo(d, Element.DataType.FLOAT_32, d.length);
1478    }
1479
1480    /**
1481     * @hide
1482     *
1483     * This is only intended to be used by auto-generated code reflected from
1484     * the RenderScript script files and should not be used by developers.
1485     *
1486     * @param xoff
1487     * @param yoff
1488     * @param zoff
1489     * @param component_number
1490     * @param fp
1491     */
1492    public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
1493        mRS.validate();
1494        if (component_number >= mType.mElement.mElements.length) {
1495            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
1496        }
1497        if(xoff < 0) {
1498            throw new RSIllegalArgumentException("Offset x must be >= 0.");
1499        }
1500        if(yoff < 0) {
1501            throw new RSIllegalArgumentException("Offset y must be >= 0.");
1502        }
1503        if(zoff < 0) {
1504            throw new RSIllegalArgumentException("Offset z must be >= 0.");
1505        }
1506
1507        final byte[] data = fp.getData();
1508        int data_length = fp.getPos();
1509        int eSize = mType.mElement.mElements[component_number].getBytesSize();
1510        eSize *= mType.mElement.mArraySizes[component_number];
1511
1512        if (data_length != eSize) {
1513            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
1514                                               " does not match component size " + eSize + ".");
1515        }
1516
1517        mRS.nAllocationElementRead(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
1518                                   component_number, data, data_length);
1519    }
1520    /**
1521     * Resize a 1D allocation.  The contents of the allocation are preserved.
1522     * If new elements are allocated objects are created with null contents and
1523     * the new region is otherwise undefined.
1524     *
1525     * <p>If the new region is smaller the references of any objects outside the
1526     * new region will be released.</p>
1527     *
1528     * <p>A new type will be created with the new dimension.</p>
1529     *
1530     * @param dimX The new size of the allocation.
1531     *
1532     * @deprecated RenderScript objects should be immutable once created.  The
1533     * replacement is to create a new allocation and copy the contents. This
1534     * function will throw an exception if API 21 or higher is used.
1535     */
1536    public synchronized void resize(int dimX) {
1537        if (mRS.getApplicationContext().getApplicationInfo().targetSdkVersion >= 21) {
1538            throw new RSRuntimeException("Resize is not allowed in API 21+.");
1539        }
1540        if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
1541            throw new RSInvalidStateException("Resize only support for 1D allocations at this time.");
1542        }
1543        mRS.nAllocationResize1D(getID(mRS), dimX);
1544        mRS.finish();  // Necessary because resize is fifoed and update is async.
1545
1546        long typeID = mRS.nAllocationGetType(getID(mRS));
1547        mType = new Type(typeID, mRS);
1548        mType.updateFromNative();
1549        updateCacheInfo(mType);
1550    }
1551
1552    private void copy1DRangeToUnchecked(int off, int count, Object array,
1553                                        Element.DataType dt, int arrayLen) {
1554        try {
1555            Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeToUnchecked");
1556            final int dataSize = mType.mElement.getBytesSize() * count;
1557            // AutoPadding for Vec3 Element
1558            boolean usePadding = false;
1559            if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1560                usePadding = true;
1561            }
1562            data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
1563            mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
1564                                  mType.mElement.mType.mSize, usePadding);
1565        } finally {
1566            Trace.traceEnd(RenderScript.TRACE_TAG);
1567        }
1568    }
1569
1570    /**
1571     * Copy part of this Allocation into an array.  This method does not
1572     * guarantee that the Allocation is compatible with the input buffer.
1573     *
1574     * @param off The offset of the first element to be copied.
1575     * @param count The number of elements to be copied.
1576     * @param array The dest data array
1577     */
1578    public void copy1DRangeToUnchecked(int off, int count, Object array) {
1579        copy1DRangeToUnchecked(off, count, array,
1580                               validateObjectIsPrimitiveArray(array, false),
1581                               java.lang.reflect.Array.getLength(array));
1582    }
1583
1584    /**
1585     * Copy part of this Allocation into an array.  This method does not
1586     * guarantee that the Allocation is compatible with the input buffer.
1587     *
1588     * @param off The offset of the first element to be copied.
1589     * @param count The number of elements to be copied.
1590     * @param d the source data array
1591     */
1592    public void copy1DRangeToUnchecked(int off, int count, int[] d) {
1593        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
1594    }
1595
1596    /**
1597     * Copy part of this Allocation into an array.  This method does not
1598     * guarantee that the Allocation is compatible with the input buffer.
1599     *
1600     * @param off The offset of the first element to be copied.
1601     * @param count The number of elements to be copied.
1602     * @param d the source data array
1603     */
1604    public void copy1DRangeToUnchecked(int off, int count, short[] d) {
1605        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
1606    }
1607
1608    /**
1609     * Copy part of this Allocation into an array.  This method does not
1610     * guarantee that the Allocation is compatible with the input buffer.
1611     *
1612     * @param off The offset of the first element to be copied.
1613     * @param count The number of elements to be copied.
1614     * @param d the source data array
1615     */
1616    public void copy1DRangeToUnchecked(int off, int count, byte[] d) {
1617        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
1618    }
1619
1620    /**
1621     * Copy part of this Allocation into an array.  This method does not
1622     * guarantee that the Allocation is compatible with the input buffer.
1623     *
1624     * @param off The offset of the first element to be copied.
1625     * @param count The number of elements to be copied.
1626     * @param d the source data array
1627     */
1628    public void copy1DRangeToUnchecked(int off, int count, float[] d) {
1629        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
1630    }
1631
1632
1633    /**
1634     * Copy part of this Allocation into an array.  This method does not
1635     * and will generate exceptions if the Allocation type does not
1636     * match the component type of the array passed in.
1637     *
1638     * @param off The offset of the first element to be copied.
1639     * @param count The number of elements to be copied.
1640     * @param array The source data array.
1641     */
1642    public void copy1DRangeTo(int off, int count, Object array) {
1643        copy1DRangeToUnchecked(off, count, array,
1644                               validateObjectIsPrimitiveArray(array, true),
1645                               java.lang.reflect.Array.getLength(array));
1646    }
1647
1648    /**
1649     * Copy part of this Allocation into an array.  This method does not
1650     * and will generate exceptions if the Allocation type is not a 32 bit
1651     * integer type.
1652     *
1653     * @param off The offset of the first element to be copied.
1654     * @param count The number of elements to be copied.
1655     * @param d the source data array
1656     */
1657    public void copy1DRangeTo(int off, int count, int[] d) {
1658        validateIsInt32();
1659        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
1660    }
1661
1662    /**
1663     * Copy part of this Allocation into an array.  This method does not
1664     * and will generate exceptions if the Allocation type is not a 16 bit
1665     * integer type.
1666     *
1667     * @param off The offset of the first element to be copied.
1668     * @param count The number of elements to be copied.
1669     * @param d the source data array
1670     */
1671    public void copy1DRangeTo(int off, int count, short[] d) {
1672        validateIsInt16();
1673        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
1674    }
1675
1676    /**
1677     * Copy part of this Allocation into an array.  This method does not
1678     * and will generate exceptions if the Allocation type is not an 8 bit
1679     * integer type.
1680     *
1681     * @param off The offset of the first element to be copied.
1682     * @param count The number of elements to be copied.
1683     * @param d the source data array
1684     */
1685    public void copy1DRangeTo(int off, int count, byte[] d) {
1686        validateIsInt8();
1687        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
1688    }
1689
1690    /**
1691     * Copy part of this Allocation into an array.  This method does not
1692     * and will generate exceptions if the Allocation type is not a 32 bit float
1693     * type.
1694     *
1695     * @param off The offset of the first element to be copied.
1696     * @param count The number of elements to be copied.
1697     * @param d the source data array.
1698     */
1699    public void copy1DRangeTo(int off, int count, float[] d) {
1700        validateIsFloat32();
1701        copy1DRangeToUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
1702    }
1703
1704
1705    void copy2DRangeToUnchecked(int xoff, int yoff, int w, int h, Object array,
1706                                Element.DataType dt, int arrayLen) {
1707        try {
1708            Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeToUnchecked");
1709            mRS.validate();
1710            validate2DRange(xoff, yoff, w, h);
1711            final int dataSize = mType.mElement.getBytesSize() * w * h;
1712            // AutoPadding for Vec3 Element
1713            boolean usePadding = false;
1714            int sizeBytes = arrayLen * dt.mSize;
1715            if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1716                if (dataSize / 4 * 3 > sizeBytes) {
1717                    throw new RSIllegalArgumentException("Array too small for allocation type.");
1718                }
1719                usePadding = true;
1720                sizeBytes = dataSize;
1721            } else {
1722                if (dataSize > sizeBytes) {
1723                    throw new RSIllegalArgumentException("Array too small for allocation type.");
1724                }
1725            }
1726            mRS.nAllocationRead2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
1727                                  array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
1728        } finally {
1729            Trace.traceEnd(RenderScript.TRACE_TAG);
1730        }
1731    }
1732
1733    /**
1734     * Copy from a rectangular region in this Allocation into an array.
1735     *
1736     * @param xoff X offset of the region to copy in this Allocation
1737     * @param yoff Y offset of the region to copy in this Allocation
1738     * @param w Width of the region to copy
1739     * @param h Height of the region to copy
1740     * @param array Dest Array to be copied into
1741     */
1742    public void copy2DRangeTo(int xoff, int yoff, int w, int h, Object array) {
1743        copy2DRangeToUnchecked(xoff, yoff, w, h, array,
1744                               validateObjectIsPrimitiveArray(array, true),
1745                               java.lang.reflect.Array.getLength(array));
1746    }
1747
1748    /**
1749     * Copy from a rectangular region in this Allocation into an array.
1750     *
1751     * @param xoff X offset of the region to copy in this Allocation
1752     * @param yoff Y offset of the region to copy in this Allocation
1753     * @param w Width of the region to copy
1754     * @param h Height of the region to copy
1755     * @param data Dest Array to be copied into
1756     */
1757    public void copy2DRangeTo(int xoff, int yoff, int w, int h, byte[] data) {
1758        validateIsInt8();
1759        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
1760                               Element.DataType.SIGNED_8, data.length);
1761    }
1762
1763    /**
1764     * Copy from a rectangular region in this Allocation into an array.
1765     *
1766     * @param xoff X offset of the region to copy in this Allocation
1767     * @param yoff Y offset of the region to copy in this Allocation
1768     * @param w Width of the region to copy
1769     * @param h Height of the region to copy
1770     * @param data Dest Array to be copied into
1771     */
1772    public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
1773        validateIsInt16();
1774        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
1775                               Element.DataType.SIGNED_16, data.length);
1776    }
1777
1778    /**
1779     * Copy from a rectangular region in this Allocation into an array.
1780     *
1781     * @param xoff X offset of the region to copy in this Allocation
1782     * @param yoff Y offset of the region to copy in this Allocation
1783     * @param w Width of the region to copy
1784     * @param h Height of the region to copy
1785     * @param data Dest Array to be copied into
1786     */
1787    public void copy2DRangeTo(int xoff, int yoff, int w, int h, int[] data) {
1788        validateIsInt32();
1789        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
1790                               Element.DataType.SIGNED_32, data.length);
1791    }
1792
1793    /**
1794     * Copy from a rectangular region in this Allocation into an array.
1795     *
1796     * @param xoff X offset of the region to copy in this Allocation
1797     * @param yoff Y offset of the region to copy in this Allocation
1798     * @param w Width of the region to copy
1799     * @param h Height of the region to copy
1800     * @param data Dest Array to be copied into
1801     */
1802    public void copy2DRangeTo(int xoff, int yoff, int w, int h, float[] data) {
1803        validateIsFloat32();
1804        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
1805                               Element.DataType.FLOAT_32, data.length);
1806    }
1807
1808
1809    /**
1810     * Copy from a rectangular region in this Allocation into an array.
1811     * The array is assumed to be tightly packed.
1812     *
1813     * The data type of the array is not required to be the same as
1814     * the element data type.
1815     */
1816    private void copy3DRangeToUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
1817                                        Object array, Element.DataType dt, int arrayLen) {
1818        try {
1819            Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeToUnchecked");
1820            mRS.validate();
1821            validate3DRange(xoff, yoff, zoff, w, h, d);
1822            final int dataSize = mType.mElement.getBytesSize() * w * h * d;
1823            // AutoPadding for Vec3 Element
1824            boolean usePadding = false;
1825            int sizeBytes = arrayLen * dt.mSize;
1826            if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1827                if (dataSize / 4 * 3 > sizeBytes) {
1828                    throw new RSIllegalArgumentException("Array too small for allocation type.");
1829                }
1830                usePadding = true;
1831                sizeBytes = dataSize;
1832            } else {
1833                if (dataSize > sizeBytes) {
1834                    throw new RSIllegalArgumentException("Array too small for allocation type.");
1835                }
1836            }
1837            mRS.nAllocationRead3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
1838                                  array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
1839        } finally {
1840            Trace.traceEnd(RenderScript.TRACE_TAG);
1841        }
1842    }
1843
1844    /*
1845     * Copy from a rectangular region in this Allocation into an array.
1846     *
1847     * @param xoff X offset of the region to copy in this Allocation
1848     * @param yoff Y offset of the region to copy in this Allocation
1849     * @param zoff Z offset of the region to copy in this Allocation
1850     * @param w Width of the region to copy
1851     * @param h Height of the region to copy
1852     * @param d Depth of the region to copy
1853     * @param array Dest Array to be copied into
1854     */
1855    public void copy3DRangeTo(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
1856        copy3DRangeToUnchecked(xoff, yoff, zoff, w, h, d, array,
1857                                 validateObjectIsPrimitiveArray(array, true),
1858                                 java.lang.reflect.Array.getLength(array));
1859    }
1860
1861    // creation
1862
1863    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
1864    static {
1865        mBitmapOptions.inScaled = false;
1866    }
1867
1868    /**
1869     * Creates a new Allocation with the given {@link
1870     * android.renderscript.Type}, mipmap flag, and usage flags.
1871     *
1872     * @param type RenderScript type describing data layout
1873     * @param mips specifies desired mipmap behaviour for the
1874     *             allocation
1875     * @param usage bit field specifying how the Allocation is
1876     *              utilized
1877     */
1878    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
1879        try {
1880            Trace.traceBegin(RenderScript.TRACE_TAG, "createTyped");
1881            rs.validate();
1882            if (type.getID(rs) == 0) {
1883                throw new RSInvalidStateException("Bad Type");
1884            }
1885            long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
1886            if (id == 0) {
1887                throw new RSRuntimeException("Allocation creation failed.");
1888            }
1889            return new Allocation(id, rs, type, usage);
1890        } finally {
1891            Trace.traceEnd(RenderScript.TRACE_TAG);
1892        }
1893    }
1894
1895    /**
1896     * Creates an Allocation with the size specified by the type and no mipmaps
1897     * generated by default
1898     *
1899     * @param rs Context to which the allocation will belong.
1900     * @param type renderscript type describing data layout
1901     * @param usage bit field specifying how the allocation is
1902     *              utilized
1903     *
1904     * @return allocation
1905     */
1906    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
1907        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
1908    }
1909
1910    /**
1911     * Creates an Allocation for use by scripts with a given {@link
1912     * android.renderscript.Type} and no mipmaps
1913     *
1914     * @param rs Context to which the Allocation will belong.
1915     * @param type RenderScript Type describing data layout
1916     *
1917     * @return allocation
1918     */
1919    static public Allocation createTyped(RenderScript rs, Type type) {
1920        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
1921    }
1922
1923    /**
1924     * Creates an Allocation with a specified number of given elements
1925     *
1926     * @param rs Context to which the Allocation will belong.
1927     * @param e Element to use in the Allocation
1928     * @param count the number of Elements in the Allocation
1929     * @param usage bit field specifying how the Allocation is
1930     *              utilized
1931     *
1932     * @return allocation
1933     */
1934    static public Allocation createSized(RenderScript rs, Element e,
1935                                         int count, int usage) {
1936        try {
1937            Trace.traceBegin(RenderScript.TRACE_TAG, "createSized");
1938            rs.validate();
1939            Type.Builder b = new Type.Builder(rs, e);
1940            b.setX(count);
1941            Type t = b.create();
1942
1943            long id = rs.nAllocationCreateTyped(t.getID(rs), MipmapControl.MIPMAP_NONE.mID, usage, 0);
1944            if (id == 0) {
1945                throw new RSRuntimeException("Allocation creation failed.");
1946            }
1947            return new Allocation(id, rs, t, usage);
1948        } finally {
1949            Trace.traceEnd(RenderScript.TRACE_TAG);
1950        }
1951    }
1952
1953    /**
1954     * Creates an Allocation with a specified number of given elements
1955     *
1956     * @param rs Context to which the Allocation will belong.
1957     * @param e Element to use in the Allocation
1958     * @param count the number of Elements in the Allocation
1959     *
1960     * @return allocation
1961     */
1962    static public Allocation createSized(RenderScript rs, Element e, int count) {
1963        return createSized(rs, e, count, USAGE_SCRIPT);
1964    }
1965
1966    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
1967        final Bitmap.Config bc = b.getConfig();
1968        if (bc == Bitmap.Config.ALPHA_8) {
1969            return Element.A_8(rs);
1970        }
1971        if (bc == Bitmap.Config.ARGB_4444) {
1972            return Element.RGBA_4444(rs);
1973        }
1974        if (bc == Bitmap.Config.ARGB_8888) {
1975            return Element.RGBA_8888(rs);
1976        }
1977        if (bc == Bitmap.Config.RGB_565) {
1978            return Element.RGB_565(rs);
1979        }
1980        throw new RSInvalidStateException("Bad bitmap type: " + bc);
1981    }
1982
1983    static Type typeFromBitmap(RenderScript rs, Bitmap b,
1984                                       MipmapControl mip) {
1985        Element e = elementFromBitmap(rs, b);
1986        Type.Builder tb = new Type.Builder(rs, e);
1987        tb.setX(b.getWidth());
1988        tb.setY(b.getHeight());
1989        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
1990        return tb.create();
1991    }
1992
1993    /**
1994     * Creates an Allocation from a {@link android.graphics.Bitmap}.
1995     *
1996     * @param rs Context to which the allocation will belong.
1997     * @param b Bitmap source for the allocation data
1998     * @param mips specifies desired mipmap behaviour for the
1999     *             allocation
2000     * @param usage bit field specifying how the allocation is
2001     *              utilized
2002     *
2003     * @return Allocation containing bitmap data
2004     *
2005     */
2006    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
2007                                              MipmapControl mips,
2008                                              int usage) {
2009        try {
2010            Trace.traceBegin(RenderScript.TRACE_TAG, "createFromBitmap");
2011            rs.validate();
2012
2013            // WAR undocumented color formats
2014            if (b.getConfig() == null) {
2015                if ((usage & USAGE_SHARED) != 0) {
2016                    throw new RSIllegalArgumentException("USAGE_SHARED cannot be used with a Bitmap that has a null config.");
2017                }
2018                Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
2019                Canvas c = new Canvas(newBitmap);
2020                c.drawBitmap(b, 0, 0, null);
2021                return createFromBitmap(rs, newBitmap, mips, usage);
2022            }
2023
2024            Type t = typeFromBitmap(rs, b, mips);
2025
2026            // enable optimized bitmap path only with no mipmap and script-only usage
2027            if (mips == MipmapControl.MIPMAP_NONE &&
2028                 t.getElement().isCompatible(Element.RGBA_8888(rs)) &&
2029                 usage == (USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE)) {
2030                long id = rs.nAllocationCreateBitmapBackedAllocation(t.getID(rs), mips.mID, b, usage);
2031                if (id == 0) {
2032                    throw new RSRuntimeException("Load failed.");
2033                }
2034
2035                // keep a reference to the Bitmap around to prevent GC
2036                Allocation alloc = new Allocation(id, rs, t, usage);
2037                alloc.setBitmap(b);
2038                return alloc;
2039            }
2040
2041
2042            long id = rs.nAllocationCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
2043            if (id == 0) {
2044                throw new RSRuntimeException("Load failed.");
2045            }
2046            return new Allocation(id, rs, t, usage);
2047        } finally {
2048            Trace.traceEnd(RenderScript.TRACE_TAG);
2049        }
2050    }
2051
2052    /**
2053     * Returns the handle to a raw buffer that is being managed by the screen
2054     * compositor. This operation is only valid for Allocations with {@link
2055     * #USAGE_IO_INPUT}.
2056     *
2057     * @return Surface object associated with allocation
2058     *
2059     */
2060    public Surface getSurface() {
2061        if ((mUsage & USAGE_IO_INPUT) == 0) {
2062            throw new RSInvalidStateException("Allocation is not a surface texture.");
2063        }
2064
2065        if (mGetSurfaceSurface == null) {
2066            mGetSurfaceSurface = mRS.nAllocationGetSurface(getID(mRS));
2067        }
2068
2069        return mGetSurfaceSurface;
2070    }
2071
2072    /**
2073     * Associate a {@link android.view.Surface} with this Allocation. This
2074     * operation is only valid for Allocations with {@link #USAGE_IO_OUTPUT}.
2075     *
2076     * @param sur Surface to associate with allocation
2077     */
2078    public void setSurface(Surface sur) {
2079        mRS.validate();
2080        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
2081            throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
2082        }
2083
2084        mRS.nAllocationSetSurface(getID(mRS), sur);
2085    }
2086
2087    /**
2088     * Creates an Allocation from a {@link android.graphics.Bitmap}.
2089     *
2090     * <p>With target API version 18 or greater, this Allocation will be created
2091     * with {@link #USAGE_SHARED}, {@link #USAGE_SCRIPT}, and {@link
2092     * #USAGE_GRAPHICS_TEXTURE}. With target API version 17 or lower, this
2093     * Allocation will be created with {@link #USAGE_GRAPHICS_TEXTURE}.</p>
2094     *
2095     * @param rs Context to which the allocation will belong.
2096     * @param b bitmap source for the allocation data
2097     *
2098     * @return Allocation containing bitmap data
2099     *
2100     */
2101    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
2102        if (rs.getApplicationContext().getApplicationInfo().targetSdkVersion >= 18) {
2103            return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
2104                                    USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
2105        }
2106        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
2107                                USAGE_GRAPHICS_TEXTURE);
2108    }
2109
2110    /**
2111     * Creates a cubemap Allocation from a {@link android.graphics.Bitmap}
2112     * containing the horizontal list of cube faces. Each face must be a square,
2113     * have the same size as all other faces, and have a width that is a power
2114     * of 2.
2115     *
2116     * @param rs Context to which the allocation will belong.
2117     * @param b Bitmap with cubemap faces layed out in the following
2118     *          format: right, left, top, bottom, front, back
2119     * @param mips specifies desired mipmap behaviour for the cubemap
2120     * @param usage bit field specifying how the cubemap is utilized
2121     *
2122     * @return allocation containing cubemap data
2123     *
2124     */
2125    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
2126                                                     MipmapControl mips,
2127                                                     int usage) {
2128        rs.validate();
2129
2130        int height = b.getHeight();
2131        int width = b.getWidth();
2132
2133        if (width % 6 != 0) {
2134            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
2135        }
2136        if (width / 6 != height) {
2137            throw new RSIllegalArgumentException("Only square cube map faces supported");
2138        }
2139        boolean isPow2 = (height & (height - 1)) == 0;
2140        if (!isPow2) {
2141            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
2142        }
2143
2144        Element e = elementFromBitmap(rs, b);
2145        Type.Builder tb = new Type.Builder(rs, e);
2146        tb.setX(height);
2147        tb.setY(height);
2148        tb.setFaces(true);
2149        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
2150        Type t = tb.create();
2151
2152        long id = rs.nAllocationCubeCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
2153        if(id == 0) {
2154            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
2155        }
2156        return new Allocation(id, rs, t, usage);
2157    }
2158
2159    /**
2160     * Creates a non-mipmapped cubemap Allocation for use as a graphics texture
2161     * from a {@link android.graphics.Bitmap} containing the horizontal list of
2162     * cube faces. Each face must be a square, have the same size as all other
2163     * faces, and have a width that is a power of 2.
2164     *
2165     * @param rs Context to which the allocation will belong.
2166     * @param b bitmap with cubemap faces layed out in the following
2167     *          format: right, left, top, bottom, front, back
2168     *
2169     * @return allocation containing cubemap data
2170     *
2171     */
2172    static public Allocation createCubemapFromBitmap(RenderScript rs,
2173                                                     Bitmap b) {
2174        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
2175                                       USAGE_GRAPHICS_TEXTURE);
2176    }
2177
2178    /**
2179     * Creates a cubemap Allocation from 6 {@link android.graphics.Bitmap}
2180     * objects containing the cube faces. Each face must be a square, have the
2181     * same size as all other faces, and have a width that is a power of 2.
2182     *
2183     * @param rs Context to which the allocation will belong.
2184     * @param xpos cubemap face in the positive x direction
2185     * @param xneg cubemap face in the negative x direction
2186     * @param ypos cubemap face in the positive y direction
2187     * @param yneg cubemap face in the negative y direction
2188     * @param zpos cubemap face in the positive z direction
2189     * @param zneg cubemap face in the negative z direction
2190     * @param mips specifies desired mipmap behaviour for the cubemap
2191     * @param usage bit field specifying how the cubemap is utilized
2192     *
2193     * @return allocation containing cubemap data
2194     *
2195     */
2196    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
2197                                                        Bitmap xpos,
2198                                                        Bitmap xneg,
2199                                                        Bitmap ypos,
2200                                                        Bitmap yneg,
2201                                                        Bitmap zpos,
2202                                                        Bitmap zneg,
2203                                                        MipmapControl mips,
2204                                                        int usage) {
2205        int height = xpos.getHeight();
2206        if (xpos.getWidth() != height ||
2207            xneg.getWidth() != height || xneg.getHeight() != height ||
2208            ypos.getWidth() != height || ypos.getHeight() != height ||
2209            yneg.getWidth() != height || yneg.getHeight() != height ||
2210            zpos.getWidth() != height || zpos.getHeight() != height ||
2211            zneg.getWidth() != height || zneg.getHeight() != height) {
2212            throw new RSIllegalArgumentException("Only square cube map faces supported");
2213        }
2214        boolean isPow2 = (height & (height - 1)) == 0;
2215        if (!isPow2) {
2216            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
2217        }
2218
2219        Element e = elementFromBitmap(rs, xpos);
2220        Type.Builder tb = new Type.Builder(rs, e);
2221        tb.setX(height);
2222        tb.setY(height);
2223        tb.setFaces(true);
2224        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
2225        Type t = tb.create();
2226        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
2227
2228        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
2229        adapter.setFace(Type.CubemapFace.POSITIVE_X);
2230        adapter.copyFrom(xpos);
2231        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
2232        adapter.copyFrom(xneg);
2233        adapter.setFace(Type.CubemapFace.POSITIVE_Y);
2234        adapter.copyFrom(ypos);
2235        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
2236        adapter.copyFrom(yneg);
2237        adapter.setFace(Type.CubemapFace.POSITIVE_Z);
2238        adapter.copyFrom(zpos);
2239        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
2240        adapter.copyFrom(zneg);
2241
2242        return cubemap;
2243    }
2244
2245    /**
2246     * Creates a non-mipmapped cubemap Allocation for use as a sampler input
2247     * from 6 {@link android.graphics.Bitmap} objects containing the cube
2248     * faces. Each face must be a square, have the same size as all other faces,
2249     * and have a width that is a power of 2.
2250     *
2251     * @param rs Context to which the allocation will belong.
2252     * @param xpos cubemap face in the positive x direction
2253     * @param xneg cubemap face in the negative x direction
2254     * @param ypos cubemap face in the positive y direction
2255     * @param yneg cubemap face in the negative y direction
2256     * @param zpos cubemap face in the positive z direction
2257     * @param zneg cubemap face in the negative z direction
2258     *
2259     * @return allocation containing cubemap data
2260     *
2261     */
2262    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
2263                                                        Bitmap xpos,
2264                                                        Bitmap xneg,
2265                                                        Bitmap ypos,
2266                                                        Bitmap yneg,
2267                                                        Bitmap zpos,
2268                                                        Bitmap zneg) {
2269        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
2270                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
2271                                          USAGE_GRAPHICS_TEXTURE);
2272    }
2273
2274    /**
2275     * Creates an Allocation from the Bitmap referenced
2276     * by resource ID.
2277     *
2278     * @param rs Context to which the allocation will belong.
2279     * @param res application resources
2280     * @param id resource id to load the data from
2281     * @param mips specifies desired mipmap behaviour for the
2282     *             allocation
2283     * @param usage bit field specifying how the allocation is
2284     *              utilized
2285     *
2286     * @return Allocation containing resource data
2287     *
2288     */
2289    static public Allocation createFromBitmapResource(RenderScript rs,
2290                                                      Resources res,
2291                                                      int id,
2292                                                      MipmapControl mips,
2293                                                      int usage) {
2294
2295        rs.validate();
2296        if ((usage & (USAGE_SHARED | USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) {
2297            throw new RSIllegalArgumentException("Unsupported usage specified.");
2298        }
2299        Bitmap b = BitmapFactory.decodeResource(res, id);
2300        Allocation alloc = createFromBitmap(rs, b, mips, usage);
2301        b.recycle();
2302        return alloc;
2303    }
2304
2305    /**
2306     * Creates a non-mipmapped Allocation to use as a graphics texture from the
2307     * {@link android.graphics.Bitmap} referenced by resource ID.
2308     *
2309     * <p>With target API version 18 or greater, this allocation will be created
2310     * with {@link #USAGE_SCRIPT} and {@link #USAGE_GRAPHICS_TEXTURE}. With
2311     * target API version 17 or lower, this allocation will be created with
2312     * {@link #USAGE_GRAPHICS_TEXTURE}.</p>
2313     *
2314     * @param rs Context to which the allocation will belong.
2315     * @param res application resources
2316     * @param id resource id to load the data from
2317     *
2318     * @return Allocation containing resource data
2319     *
2320     */
2321    static public Allocation createFromBitmapResource(RenderScript rs,
2322                                                      Resources res,
2323                                                      int id) {
2324        if (rs.getApplicationContext().getApplicationInfo().targetSdkVersion >= 18) {
2325            return createFromBitmapResource(rs, res, id,
2326                                            MipmapControl.MIPMAP_NONE,
2327                                            USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
2328        }
2329        return createFromBitmapResource(rs, res, id,
2330                                        MipmapControl.MIPMAP_NONE,
2331                                        USAGE_GRAPHICS_TEXTURE);
2332    }
2333
2334    /**
2335     * Creates an Allocation containing string data encoded in UTF-8 format.
2336     *
2337     * @param rs Context to which the allocation will belong.
2338     * @param str string to create the allocation from
2339     * @param usage bit field specifying how the allocaiton is
2340     *              utilized
2341     *
2342     */
2343    static public Allocation createFromString(RenderScript rs,
2344                                              String str,
2345                                              int usage) {
2346        rs.validate();
2347        byte[] allocArray = null;
2348        try {
2349            allocArray = str.getBytes("UTF-8");
2350            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
2351            alloc.copyFrom(allocArray);
2352            return alloc;
2353        }
2354        catch (Exception e) {
2355            throw new RSRuntimeException("Could not convert string to utf-8.");
2356        }
2357    }
2358
2359    /**
2360     * Interface to handle notification when new buffers are available via
2361     * {@link #USAGE_IO_INPUT}. An application will receive one notification
2362     * when a buffer is available. Additional buffers will not trigger new
2363     * notifications until a buffer is processed.
2364     */
2365    public interface OnBufferAvailableListener {
2366        public void onBufferAvailable(Allocation a);
2367    }
2368
2369    /**
2370     * Set a notification handler for {@link #USAGE_IO_INPUT}.
2371     *
2372     * @param callback instance of the OnBufferAvailableListener
2373     *                 class to be called when buffer arrive.
2374     */
2375    public void setOnBufferAvailableListener(OnBufferAvailableListener callback) {
2376        synchronized(mAllocationMap) {
2377            mAllocationMap.put(new Long(getID(mRS)), this);
2378            mBufferNotifier = callback;
2379        }
2380    }
2381
2382    static void sendBufferNotification(long id) {
2383        synchronized(mAllocationMap) {
2384            Allocation a = mAllocationMap.get(new Long(id));
2385
2386            if ((a != null) && (a.mBufferNotifier != null)) {
2387                a.mBufferNotifier.onBufferAvailable(a);
2388            }
2389        }
2390    }
2391
2392    /**
2393     * For USAGE_IO_OUTPUT, destroy() implies setSurface(null).
2394     *
2395     */
2396    @Override
2397    public void destroy() {
2398        if((mUsage & USAGE_IO_OUTPUT) != 0) {
2399            setSurface(null);
2400        }
2401        super.destroy();
2402    }
2403}
2404