Allocation.java revision a4f4a00cdd01fe58862f7ee7d81a9fd445f9dbf7
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 zoff
800     * @param component_number
801     * @param fp
802     */
803    /*
804    public void setFromFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
805        mRS.validate();
806        if (component_number >= mType.mElement.mElements.length) {
807            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
808        }
809        if(xoff < 0) {
810            throw new RSIllegalArgumentException("Offset x must be >= 0.");
811        }
812        if(yoff < 0) {
813            throw new RSIllegalArgumentException("Offset y must be >= 0.");
814        }
815        if(zoff < 0) {
816            throw new RSIllegalArgumentException("Offset z must be >= 0.");
817        }
818
819        final byte[] data = fp.getData();
820        int data_length = fp.getPos();
821        int eSize = mType.mElement.mElements[component_number].getBytesSize();
822        eSize *= mType.mElement.mArraySizes[component_number];
823
824        if (data_length != eSize) {
825            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
826                                               " does not match component size " + eSize + ".");
827        }
828
829        mRS.nAllocationElementData(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
830                                   component_number, data, data_length);
831    }
832    */
833
834    private void data1DChecks(int off, int count, int len, int dataSize, boolean usePadding) {
835        mRS.validate();
836        if(off < 0) {
837            throw new RSIllegalArgumentException("Offset must be >= 0.");
838        }
839        if(count < 1) {
840            throw new RSIllegalArgumentException("Count must be >= 1.");
841        }
842        if((off + count) > mCurrentCount) {
843            throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
844                                               ", got " + count + " at offset " + off + ".");
845        }
846        if(usePadding) {
847            if(len < dataSize / 4 * 3) {
848                throw new RSIllegalArgumentException("Array too small for allocation type.");
849            }
850        } else {
851            if(len < dataSize) {
852                throw new RSIllegalArgumentException("Array too small for allocation type.");
853            }
854        }
855    }
856
857    /**
858     * Generate a mipmap chain. This is only valid if the Type of the Allocation
859     * includes mipmaps.
860     *
861     * <p>This function will generate a complete set of mipmaps from the top
862     * level LOD and place them into the script memory space.</p>
863     *
864     * <p>If the Allocation is also using other memory spaces, a call to {@link
865     * #syncAll syncAll(Allocation.USAGE_SCRIPT)} is required.</p>
866     */
867    public void generateMipmaps() {
868        mRS.nAllocationGenerateMipmaps(getID(mRS));
869    }
870
871    private void copy1DRangeFromUnchecked(int off, int count, Object array,
872                                          Element.DataType dt, int arrayLen) {
873        final int dataSize = mType.mElement.getBytesSize() * count;
874        // AutoPadding for Vec3 Element
875        boolean usePadding = false;
876        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
877            usePadding = true;
878        }
879        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
880        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
881                              mType.mElement.mType.mSize, usePadding);
882    }
883
884    /**
885     * Copy an array into part of this Allocation.  This method does not
886     * guarantee that the Allocation is compatible with the input buffer.
887     *
888     * @param off The offset of the first element to be copied.
889     * @param count The number of elements to be copied.
890     * @param array The source data array
891     */
892    public void copy1DRangeFromUnchecked(int off, int count, Object array) {
893        copy1DRangeFromUnchecked(off, count, array,
894                                 validateObjectIsPrimitiveArray(array, false),
895                                 java.lang.reflect.Array.getLength(array));
896    }
897
898    /**
899     * Copy an array into part of this Allocation.  This method does not
900     * guarantee that the Allocation is compatible with the input buffer.
901     *
902     * @param off The offset of the first element to be copied.
903     * @param count The number of elements to be copied.
904     * @param d the source data array
905     */
906    public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
907        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
908    }
909
910    /**
911     * Copy an array into part of this Allocation.  This method does not
912     * guarantee that the Allocation is compatible with the input buffer.
913     *
914     * @param off The offset of the first element to be copied.
915     * @param count The number of elements to be copied.
916     * @param d the source data array
917     */
918    public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
919        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
920    }
921
922    /**
923     * Copy an array into part of this Allocation.  This method does not
924     * guarantee that the Allocation is compatible with the input buffer.
925     *
926     * @param off The offset of the first element to be copied.
927     * @param count The number of elements to be copied.
928     * @param d the source data array
929     */
930    public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
931        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
932    }
933
934    /**
935     * Copy an array into part of this Allocation.  This method does not
936     * guarantee that the Allocation is compatible with the input buffer.
937     *
938     * @param off The offset of the first element to be copied.
939     * @param count The number of elements to be copied.
940     * @param d the source data array
941     */
942    public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
943        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
944    }
945
946
947    /**
948     * Copy an array into part of this Allocation.  This variant is type checked
949     * and will generate exceptions if the Allocation type does not
950     * match the component type of the array passed in.
951     *
952     * @param off The offset of the first element to be copied.
953     * @param count The number of elements to be copied.
954     * @param array The source data array.
955     */
956    public void copy1DRangeFrom(int off, int count, Object array) {
957        copy1DRangeFromUnchecked(off, count, array,
958                                 validateObjectIsPrimitiveArray(array, true),
959                                 java.lang.reflect.Array.getLength(array));
960    }
961
962    /**
963     * Copy an array into part of this Allocation.  This variant is type checked
964     * and will generate exceptions if the Allocation type is not a 32 bit
965     * integer type.
966     *
967     * @param off The offset of the first element to be copied.
968     * @param count The number of elements to be copied.
969     * @param d the source data array
970     */
971    public void copy1DRangeFrom(int off, int count, int[] d) {
972        validateIsInt32();
973        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
974    }
975
976    /**
977     * Copy an array into part of this Allocation.  This variant is type checked
978     * and will generate exceptions if the Allocation type is not a 16 bit
979     * integer type.
980     *
981     * @param off The offset of the first element to be copied.
982     * @param count The number of elements to be copied.
983     * @param d the source data array
984     */
985    public void copy1DRangeFrom(int off, int count, short[] d) {
986        validateIsInt16();
987        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
988    }
989
990    /**
991     * Copy an array into part of this Allocation.  This variant is type checked
992     * and will generate exceptions if the Allocation type is not an 8 bit
993     * integer type.
994     *
995     * @param off The offset of the first element to be copied.
996     * @param count The number of elements to be copied.
997     * @param d the source data array
998     */
999    public void copy1DRangeFrom(int off, int count, byte[] d) {
1000        validateIsInt8();
1001        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
1002    }
1003
1004    /**
1005     * Copy an array into part of this Allocation.  This variant is type checked
1006     * and will generate exceptions if the Allocation type is not a 32 bit float
1007     * type.
1008     *
1009     * @param off The offset of the first element to be copied.
1010     * @param count The number of elements to be copied.
1011     * @param d the source data array.
1012     */
1013    public void copy1DRangeFrom(int off, int count, float[] d) {
1014        validateIsFloat32();
1015        copy1DRangeFromUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
1016    }
1017
1018     /**
1019     * Copy part of an Allocation into this Allocation.
1020     *
1021     * @param off The offset of the first element to be copied.
1022     * @param count The number of elements to be copied.
1023     * @param data the source data allocation.
1024     * @param dataOff off The offset of the first element in data to
1025     *          be copied.
1026     */
1027    public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
1028        mRS.nAllocationData2D(getIDSafe(), off, 0,
1029                              mSelectedLOD, mSelectedFace.mID,
1030                              count, 1, data.getID(mRS), dataOff, 0,
1031                              data.mSelectedLOD, data.mSelectedFace.mID);
1032    }
1033
1034    private void validate2DRange(int xoff, int yoff, int w, int h) {
1035        if (mAdaptedAllocation != null) {
1036
1037        } else {
1038
1039            if (xoff < 0 || yoff < 0) {
1040                throw new RSIllegalArgumentException("Offset cannot be negative.");
1041            }
1042            if (h < 0 || w < 0) {
1043                throw new RSIllegalArgumentException("Height or width cannot be negative.");
1044            }
1045            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
1046                throw new RSIllegalArgumentException("Updated region larger than allocation.");
1047            }
1048        }
1049    }
1050
1051    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, Object array,
1052                                  Element.DataType dt, int arrayLen) {
1053        mRS.validate();
1054        validate2DRange(xoff, yoff, w, h);
1055        final int dataSize = mType.mElement.getBytesSize() * w * h;
1056        // AutoPadding for Vec3 Element
1057        boolean usePadding = false;
1058        int sizeBytes = arrayLen * dt.mSize;
1059        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1060            if (dataSize / 4 * 3 > sizeBytes) {
1061                throw new RSIllegalArgumentException("Array too small for allocation type.");
1062            }
1063            usePadding = true;
1064            sizeBytes = dataSize;
1065        } else {
1066            if (dataSize > sizeBytes) {
1067                throw new RSIllegalArgumentException("Array too small for allocation type.");
1068            }
1069        }
1070        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
1071                              array, sizeBytes, dt,
1072                              mType.mElement.mType.mSize, usePadding);
1073    }
1074
1075    /**
1076     * Copy from an array into a rectangular region in this Allocation.  The
1077     * array is assumed to be tightly packed.
1078     *
1079     * @param xoff X offset of the region to update in this Allocation
1080     * @param yoff Y offset of the region to update in this Allocation
1081     * @param w Width of the region to update
1082     * @param h Height of the region to update
1083     * @param array Data to be placed into the Allocation
1084     */
1085    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, Object array) {
1086        copy2DRangeFromUnchecked(xoff, yoff, w, h, array,
1087                                 validateObjectIsPrimitiveArray(array, true),
1088                                 java.lang.reflect.Array.getLength(array));
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 data to be placed into the Allocation
1100     */
1101    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
1102        validateIsInt8();
1103        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
1104                                 Element.DataType.SIGNED_8, data.length);
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, short[] data) {
1118        validateIsInt16();
1119        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
1120                                 Element.DataType.SIGNED_16, 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, int[] data) {
1134        validateIsInt32();
1135        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
1136                                 Element.DataType.SIGNED_32, 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, float[] data) {
1150        validateIsFloat32();
1151        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
1152                                 Element.DataType.FLOAT_32, data.length);
1153    }
1154
1155    /**
1156     * Copy a rectangular region from an Allocation into a rectangular region in
1157     * this Allocation.
1158     *
1159     * @param xoff X offset of the region in this Allocation
1160     * @param yoff Y offset of the region in this Allocation
1161     * @param w Width of the region to update.
1162     * @param h Height of the region to update.
1163     * @param data source Allocation.
1164     * @param dataXoff X offset in source Allocation
1165     * @param dataYoff Y offset in source Allocation
1166     */
1167    public void copy2DRangeFrom(int xoff, int yoff, int w, int h,
1168                                Allocation data, int dataXoff, int dataYoff) {
1169        mRS.validate();
1170        validate2DRange(xoff, yoff, w, h);
1171        mRS.nAllocationData2D(getIDSafe(), xoff, yoff,
1172                              mSelectedLOD, mSelectedFace.mID,
1173                              w, h, data.getID(mRS), dataXoff, dataYoff,
1174                              data.mSelectedLOD, data.mSelectedFace.mID);
1175    }
1176
1177    /**
1178     * Copy a {@link android.graphics.Bitmap} into an Allocation.  The height
1179     * and width of the update will use the height and width of the {@link
1180     * android.graphics.Bitmap}.
1181     *
1182     * @param xoff X offset of the region to update in this Allocation
1183     * @param yoff Y offset of the region to update in this Allocation
1184     * @param data the Bitmap to be copied
1185     */
1186    public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
1187        mRS.validate();
1188        if (data.getConfig() == null) {
1189            Bitmap newBitmap = Bitmap.createBitmap(data.getWidth(), data.getHeight(), Bitmap.Config.ARGB_8888);
1190            Canvas c = new Canvas(newBitmap);
1191            c.drawBitmap(data, 0, 0, null);
1192            copy2DRangeFrom(xoff, yoff, newBitmap);
1193            return;
1194        }
1195        validateBitmapFormat(data);
1196        validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
1197        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
1198    }
1199
1200    private void validate3DRange(int xoff, int yoff, int zoff, int w, int h, int d) {
1201        if (mAdaptedAllocation != null) {
1202
1203        } else {
1204
1205            if (xoff < 0 || yoff < 0 || zoff < 0) {
1206                throw new RSIllegalArgumentException("Offset cannot be negative.");
1207            }
1208            if (h < 0 || w < 0 || d < 0) {
1209                throw new RSIllegalArgumentException("Height or width cannot be negative.");
1210            }
1211            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) {
1212                throw new RSIllegalArgumentException("Updated region larger than allocation.");
1213            }
1214        }
1215    }
1216
1217    /**
1218     * @hide
1219     *
1220     */
1221    private void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
1222                                          Object array, Element.DataType dt, int arrayLen) {
1223        mRS.validate();
1224        validate3DRange(xoff, yoff, zoff, w, h, d);
1225        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
1226        // AutoPadding for Vec3 Element
1227        boolean usePadding = false;
1228        int sizeBytes = arrayLen * dt.mSize;
1229        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1230            if (dataSize / 4 * 3 > sizeBytes) {
1231                throw new RSIllegalArgumentException("Array too small for allocation type.");
1232            }
1233            usePadding = true;
1234            sizeBytes = dataSize;
1235        } else {
1236            if (dataSize > sizeBytes) {
1237                throw new RSIllegalArgumentException("Array too small for allocation type.");
1238            }
1239        }
1240        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
1241                              array, sizeBytes, dt,
1242                              mType.mElement.mType.mSize, usePadding);
1243    }
1244
1245    /**
1246     * @hide
1247     * Copy a rectangular region from the array into the allocation.
1248     * The array is assumed to be tightly packed.
1249     *
1250     * @param xoff X offset of the region to update in this Allocation
1251     * @param yoff Y offset of the region to update in this Allocation
1252     * @param zoff Z offset of the region to update in this Allocation
1253     * @param w Width of the region to update
1254     * @param h Height of the region to update
1255     * @param d Depth of the region to update
1256     * @param data to be placed into the allocation
1257     */
1258    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
1259        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, array,
1260                                 validateObjectIsPrimitiveArray(array, true),
1261                                 java.lang.reflect.Array.getLength(array));
1262    }
1263
1264    /**
1265     * @hide
1266     * Copy a rectangular region into the allocation from another
1267     * allocation.
1268     *
1269     * @param xoff X offset of the region to update in this Allocation
1270     * @param yoff Y offset of the region to update in this Allocation
1271     * @param zoff Z offset of the region to update in this Allocation
1272     * @param w Width of the region to update.
1273     * @param h Height of the region to update.
1274     * @param d Depth of the region to update.
1275     * @param data source allocation.
1276     * @param dataXoff X offset of the region in the source Allocation
1277     * @param dataYoff Y offset of the region in the source Allocation
1278     * @param dataZoff Z offset of the region in the source Allocation
1279     */
1280    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d,
1281                                Allocation data, int dataXoff, int dataYoff, int dataZoff) {
1282        mRS.validate();
1283        validate3DRange(xoff, yoff, zoff, w, h, d);
1284        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
1285                              w, h, d, data.getID(mRS), dataXoff, dataYoff, dataZoff,
1286                              data.mSelectedLOD);
1287    }
1288
1289
1290    /**
1291     * Copy from the Allocation into a {@link android.graphics.Bitmap}.  The
1292     * bitmap must match the dimensions of the Allocation.
1293     *
1294     * @param b The bitmap to be set from the Allocation.
1295     */
1296    public void copyTo(Bitmap b) {
1297        mRS.validate();
1298        validateBitmapFormat(b);
1299        validateBitmapSize(b);
1300        mRS.nAllocationCopyToBitmap(getID(mRS), b);
1301    }
1302
1303    private void copyTo(Object array, Element.DataType dt, int arrayLen) {
1304        mRS.validate();
1305        boolean usePadding = false;
1306        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1307            usePadding = true;
1308        }
1309        if (usePadding) {
1310            if (dt.mSize * arrayLen < mSize / 4 * 3) {
1311                throw new RSIllegalArgumentException(
1312                    "Size of output array cannot be smaller than size of allocation.");
1313            }
1314        } else {
1315            if (dt.mSize * arrayLen < mSize) {
1316                throw new RSIllegalArgumentException(
1317                    "Size of output array cannot be smaller than size of allocation.");
1318            }
1319        }
1320        mRS.nAllocationRead(getID(mRS), array, dt, mType.mElement.mType.mSize, usePadding);
1321    }
1322
1323    /**
1324     * Copy from the Allocation into an array.  The array must be at
1325     * least as large as the Allocation.  The
1326     * {@link android.renderscript.Element} must match the component
1327     * type of the array passed in.
1328     *
1329     * @param array The array to be set from the Allocation.
1330     */
1331    public void copyTo(Object array) {
1332        copyTo(array, validateObjectIsPrimitiveArray(array, true),
1333               java.lang.reflect.Array.getLength(array));
1334    }
1335
1336    /**
1337     * Copy from the Allocation into a byte array.  The array must be at least
1338     * as large as the Allocation.  The allocation must be of an 8 bit integer
1339     * {@link android.support.v8.renderscript.Element} type.
1340     *
1341     * @param d The array to be set from the Allocation.
1342     */
1343    public void copyTo(byte[] d) {
1344        validateIsInt8();
1345        copyTo(d, Element.DataType.SIGNED_8, d.length);
1346    }
1347
1348    /**
1349     * Copy from the Allocation into a short array.  The array must be at least
1350     * as large as the Allocation.  The allocation must be of an 16 bit integer
1351     * {@link android.support.v8.renderscript.Element} type.
1352     *
1353     * @param d The array to be set from the Allocation.
1354     */
1355    public void copyTo(short[] d) {
1356        validateIsInt16();
1357        copyTo(d, Element.DataType.SIGNED_16, d.length);
1358    }
1359
1360    /**
1361     * Copy from the Allocation into a int array.  The array must be at least as
1362     * large as the Allocation.  The allocation must be of an 32 bit integer
1363     * {@link android.support.v8.renderscript.Element} type.
1364     *
1365     * @param d The array to be set from the Allocation.
1366     */
1367    public void copyTo(int[] d) {
1368        validateIsInt32();
1369        copyTo(d, Element.DataType.SIGNED_32, d.length);
1370    }
1371
1372    /**
1373     * Copy from the Allocation into a float array.  The array must be at least
1374     * as large as the Allocation.  The allocation must be of an 32 bit float
1375     * {@link android.support.v8.renderscript.Element} type.
1376     *
1377     * @param d The array to be set from the Allocation.
1378     */
1379    public void copyTo(float[] d) {
1380        validateIsFloat32();
1381        copyTo(d, Element.DataType.FLOAT_32, d.length);
1382    }
1383
1384    /**
1385     * @hide
1386     * This is only intended to be used by auto-generated code reflected from
1387     * the RenderScript script files and should not be used by developers.
1388     *
1389     * @param xoff
1390     * @param yoff
1391     * @param zoff
1392     * @param component_number
1393     * @param array
1394     */
1395    /*
1396    public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
1397        mRS.validate();
1398        if (component_number >= mType.mElement.mElements.length) {
1399            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
1400        }
1401        if(xoff < 0) {
1402            throw new RSIllegalArgumentException("Offset x must be >= 0.");
1403        }
1404        if(yoff < 0) {
1405            throw new RSIllegalArgumentException("Offset y must be >= 0.");
1406        }
1407        if(zoff < 0) {
1408            throw new RSIllegalArgumentException("Offset z must be >= 0.");
1409        }
1410
1411        final byte[] data = fp.getData();
1412        int data_length = fp.getPos();
1413        int eSize = mType.mElement.mElements[component_number].getBytesSize();
1414        eSize *= mType.mElement.mArraySizes[component_number];
1415
1416        if (data_length != eSize) {
1417            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
1418                                               " does not match component size " + eSize + ".");
1419        }
1420
1421        mRS.nAllocationElementRead(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
1422                                   component_number, data, data_length);
1423    }
1424    */
1425
1426    private void copy1DRangeToUnchecked(int off, int count, Object array,
1427                                        Element.DataType dt, int arrayLen) {
1428        final int dataSize = mType.mElement.getBytesSize() * count;
1429        // AutoPadding for Vec3 Element
1430        boolean usePadding = false;
1431        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1432            usePadding = true;
1433        }
1434        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
1435        mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
1436                              mType.mElement.mType.mSize, usePadding);
1437    }
1438
1439    /**
1440     * @hide
1441     * Copy part of this Allocation into an array.  This method does not
1442     * guarantee that the Allocation is compatible with the input buffer.
1443     *
1444     * @param off The offset of the first element to be copied.
1445     * @param count The number of elements to be copied.
1446     * @param array The dest data array
1447     */
1448    public void copy1DRangeToUnchecked(int off, int count, Object array) {
1449        copy1DRangeToUnchecked(off, count, array,
1450                               validateObjectIsPrimitiveArray(array, false),
1451                               java.lang.reflect.Array.getLength(array));
1452    }
1453
1454    /**
1455     * @hide
1456     * Copy part of this Allocation into an array.  This method does not
1457     * guarantee that the Allocation is compatible with the input buffer.
1458     *
1459     * @param off The offset of the first element to be copied.
1460     * @param count The number of elements to be copied.
1461     * @param d the source data array
1462     */
1463    public void copy1DRangeToUnchecked(int off, int count, int[] d) {
1464        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
1465    }
1466
1467    /**
1468     * @hide
1469     * Copy part of this Allocation into an array.  This method does not
1470     * guarantee that the Allocation is compatible with the input buffer.
1471     *
1472     * @param off The offset of the first element to be copied.
1473     * @param count The number of elements to be copied.
1474     * @param d the source data array
1475     */
1476    public void copy1DRangeToUnchecked(int off, int count, short[] d) {
1477        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
1478    }
1479
1480    /**
1481     * @hide
1482     * Copy part of this Allocation into an array.  This method does not
1483     * guarantee that the Allocation is compatible with the input buffer.
1484     *
1485     * @param off The offset of the first element to be copied.
1486     * @param count The number of elements to be copied.
1487     * @param d the source data array
1488     */
1489    public void copy1DRangeToUnchecked(int off, int count, byte[] d) {
1490        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
1491    }
1492
1493    /**
1494     * @hide
1495     * Copy part of this Allocation into an array.  This method does not
1496     * guarantee that the Allocation is compatible with the input buffer.
1497     *
1498     * @param off The offset of the first element to be copied.
1499     * @param count The number of elements to be copied.
1500     * @param d the source data array
1501     */
1502    public void copy1DRangeToUnchecked(int off, int count, float[] d) {
1503        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
1504    }
1505
1506
1507    /**
1508     * @hide
1509     * Copy part of this Allocation into an array.  This method does not
1510     * and will generate exceptions if the Allocation type does not
1511     * match the component type of the array passed in.
1512     *
1513     * @param off The offset of the first element to be copied.
1514     * @param count The number of elements to be copied.
1515     * @param array The source data array.
1516     */
1517    public void copy1DRangeTo(int off, int count, Object array) {
1518        copy1DRangeToUnchecked(off, count, array,
1519                               validateObjectIsPrimitiveArray(array, true),
1520                               java.lang.reflect.Array.getLength(array));
1521    }
1522
1523    /**
1524     * @hide
1525     * Copy part of this Allocation into an array.  This method does not
1526     * and will generate exceptions if the Allocation type is not a 32 bit
1527     * integer type.
1528     *
1529     * @param off The offset of the first element to be copied.
1530     * @param count The number of elements to be copied.
1531     * @param d the source data array
1532     */
1533    public void copy1DRangeTo(int off, int count, int[] d) {
1534        validateIsInt32();
1535        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
1536    }
1537
1538    /**
1539     * @hide
1540     * Copy part of this Allocation into an array.  This method does not
1541     * and will generate exceptions if the Allocation type is not a 16 bit
1542     * integer type.
1543     *
1544     * @param off The offset of the first element to be copied.
1545     * @param count The number of elements to be copied.
1546     * @param d the source data array
1547     */
1548    public void copy1DRangeTo(int off, int count, short[] d) {
1549        validateIsInt16();
1550        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
1551    }
1552
1553    /**
1554     * @hide
1555     * Copy part of this Allocation into an array.  This method does not
1556     * and will generate exceptions if the Allocation type is not an 8 bit
1557     * integer type.
1558     *
1559     * @param off The offset of the first element to be copied.
1560     * @param count The number of elements to be copied.
1561     * @param d the source data array
1562     */
1563    public void copy1DRangeTo(int off, int count, byte[] d) {
1564        validateIsInt8();
1565        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
1566    }
1567
1568    /**
1569     * @hide
1570     * Copy part of this Allocation into an array.  This method does not
1571     * and will generate exceptions if the Allocation type is not a 32 bit float
1572     * type.
1573     *
1574     * @param off The offset of the first element to be copied.
1575     * @param count The number of elements to be copied.
1576     * @param d the source data array.
1577     */
1578    public void copy1DRangeTo(int off, int count, float[] d) {
1579        validateIsFloat32();
1580        copy1DRangeToUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
1581    }
1582
1583
1584    void copy2DRangeToUnchecked(int xoff, int yoff, int w, int h, Object array,
1585                                Element.DataType dt, int arrayLen) {
1586        mRS.validate();
1587        validate2DRange(xoff, yoff, w, h);
1588        final int dataSize = mType.mElement.getBytesSize() * w * h;
1589        // AutoPadding for Vec3 Element
1590        boolean usePadding = false;
1591        int sizeBytes = arrayLen * dt.mSize;
1592        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1593            if (dataSize / 4 * 3 > sizeBytes) {
1594                throw new RSIllegalArgumentException("Array too small for allocation type.");
1595            }
1596            usePadding = true;
1597            sizeBytes = dataSize;
1598        } else {
1599            if (dataSize > sizeBytes) {
1600                throw new RSIllegalArgumentException("Array too small for allocation type.");
1601            }
1602        }
1603        mRS.nAllocationRead2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
1604                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
1605    }
1606
1607    /**
1608     * @hide
1609     * Copy from a rectangular region in this Allocation into an array.
1610     *
1611     * @param xoff X offset of the region to copy in this Allocation
1612     * @param yoff Y offset of the region to copy in this Allocation
1613     * @param w Width of the region to copy
1614     * @param h Height of the region to copy
1615     * @param array Dest Array to be copied into
1616     */
1617    public void copy2DRangeTo(int xoff, int yoff, int w, int h, Object array) {
1618        copy2DRangeToUnchecked(xoff, yoff, w, h, array,
1619                               validateObjectIsPrimitiveArray(array, true),
1620                               java.lang.reflect.Array.getLength(array));
1621    }
1622
1623    /**
1624     * @hide
1625     * Copy from a rectangular region in this Allocation into an array.
1626     *
1627     * @param xoff X offset of the region to copy in this Allocation
1628     * @param yoff Y offset of the region to copy in this Allocation
1629     * @param w Width of the region to copy
1630     * @param h Height of the region to copy
1631     * @param array Dest Array to be copied into
1632     */
1633    public void copy2DRangeTo(int xoff, int yoff, int w, int h, byte[] data) {
1634        validateIsInt8();
1635        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
1636                               Element.DataType.SIGNED_8, data.length);
1637    }
1638
1639    /**
1640     * @hide
1641     * Copy from a rectangular region in this Allocation into an array.
1642     *
1643     * @param xoff X offset of the region to copy in this Allocation
1644     * @param yoff Y offset of the region to copy in this Allocation
1645     * @param w Width of the region to copy
1646     * @param h Height of the region to copy
1647     * @param array Dest Array to be copied into
1648     */
1649    public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
1650        validateIsInt16();
1651        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
1652                               Element.DataType.SIGNED_16, data.length);
1653    }
1654
1655    /**
1656     * @hide
1657     * Copy from a rectangular region in this Allocation into an array.
1658     *
1659     * @param xoff X offset of the region to copy in this Allocation
1660     * @param yoff Y offset of the region to copy in this Allocation
1661     * @param w Width of the region to copy
1662     * @param h Height of the region to copy
1663     * @param array Dest Array to be copied into
1664     */
1665    public void copy2DRangeTo(int xoff, int yoff, int w, int h, int[] data) {
1666        validateIsInt32();
1667        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
1668                               Element.DataType.SIGNED_32, data.length);
1669    }
1670
1671    /**
1672     * @hide
1673     * Copy from a rectangular region in this Allocation into an array.
1674     *
1675     * @param xoff X offset of the region to copy in this Allocation
1676     * @param yoff Y offset of the region to copy in this Allocation
1677     * @param w Width of the region to copy
1678     * @param h Height of the region to copy
1679     * @param array Dest Array to be copied into
1680     */
1681    public void copy2DRangeTo(int xoff, int yoff, int w, int h, float[] data) {
1682        validateIsFloat32();
1683        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
1684                               Element.DataType.FLOAT_32, data.length);
1685    }
1686
1687
1688    /**
1689     * @hide
1690     *
1691     */
1692    /*
1693    private void copy3DRangeToUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
1694                                        Object array, Element.DataType dt, int arrayLen) {
1695        mRS.validate();
1696        validate3DRange(xoff, yoff, zoff, w, h, d);
1697        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
1698        // AutoPadding for Vec3 Element
1699        boolean usePadding = false;
1700        int sizeBytes = arrayLen * dt.mSize;
1701        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
1702            if (dataSize / 4 * 3 > sizeBytes) {
1703                throw new RSIllegalArgumentException("Array too small for allocation type.");
1704            }
1705            usePadding = true;
1706            sizeBytes = dataSize;
1707        } else {
1708            if (dataSize > sizeBytes) {
1709                throw new RSIllegalArgumentException("Array too small for allocation type.");
1710            }
1711        }
1712        mRS.nAllocationRead3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
1713                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
1714    }
1715    */
1716
1717    /**
1718     * @hide
1719     * Copy from a rectangular region in this Allocation into an array.
1720     *
1721     * @param xoff X offset of the region to copy in this Allocation
1722     * @param yoff Y offset of the region to copy in this Allocation
1723     * @param zoff Z offset of the region to copy in this Allocation
1724     * @param w Width of the region to copy
1725     * @param h Height of the region to copy
1726     * @param d Depth of the region to copy
1727     * @param array Dest Array to be copied into
1728     */
1729    /*
1730    public void copy3DRangeTo(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
1731        copy3DRangeToUnchecked(xoff, yoff, zoff, w, h, d, array,
1732                                 validateObjectIsPrimitiveArray(array, true),
1733                                 java.lang.reflect.Array.getLength(array));
1734    }
1735    */
1736
1737    // creation
1738
1739    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
1740    static {
1741        mBitmapOptions.inScaled = false;
1742    }
1743
1744    /**
1745     * Creates a new Allocation with the given {@link
1746     * android.support.v8.renderscript.Type}, mipmap flag, and usage flags.
1747     *
1748     * @param type RenderScript type describing data layout
1749     * @param mips specifies desired mipmap behaviour for the
1750     *             allocation
1751     * @param usage bit field specifying how the Allocation is
1752     *              utilized
1753     */
1754    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
1755        rs.validate();
1756        if (type.getID(rs) == 0) {
1757            throw new RSInvalidStateException("Bad Type");
1758        }
1759
1760        if(!rs.usingIO() && (usage & (USAGE_IO_INPUT | USAGE_IO_INPUT)) != 0) {
1761            throw new RSRuntimeException("USAGE_IO not supported, Allocation creation failed.");
1762        }
1763
1764        long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
1765        if (id == 0) {
1766            throw new RSRuntimeException("Allocation creation failed.");
1767        }
1768        return new Allocation(id, rs, type, usage);
1769    }
1770
1771    /**
1772     * Creates an Allocation with the size specified by the type and no mipmaps
1773     * generated by default
1774     *
1775     * @param rs Context to which the allocation will belong.
1776     * @param type renderscript type describing data layout
1777     * @param usage bit field specifying how the allocation is
1778     *              utilized
1779     *
1780     * @return allocation
1781     */
1782    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
1783        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
1784    }
1785
1786    /**
1787     * Creates an Allocation for use by scripts with a given {@link
1788     * android.support.v8.renderscript.Type} and no mipmaps
1789     *
1790     * @param rs Context to which the Allocation will belong.
1791     * @param type RenderScript Type describing data layout
1792     *
1793     * @return allocation
1794     */
1795    static public Allocation createTyped(RenderScript rs, Type type) {
1796        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
1797    }
1798
1799    /**
1800     * Creates an Allocation with a specified number of given elements
1801     *
1802     * @param rs Context to which the Allocation will belong.
1803     * @param e Element to use in the Allocation
1804     * @param count the number of Elements in the Allocation
1805     * @param usage bit field specifying how the Allocation is
1806     *              utilized
1807     *
1808     * @return allocation
1809     */
1810    static public Allocation createSized(RenderScript rs, Element e,
1811                                         int count, int usage) {
1812        rs.validate();
1813        Type.Builder b = new Type.Builder(rs, e);
1814        b.setX(count);
1815        Type t = b.create();
1816
1817        long id = rs.nAllocationCreateTyped(t.getID(rs), MipmapControl.MIPMAP_NONE.mID, usage, 0);
1818        if (id == 0) {
1819            throw new RSRuntimeException("Allocation creation failed.");
1820        }
1821        return new Allocation(id, rs, t, usage);
1822    }
1823
1824    /**
1825     * Creates an Allocation with a specified number of given elements
1826     *
1827     * @param rs Context to which the Allocation will belong.
1828     * @param e Element to use in the Allocation
1829     * @param count the number of Elements in the Allocation
1830     *
1831     * @return allocation
1832     */
1833    static public Allocation createSized(RenderScript rs, Element e, int count) {
1834        return createSized(rs, e, count, USAGE_SCRIPT);
1835    }
1836
1837    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
1838        final Bitmap.Config bc = b.getConfig();
1839        if (bc == Bitmap.Config.ALPHA_8) {
1840            return Element.A_8(rs);
1841        }
1842        if (bc == Bitmap.Config.ARGB_4444) {
1843            return Element.RGBA_4444(rs);
1844        }
1845        if (bc == Bitmap.Config.ARGB_8888) {
1846            return Element.RGBA_8888(rs);
1847        }
1848        if (bc == Bitmap.Config.RGB_565) {
1849            return Element.RGB_565(rs);
1850        }
1851        throw new RSInvalidStateException("Bad bitmap type: " + bc);
1852    }
1853
1854    static Type typeFromBitmap(RenderScript rs, Bitmap b,
1855                                       MipmapControl mip) {
1856        Element e = elementFromBitmap(rs, b);
1857        Type.Builder tb = new Type.Builder(rs, e);
1858        tb.setX(b.getWidth());
1859        tb.setY(b.getHeight());
1860        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
1861        return tb.create();
1862    }
1863
1864    /**
1865     * Creates an Allocation from a {@link android.graphics.Bitmap}.
1866     *
1867     * @param rs Context to which the allocation will belong.
1868     * @param b Bitmap source for the allocation data
1869     * @param mips specifies desired mipmap behaviour for the
1870     *             allocation
1871     * @param usage bit field specifying how the allocation is
1872     *              utilized
1873     *
1874     * @return Allocation containing bitmap data
1875     *
1876     */
1877    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
1878                                              MipmapControl mips,
1879                                              int usage) {
1880        rs.validate();
1881
1882        // WAR undocumented color formats
1883        if (b.getConfig() == null) {
1884            if ((usage & USAGE_SHARED) != 0) {
1885                throw new RSIllegalArgumentException("USAGE_SHARED cannot be used with a Bitmap that has a null config.");
1886            }
1887            Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
1888            Canvas c = new Canvas(newBitmap);
1889            c.drawBitmap(b, 0, 0, null);
1890            return createFromBitmap(rs, newBitmap, mips, usage);
1891        }
1892
1893        Type t = typeFromBitmap(rs, b, mips);
1894
1895        // enable optimized bitmap path only with no mipmap and script-only usage
1896        if (mips == MipmapControl.MIPMAP_NONE &&
1897            t.getElement().isCompatible(Element.RGBA_8888(rs)) &&
1898            usage == (USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE)) {
1899            long id = rs.nAllocationCreateBitmapBackedAllocation(t.getID(rs), mips.mID, b, usage);
1900            if (id == 0) {
1901                throw new RSRuntimeException("Load failed.");
1902            }
1903
1904            // keep a reference to the Bitmap around to prevent GC
1905            Allocation alloc = new Allocation(id, rs, t, usage);
1906            alloc.setBitmap(b);
1907            return alloc;
1908        }
1909
1910
1911        long id = rs.nAllocationCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
1912        if (id == 0) {
1913            throw new RSRuntimeException("Load failed.");
1914        }
1915        return new Allocation(id, rs, t, usage);
1916    }
1917
1918    /**
1919     * Associate a {@link android.view.Surface} with this Allocation. This
1920     * operation is only valid for Allocations with {@link #USAGE_IO_OUTPUT}.
1921     *
1922     * @param sur Surface to associate with allocation
1923     */
1924    public void setSurface(Surface sur) {
1925        mRS.validate();
1926        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
1927            throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
1928        }
1929
1930        mRS.nAllocationSetSurface(getID(mRS), sur);
1931    }
1932
1933    /**
1934     * Creates an Allocation from a {@link android.graphics.Bitmap}.
1935     *
1936     * <p>This Allocation will be created with {@link #USAGE_SHARED}, and
1937     * {@link #USAGE_SCRIPT}.</p>
1938     *
1939     * @param rs Context to which the allocation will belong.
1940     * @param b bitmap source for the allocation data
1941     *
1942     * @return Allocation containing bitmap data
1943     *
1944     */
1945    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
1946        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
1947                                USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
1948    }
1949
1950    /**
1951     * Creates a cubemap Allocation from a {@link android.graphics.Bitmap}
1952     * containing the horizontal list of cube faces. Each face must be a square,
1953     * have the same size as all other faces, and have a width that is a power
1954     * of 2.
1955     *
1956     * @param rs Context to which the allocation will belong.
1957     * @param b Bitmap with cubemap faces layed out in the following
1958     *          format: right, left, top, bottom, front, back
1959     * @param mips specifies desired mipmap behaviour for the cubemap
1960     * @param usage bit field specifying how the cubemap is utilized
1961     *
1962     * @return allocation containing cubemap data
1963     *
1964     */
1965    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
1966                                                     MipmapControl mips,
1967                                                     int usage) {
1968        rs.validate();
1969
1970        int height = b.getHeight();
1971        int width = b.getWidth();
1972
1973        if (width % 6 != 0) {
1974            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
1975        }
1976        if (width / 6 != height) {
1977            throw new RSIllegalArgumentException("Only square cube map faces supported");
1978        }
1979        boolean isPow2 = (height & (height - 1)) == 0;
1980        if (!isPow2) {
1981            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
1982        }
1983
1984        Element e = elementFromBitmap(rs, b);
1985        Type.Builder tb = new Type.Builder(rs, e);
1986        tb.setX(height);
1987        tb.setY(height);
1988        tb.setFaces(true);
1989        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
1990        Type t = tb.create();
1991
1992        long id = rs.nAllocationCubeCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
1993        if(id == 0) {
1994            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
1995        }
1996        return new Allocation(id, rs, t, usage);
1997    }
1998
1999    /**
2000     * Creates a non-mipmapped cubemap Allocation for use as a graphics texture
2001     * from a {@link android.graphics.Bitmap} containing the horizontal list of
2002     * cube faces. Each face must be a square, have the same size as all other
2003     * faces, and have a width that is a power of 2.
2004     *
2005     * @param rs Context to which the allocation will belong.
2006     * @param b bitmap with cubemap faces layed out in the following
2007     *          format: right, left, top, bottom, front, back
2008     *
2009     * @return allocation containing cubemap data
2010     *
2011     */
2012    static public Allocation createCubemapFromBitmap(RenderScript rs,
2013                                                     Bitmap b) {
2014        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
2015                                       USAGE_GRAPHICS_TEXTURE);
2016    }
2017
2018    /**
2019     * Creates a cubemap Allocation from 6 {@link android.graphics.Bitmap}
2020     * objects containing the cube faces. Each face must be a square, have the
2021     * same size as all other faces, and have a width that is a power of 2.
2022     *
2023     * @param rs Context to which the allocation will belong.
2024     * @param xpos cubemap face in the positive x direction
2025     * @param xneg cubemap face in the negative x direction
2026     * @param ypos cubemap face in the positive y direction
2027     * @param yneg cubemap face in the negative y direction
2028     * @param zpos cubemap face in the positive z direction
2029     * @param zneg cubemap face in the negative z direction
2030     * @param mips specifies desired mipmap behaviour for the cubemap
2031     * @param usage bit field specifying how the cubemap is utilized
2032     *
2033     * @return allocation containing cubemap data
2034     *
2035     */
2036    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
2037                                                        Bitmap xpos,
2038                                                        Bitmap xneg,
2039                                                        Bitmap ypos,
2040                                                        Bitmap yneg,
2041                                                        Bitmap zpos,
2042                                                        Bitmap zneg,
2043                                                        MipmapControl mips,
2044                                                        int usage) {
2045        /*
2046        int height = xpos.getHeight();
2047        if (xpos.getWidth() != height ||
2048            xneg.getWidth() != height || xneg.getHeight() != height ||
2049            ypos.getWidth() != height || ypos.getHeight() != height ||
2050            yneg.getWidth() != height || yneg.getHeight() != height ||
2051            zpos.getWidth() != height || zpos.getHeight() != height ||
2052            zneg.getWidth() != height || zneg.getHeight() != height) {
2053            throw new RSIllegalArgumentException("Only square cube map faces supported");
2054        }
2055        boolean isPow2 = (height & (height - 1)) == 0;
2056        if (!isPow2) {
2057            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
2058        }
2059
2060        Element e = elementFromBitmap(rs, xpos);
2061        Type.Builder tb = new Type.Builder(rs, e);
2062        tb.setX(height);
2063        tb.setY(height);
2064        tb.setFaces(true);
2065        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
2066        Type t = tb.create();
2067        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
2068
2069        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
2070        adapter.setFace(Type.CubemapFace.POSITIVE_X);
2071        adapter.copyFrom(xpos);
2072        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
2073        adapter.copyFrom(xneg);
2074        adapter.setFace(Type.CubemapFace.POSITIVE_Y);
2075        adapter.copyFrom(ypos);
2076        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
2077        adapter.copyFrom(yneg);
2078        adapter.setFace(Type.CubemapFace.POSITIVE_Z);
2079        adapter.copyFrom(zpos);
2080        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
2081        adapter.copyFrom(zneg);
2082
2083        return cubemap;
2084        */
2085        return null;
2086    }
2087
2088    /**
2089     * Creates a non-mipmapped cubemap Allocation for use as a sampler input
2090     * from 6 {@link android.graphics.Bitmap} objects containing the cube
2091     * faces. Each face must be a square, have the same size as all other faces,
2092     * and have a width that is a power of 2.
2093     *
2094     * @param rs Context to which the allocation will belong.
2095     * @param xpos cubemap face in the positive x direction
2096     * @param xneg cubemap face in the negative x direction
2097     * @param ypos cubemap face in the positive y direction
2098     * @param yneg cubemap face in the negative y direction
2099     * @param zpos cubemap face in the positive z direction
2100     * @param zneg cubemap face in the negative z direction
2101     *
2102     * @return allocation containing cubemap data
2103     *
2104     */
2105    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
2106                                                        Bitmap xpos,
2107                                                        Bitmap xneg,
2108                                                        Bitmap ypos,
2109                                                        Bitmap yneg,
2110                                                        Bitmap zpos,
2111                                                        Bitmap zneg) {
2112        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
2113                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
2114                                          USAGE_GRAPHICS_TEXTURE);
2115    }
2116
2117    /**
2118     * Creates an Allocation from the Bitmap referenced
2119     * by resource ID.
2120     *
2121     * @param rs Context to which the allocation will belong.
2122     * @param res application resources
2123     * @param id resource id to load the data from
2124     * @param mips specifies desired mipmap behaviour for the
2125     *             allocation
2126     * @param usage bit field specifying how the allocation is
2127     *              utilized
2128     *
2129     * @return Allocation containing resource data
2130     *
2131     */
2132    static public Allocation createFromBitmapResource(RenderScript rs,
2133                                                      Resources res,
2134                                                      int id,
2135                                                      MipmapControl mips,
2136                                                      int usage) {
2137
2138        rs.validate();
2139        if ((usage & (USAGE_SHARED | USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) {
2140            throw new RSIllegalArgumentException("Unsupported usage specified.");
2141        }
2142        Bitmap b = BitmapFactory.decodeResource(res, id);
2143        Allocation alloc = createFromBitmap(rs, b, mips, usage);
2144        b.recycle();
2145        return alloc;
2146    }
2147
2148    /**
2149     * Creates a non-mipmapped Allocation to use as a graphics texture from the
2150     * {@link android.graphics.Bitmap} referenced by resource ID.
2151     *
2152     * <p>This allocation will be created with {@link #USAGE_SCRIPT} and
2153     * {@link #USAGE_GRAPHICS_TEXTURE}.</p>
2154     *
2155     * @param rs Context to which the allocation will belong.
2156     * @param res application resources
2157     * @param id resource id to load the data from
2158     *
2159     * @return Allocation containing resource data
2160     *
2161     */
2162    static public Allocation createFromBitmapResource(RenderScript rs,
2163                                                      Resources res,
2164                                                      int id) {
2165        return createFromBitmapResource(rs, res, id,
2166                                        MipmapControl.MIPMAP_NONE,
2167                                        USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
2168    }
2169
2170    /**
2171     * Creates an Allocation containing string data encoded in UTF-8 format.
2172     *
2173     * @param rs Context to which the allocation will belong.
2174     * @param str string to create the allocation from
2175     * @param usage bit field specifying how the allocaiton is
2176     *              utilized
2177     *
2178     */
2179    static public Allocation createFromString(RenderScript rs,
2180                                              String str,
2181                                              int usage) {
2182        rs.validate();
2183        byte[] allocArray = null;
2184        try {
2185            allocArray = str.getBytes("UTF-8");
2186            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
2187            alloc.copyFrom(allocArray);
2188            return alloc;
2189        }
2190        catch (Exception e) {
2191            throw new RSRuntimeException("Could not convert string to utf-8.");
2192        }
2193    }
2194
2195    /**
2196     * Frees any native resources associated with this object.  The
2197     * primary use is to force immediate cleanup of resources when it is
2198     * believed the GC will not respond quickly enough.
2199     * For USAGE_IO_OUTPUT, destroy() implies setSurface(null).
2200     */
2201    @Override
2202    public void destroy() {
2203        if (mIncCompatAllocation != 0) {
2204            boolean shouldDestroy = false;
2205            synchronized(this) {
2206                if (!mIncAllocDestroyed) {
2207                    shouldDestroy = true;
2208                    mIncAllocDestroyed = true;
2209                }
2210            }
2211
2212            if (shouldDestroy) {
2213                // must include nObjDestroy in the critical section
2214                ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
2215                rlock.lock();
2216                if(mRS.isAlive()) {
2217                    mRS.nIncObjDestroy(mIncCompatAllocation);
2218                }
2219                rlock.unlock();
2220                mIncCompatAllocation = 0;
2221            }
2222        }
2223        if ((mUsage & (USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) {
2224            setSurface(null);
2225        }
2226        super.destroy();
2227    }
2228
2229}
2230
2231