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