Allocation.java revision 6a9c942955a1a316f35f71c6f4088a6fb70d187c
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 android.content.res.Resources;
22import android.content.res.AssetManager;
23import android.graphics.Bitmap;
24import android.graphics.BitmapFactory;
25import android.graphics.Canvas;
26import android.view.Surface;
27import android.util.Log;
28import android.util.TypedValue;
29
30/**
31 * <p> This class provides the primary method through which data is passed to
32 * and from RenderScript kernels.  An Allocation provides the backing store for
33 * a given {@link android.support.v8.renderscript.Type}.  </p>
34 *
35 * <p>An Allocation also contains a set of usage flags that denote how the
36 * Allocation could be used. For example, an Allocation may have usage flags
37 * specifying that it can be used from a script as well as input to a {@link
38 * android.support.v8.renderscript.Sampler}. A developer must synchronize
39 * across these different usages using
40 * {@link android.support.v8.renderscript.Allocation#syncAll} in
41 * order to ensure that different users of the Allocation have a consistent view
42 * of memory. For example, in the case where an Allocation is used as the output
43 * of one kernel and as Sampler input in a later kernel, a developer must call
44 * {@link #syncAll syncAll(Allocation.USAGE_SCRIPT)} prior to launching the
45 * second kernel to ensure correctness.
46 *
47 * <p>An Allocation can be populated with the {@link #copyFrom} routines. For
48 * more complex Element types, the {@link #copyFromUnchecked} methods can be
49 * used to copy from byte arrays or similar constructs.</p>
50 *
51 * <div class="special reference">
52 * <h3>Developer Guides</h3>
53 * <p>For more information about creating an application that uses
54 * RenderScript, read the
55 * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
56 * developer guide.</p>
57 * </div>
58 **/
59public class Allocation extends BaseObj {
60    Type mType;
61    Bitmap mBitmap;
62    int mUsage;
63    Allocation mAdaptedAllocation;
64    int mSize;
65
66    boolean mConstrainedLOD;
67    boolean mConstrainedFace;
68    boolean mConstrainedY;
69    boolean mConstrainedZ;
70    boolean mReadAllowed = true;
71    boolean mWriteAllowed = true;
72    int mSelectedY;
73    int mSelectedZ;
74    int mSelectedLOD;
75    Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
76
77    int mCurrentDimX;
78    int mCurrentDimY;
79    int mCurrentDimZ;
80    int mCurrentCount;
81
82    /**
83     * The usage of the Allocation.  These signal to RenderScript where to place
84     * the Allocation in memory.
85     *
86     */
87
88    /**
89     * The Allocation will be bound to and accessed by scripts.
90     */
91    public static final int USAGE_SCRIPT = 0x0001;
92
93    /**
94     * The Allocation will be used as a texture source by one or more graphics
95     * programs.
96     *
97     */
98    public static final int USAGE_GRAPHICS_TEXTURE = 0x0002;
99
100    /**
101     * The Allocation will be used as a {@link android.graphics.SurfaceTexture}
102     * consumer.  This usage will cause the Allocation to be created as
103     * read-only.
104     *
105     */
106    public static final int USAGE_IO_INPUT = 0x0020;
107
108    /**
109     * The Allocation will be used as a {@link android.graphics.SurfaceTexture}
110     * producer.  The dimensions and format of the {@link
111     * android.graphics.SurfaceTexture} will be forced to those of the
112     * Allocation.
113     *
114     */
115    public static final int USAGE_IO_OUTPUT = 0x0040;
116
117    /**
118     * The Allocation's backing store will be inherited from another object
119     * (usually a {@link android.graphics.Bitmap}); copying to or from the
120     * original source Bitmap will cause a synchronization rather than a full
121     * copy.  {@link #syncAll} may also be used to synchronize the Allocation
122     * and the source Bitmap.
123     *
124     * <p>This is set by default for allocations created with {@link
125     * #createFromBitmap} in API version 18 and higher.</p>
126     *
127     */
128    public static final int USAGE_SHARED = 0x0080;
129
130    /**
131     * Controls mipmap behavior when using the bitmap creation and update
132     * functions.
133     */
134    public enum MipmapControl {
135        /**
136         * No mipmaps will be generated and the type generated from the incoming
137         * bitmap will not contain additional LODs.
138         */
139        MIPMAP_NONE(0),
140
141        /**
142         * A full mipmap chain will be created in script memory.  The Type of
143         * the Allocation will contain a full mipmap chain.  On upload, the full
144         * chain will be transferred.
145         */
146        MIPMAP_FULL(1),
147
148        /**
149         * The Type of the Allocation will be the same as MIPMAP_NONE.  It will
150         * not contain mipmaps.  On upload, the allocation data will contain a
151         * full mipmap chain generated from the top level in script memory.
152         */
153        MIPMAP_ON_SYNC_TO_TEXTURE(2);
154
155        int mID;
156        MipmapControl(int id) {
157            mID = id;
158        }
159    }
160
161
162    private long getIDSafe() {
163        if (mAdaptedAllocation != null) {
164            return mAdaptedAllocation.getID(mRS);
165        }
166        return getID(mRS);
167    }
168
169
170   /**
171     * Get the {@link android.support.v8.renderscript.Element} of the {@link
172     * android.support.v8.renderscript.Type} of the Allocation.
173     *
174     * @return Element
175     *
176     */
177    public Element getElement() {
178        return mType.getElement();
179    }
180
181    /**
182     * Get the usage flags of the Allocation.
183     *
184     * @return usage this Allocation's set of the USAGE_* flags OR'd together
185     *
186     */
187    public int getUsage() {
188        return mUsage;
189    }
190
191    /**
192     * Get the size of the Allocation in bytes.
193     *
194     * @return size of the Allocation in bytes.
195     *
196     */
197    public int getBytesSize() {
198        if (mType.mDimYuv != 0) {
199            return (int)Math.ceil(mType.getCount() * mType.getElement().getBytesSize() * 1.5);
200        }
201        return mType.getCount() * mType.getElement().getBytesSize();
202    }
203
204    private void updateCacheInfo(Type t) {
205        mCurrentDimX = t.getX();
206        mCurrentDimY = t.getY();
207        mCurrentDimZ = t.getZ();
208        mCurrentCount = mCurrentDimX;
209        if (mCurrentDimY > 1) {
210            mCurrentCount *= mCurrentDimY;
211        }
212        if (mCurrentDimZ > 1) {
213            mCurrentCount *= mCurrentDimZ;
214        }
215    }
216
217    private void setBitmap(Bitmap b) {
218        mBitmap = b;
219    }
220
221    Allocation(long id, RenderScript rs, Type t, int usage) {
222        super(id, rs);
223        if ((usage & ~(USAGE_SCRIPT |
224                       USAGE_GRAPHICS_TEXTURE |
225                       USAGE_IO_INPUT |
226                       USAGE_IO_OUTPUT |
227                       USAGE_SHARED)) != 0) {
228            throw new RSIllegalArgumentException("Unknown usage specified.");
229        }
230
231        if ((usage & USAGE_IO_INPUT) != 0) {
232            mWriteAllowed = false;
233
234            if ((usage & ~(USAGE_IO_INPUT |
235                           USAGE_GRAPHICS_TEXTURE |
236                           USAGE_SCRIPT)) != 0) {
237                throw new RSIllegalArgumentException("Invalid usage combination.");
238            }
239        }
240
241        mType = t;
242        mUsage = usage;
243        mSize = mType.getCount() * mType.getElement().getBytesSize();
244
245        if (t != null) {
246            updateCacheInfo(t);
247        }
248        if (RenderScript.sUseGCHooks == true) {
249            try {
250                RenderScript.registerNativeAllocation.invoke(RenderScript.sRuntime, mSize);
251            } catch (Exception e) {
252                Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
253                throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
254            }
255        }
256    }
257
258    protected void finalize() throws Throwable {
259        if (RenderScript.sUseGCHooks == true) {
260            RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
261        }
262        super.finalize();
263    }
264
265    private void validateIsInt64() {
266        if ((mType.mElement.mType == Element.DataType.SIGNED_64) ||
267            (mType.mElement.mType == Element.DataType.UNSIGNED_64)) {
268            return;
269        }
270        throw new RSIllegalArgumentException(
271            "64 bit integer source does not match allocation type " + mType.mElement.mType);
272    }
273
274    private void validateIsInt32() {
275        if ((mType.mElement.mType == Element.DataType.SIGNED_32) ||
276            (mType.mElement.mType == Element.DataType.UNSIGNED_32)) {
277            return;
278        }
279        throw new RSIllegalArgumentException(
280            "32 bit integer source does not match allocation type " + mType.mElement.mType);
281    }
282
283    private void validateIsInt16() {
284        if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
285            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
286            return;
287        }
288        throw new RSIllegalArgumentException(
289            "16 bit integer source does not match allocation type " + mType.mElement.mType);
290    }
291
292    private void validateIsInt8() {
293        if ((mType.mElement.mType == Element.DataType.SIGNED_8) ||
294            (mType.mElement.mType == Element.DataType.UNSIGNED_8)) {
295            return;
296        }
297        throw new RSIllegalArgumentException(
298            "8 bit integer source does not match allocation type " + mType.mElement.mType);
299    }
300
301    private void validateIsFloat32() {
302        if (mType.mElement.mType == Element.DataType.FLOAT_32) {
303            return;
304        }
305        throw new RSIllegalArgumentException(
306            "32 bit float source does not match allocation type " + mType.mElement.mType);
307    }
308
309    private void validateIsObject() {
310        if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) ||
311            (mType.mElement.mType == Element.DataType.RS_TYPE) ||
312            (mType.mElement.mType == Element.DataType.RS_ALLOCATION) ||
313            (mType.mElement.mType == Element.DataType.RS_SAMPLER) ||
314            (mType.mElement.mType == Element.DataType.RS_SCRIPT)) {
315            return;
316        }
317        throw new RSIllegalArgumentException(
318            "Object source does not match allocation type " + mType.mElement.mType);
319    }
320
321    /**
322     * Get the {@link android.support.v8.renderscript.Type} of the Allocation.
323     *
324     * @return Type
325     *
326     */
327    public Type getType() {
328        return mType;
329    }
330
331    /**
332     * Propagate changes from one usage of the Allocation to the
333     * other usages of the Allocation.
334     *
335     */
336    public void syncAll(int srcLocation) {
337        switch (srcLocation) {
338        case USAGE_SCRIPT:
339        case USAGE_GRAPHICS_TEXTURE:
340            break;
341        default:
342            throw new RSIllegalArgumentException("Source must be exactly one usage type.");
343        }
344        mRS.validate();
345        mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
346    }
347
348    /**
349     * Send a buffer to the output stream.  The contents of the Allocation will
350     * be undefined after this operation. This operation is only valid if {@link
351     * #USAGE_IO_OUTPUT} is set on the Allocation.
352     *
353     *
354     */
355    public void ioSend() {
356        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
357            throw new RSIllegalArgumentException(
358                "Can only send buffer if IO_OUTPUT usage specified.");
359        }
360        mRS.validate();
361        mRS.nAllocationIoSend(getID(mRS));
362    }
363
364    /**
365     * Delete once code is updated.
366     * @hide
367     */
368    public void ioSendOutput() {
369        ioSend();
370    }
371
372    /**
373     * Receive the latest input into the Allocation. This operation
374     * is only valid if {@link #USAGE_IO_INPUT} is set on the Allocation.
375     *
376     */
377    public void ioReceive() {
378        if ((mUsage & USAGE_IO_INPUT) == 0) {
379            throw new RSIllegalArgumentException(
380                "Can only receive if IO_INPUT usage specified.");
381        }
382        mRS.validate();
383        mRS.nAllocationIoReceive(getID(mRS));
384    }
385
386    /**
387     * Copy an array of RS objects to the Allocation.
388     *
389     * @param d Source array.
390     */
391    public void copyFrom(BaseObj[] d) {
392        mRS.validate();
393        validateIsObject();
394        if (d.length != mCurrentCount) {
395            throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
396                                                 mCurrentCount + ", array length = " + d.length);
397        }
398
399        if (RenderScript.sPointerSize == 8) {
400            long i[] = new long[d.length * 4];
401            for (int ct=0; ct < d.length; ct++) {
402                i[ct * 4] = d[ct].getID(mRS);
403            }
404            copy1DRangeFromUnchecked(0, mCurrentCount, i);
405        } else {
406            int i[] = new int[d.length];
407            for (int ct=0; ct < d.length; ct++) {
408                i[ct] = (int)d[ct].getID(mRS);
409            }
410            copy1DRangeFromUnchecked(0, mCurrentCount, i);
411        }
412    }
413
414    private void validateBitmapFormat(Bitmap b) {
415        Bitmap.Config bc = b.getConfig();
416        if (bc == null) {
417            throw new RSIllegalArgumentException("Bitmap has an unsupported format for this operation");
418        }
419        switch (bc) {
420        case ALPHA_8:
421            if (mType.getElement().mKind != Element.DataKind.PIXEL_A) {
422                throw new RSIllegalArgumentException("Allocation kind is " +
423                                                     mType.getElement().mKind + ", type " +
424                                                     mType.getElement().mType +
425                                                     " of " + mType.getElement().getBytesSize() +
426                                                     " bytes, passed bitmap was " + bc);
427            }
428            break;
429        case ARGB_8888:
430            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
431                (mType.getElement().getBytesSize() != 4)) {
432                throw new RSIllegalArgumentException("Allocation kind is " +
433                                                     mType.getElement().mKind + ", type " +
434                                                     mType.getElement().mType +
435                                                     " of " + mType.getElement().getBytesSize() +
436                                                     " bytes, passed bitmap was " + bc);
437            }
438            break;
439        case RGB_565:
440            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) ||
441                (mType.getElement().getBytesSize() != 2)) {
442                throw new RSIllegalArgumentException("Allocation kind is " +
443                                                     mType.getElement().mKind + ", type " +
444                                                     mType.getElement().mType +
445                                                     " of " + mType.getElement().getBytesSize() +
446                                                     " bytes, passed bitmap was " + bc);
447            }
448            break;
449        case ARGB_4444:
450            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
451                (mType.getElement().getBytesSize() != 2)) {
452                throw new RSIllegalArgumentException("Allocation kind is " +
453                                                     mType.getElement().mKind + ", type " +
454                                                     mType.getElement().mType +
455                                                     " of " + mType.getElement().getBytesSize() +
456                                                     " bytes, passed bitmap was " + bc);
457            }
458            break;
459
460        }
461    }
462
463    private void validateBitmapSize(Bitmap b) {
464        if((mCurrentDimX != b.getWidth()) || (mCurrentDimY != b.getHeight())) {
465            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
466        }
467    }
468
469    /**
470     * Copy into this Allocation from an array. This method does not guarantee
471     * that the Allocation is compatible with the input buffer; it copies memory
472     * without reinterpretation.
473     *
474     * @param d the source data array
475     */
476    public void copyFromUnchecked(int[] d) {
477        mRS.validate();
478        if (mCurrentDimZ > 0) {
479            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
480        } else if (mCurrentDimY > 0) {
481            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
482        } else {
483            copy1DRangeFromUnchecked(0, mCurrentCount, d);
484        }
485    }
486    /**
487     * Copy into this Allocation from an array. This method does not guarantee
488     * that the Allocation is compatible with the input buffer; it copies memory
489     * without reinterpretation.
490     *
491     * @param d the source data array
492     */
493    public void copyFromUnchecked(short[] d) {
494        mRS.validate();
495        if (mCurrentDimZ > 0) {
496            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
497        } else if (mCurrentDimY > 0) {
498            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
499        } else {
500            copy1DRangeFromUnchecked(0, mCurrentCount, d);
501        }
502    }
503    /**
504     * Copy into this Allocation from an array. This method does not guarantee
505     * that the Allocation is compatible with the input buffer; it copies memory
506     * without reinterpretation.
507     *
508     * @param d the source data array
509     */
510    public void copyFromUnchecked(byte[] d) {
511        mRS.validate();
512        if (mCurrentDimZ > 0) {
513            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
514        } else if (mCurrentDimY > 0) {
515            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
516        } else {
517            copy1DRangeFromUnchecked(0, mCurrentCount, d);
518        }
519    }
520    /**
521     * Copy into this Allocation from an array. This method does not guarantee
522     * that the Allocation is compatible with the input buffer; it copies memory
523     * without reinterpretation.
524     *
525     * @param d the source data array
526     */
527    public void copyFromUnchecked(float[] d) {
528        mRS.validate();
529        if (mCurrentDimZ > 0) {
530            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
531        } else if (mCurrentDimY > 0) {
532            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
533        } else {
534            copy1DRangeFromUnchecked(0, mCurrentCount, d);
535        }
536    }
537
538    /**
539     * Copy into this Allocation from an array.  This variant is type checked
540     * and will generate exceptions if the Allocation's {@link
541     * android.support.v8.renderscript.Element} is not a 32 bit integer type.
542     *
543     * @param d the source data array
544     */
545    public void copyFrom(int[] d) {
546        mRS.validate();
547        if (mCurrentDimZ > 0) {
548            copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
549        } else if (mCurrentDimY > 0) {
550            copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
551        } else {
552            copy1DRangeFrom(0, mCurrentCount, d);
553        }
554    }
555
556    /**
557     * Copy into this Allocation from an array.  This variant is type checked
558     * and will generate exceptions if the Allocation's {@link
559     * android.support.v8.renderscript.Element} is not a 16 bit integer type.
560     *
561     * @param d the source data array
562     */
563    public void copyFrom(short[] d) {
564        mRS.validate();
565        if (mCurrentDimZ > 0) {
566            copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
567        } else if (mCurrentDimY > 0) {
568            copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
569        } else {
570            copy1DRangeFrom(0, mCurrentCount, d);
571        }
572    }
573
574    /**
575     * Copy into this Allocation from an array.  This variant is type checked
576     * and will generate exceptions if the Allocation's {@link
577     * android.support.v8.renderscript.Element} is not an 8 bit integer type.
578     *
579     * @param d the source data array
580     */
581    public void copyFrom(byte[] d) {
582        mRS.validate();
583        if (mCurrentDimZ > 0) {
584            copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
585        } else if (mCurrentDimY > 0) {
586            copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
587        } else {
588            copy1DRangeFrom(0, mCurrentCount, d);
589        }
590    }
591
592    /**
593     * Copy into this Allocation from an array.  This variant is type checked
594     * and will generate exceptions if the Allocation's {@link
595     * android.support.v8.renderscript.Element} is not a 32 bit float type.
596     *
597     * @param d the source data array
598     */
599    public void copyFrom(float[] d) {
600        mRS.validate();
601        if (mCurrentDimZ > 0) {
602            copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
603        } else if (mCurrentDimY > 0) {
604            copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
605        } else {
606            copy1DRangeFrom(0, mCurrentCount, d);
607        }
608    }
609
610    /**
611     * Copy into an Allocation from a {@link android.graphics.Bitmap}.  The
612     * height, width, and format of the bitmap must match the existing
613     * allocation.
614     *
615     * <p>If the {@link android.graphics.Bitmap} is the same as the {@link
616     * android.graphics.Bitmap} used to create the Allocation with {@link
617     * #createFromBitmap} and {@link #USAGE_SHARED} is set on the Allocation,
618     * this will synchronize the Allocation with the latest data from the {@link
619     * android.graphics.Bitmap}, potentially avoiding the actual copy.</p>
620     *
621     * @param b the source bitmap
622     */
623    public void copyFrom(Bitmap b) {
624        mRS.validate();
625        if (b.getConfig() == null) {
626            Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
627            Canvas c = new Canvas(newBitmap);
628            c.drawBitmap(b, 0, 0, null);
629            copyFrom(newBitmap);
630            return;
631        }
632        validateBitmapSize(b);
633        validateBitmapFormat(b);
634        mRS.nAllocationCopyFromBitmap(getID(mRS), b);
635    }
636
637    /**
638     * Copy an Allocation from an Allocation.  The types of both allocations
639     * must be identical.
640     *
641     * @param a the source allocation
642     */
643    public void copyFrom(Allocation a) {
644        mRS.validate();
645        if (!mType.equals(a.getType())) {
646            throw new RSIllegalArgumentException("Types of allocations must match.");
647        }
648        copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, a, 0, 0);
649    }
650
651
652    /**
653     * This is only intended to be used by auto-generated code reflected from
654     * the RenderScript script files and should not be used by developers.
655     *
656     * @param xoff
657     * @param fp
658     */
659    public void setFromFieldPacker(int xoff, FieldPacker fp) {
660        mRS.validate();
661        int eSize = mType.mElement.getBytesSize();
662        final byte[] data = fp.getData();
663        int data_length = fp.getPos();
664
665        int count = data_length / eSize;
666        if ((eSize * count) != data_length) {
667            throw new RSIllegalArgumentException("Field packer length " + data_length +
668                                               " not divisible by element size " + eSize + ".");
669        }
670        copy1DRangeFromUnchecked(xoff, count, data);
671    }
672
673    /**
674     * This is only intended to be used by auto-generated code reflected from
675     * the RenderScript script files.
676     *
677     * @param xoff
678     * @param component_number
679     * @param fp
680     */
681    public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
682        mRS.validate();
683        if (component_number >= mType.mElement.mElements.length) {
684            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
685        }
686        if(xoff < 0) {
687            throw new RSIllegalArgumentException("Offset must be >= 0.");
688        }
689
690        final byte[] data = fp.getData();
691        int data_length = fp.getPos();
692        int eSize = mType.mElement.mElements[component_number].getBytesSize();
693        eSize *= mType.mElement.mArraySizes[component_number];
694
695        if (data_length != eSize) {
696            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
697                                               " does not match component size " + eSize + ".");
698        }
699
700        mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD,
701                                     component_number, data, data_length);
702    }
703
704    private void data1DChecks(int off, int count, int len, int dataSize) {
705        mRS.validate();
706        if(off < 0) {
707            throw new RSIllegalArgumentException("Offset must be >= 0.");
708        }
709        if(count < 1) {
710            throw new RSIllegalArgumentException("Count must be >= 1.");
711        }
712        if((off + count) > mCurrentCount) {
713            throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
714                                               ", got " + count + " at offset " + off + ".");
715        }
716        if(len < dataSize) {
717            throw new RSIllegalArgumentException("Array too small for allocation type.");
718        }
719    }
720
721    /**
722     * Generate a mipmap chain. This is only valid if the Type of the Allocation
723     * includes mipmaps.
724     *
725     * <p>This function will generate a complete set of mipmaps from the top
726     * level LOD and place them into the script memory space.</p>
727     *
728     * <p>If the Allocation is also using other memory spaces, a call to {@link
729     * #syncAll syncAll(Allocation.USAGE_SCRIPT)} is required.</p>
730     */
731    public void generateMipmaps() {
732        mRS.nAllocationGenerateMipmaps(getID(mRS));
733    }
734
735    /**
736     * Copy an array into part of this Allocation.  This method does not
737     * guarantee that the Allocation is compatible with the input buffer.
738     *
739     * @param off The offset of the first element to be copied.
740     * @param count The number of elements to be copied.
741     * @param d the source data array
742     */
743    public void copy1DRangeFromUnchecked(int off, int count, long[] d) {
744        int dataSize = mType.mElement.getBytesSize() * count;
745        data1DChecks(off, count, d.length * 8, dataSize);
746        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
747    }
748    /**
749     * Copy an array into part of this Allocation.  This method does not
750     * guarantee that the Allocation is compatible with the input buffer.
751     *
752     * @param off The offset of the first element to be copied.
753     * @param count The number of elements to be copied.
754     * @param d the source data array
755     */
756    public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
757        int dataSize = mType.mElement.getBytesSize() * count;
758        data1DChecks(off, count, d.length * 4, dataSize);
759        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
760    }
761    /**
762     * Copy an array into part of this Allocation.  This method does not
763     * guarantee that the Allocation is compatible with the input buffer.
764     *
765     * @param off The offset of the first element to be copied.
766     * @param count The number of elements to be copied.
767     * @param d the source data array
768     */
769    public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
770        int dataSize = mType.mElement.getBytesSize() * count;
771        data1DChecks(off, count, d.length * 2, dataSize);
772        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
773    }
774    /**
775     * Copy an array into part of this Allocation.  This method does not
776     * guarantee that the Allocation is compatible with the input buffer.
777     *
778     * @param off The offset of the first element to be copied.
779     * @param count The number of elements to be copied.
780     * @param d the source data array
781     */
782    public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
783        int dataSize = mType.mElement.getBytesSize() * count;
784        data1DChecks(off, count, d.length, dataSize);
785        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
786    }
787    /**
788     * Copy an array into part of this Allocation.  This method does not
789     * guarantee that the Allocation is compatible with the input buffer.
790     *
791     * @param off The offset of the first element to be copied.
792     * @param count The number of elements to be copied.
793     * @param d the source data array
794     */
795    public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
796        int dataSize = mType.mElement.getBytesSize() * count;
797        data1DChecks(off, count, d.length * 4, dataSize);
798        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
799    }
800
801    /**
802     * Copy an array into part of this Allocation.  This variant is type checked
803     * and will generate exceptions if the Allocation type is not a 32 bit
804     * integer type.
805     *
806     * @param off The offset of the first element to be copied.
807     * @param count The number of elements to be copied.
808     * @param d the source data array
809     */
810    public void copy1DRangeFrom(int off, int count, long[] d) {
811        validateIsInt64();
812        copy1DRangeFromUnchecked(off, count, d);
813    }
814
815    /**
816     * Copy an array into part of this Allocation.  This variant is type checked
817     * and will generate exceptions if the Allocation type is not a 32 bit
818     * integer type.
819     *
820     * @param off The offset of the first element to be copied.
821     * @param count The number of elements to be copied.
822     * @param d the source data array
823     */
824    public void copy1DRangeFrom(int off, int count, int[] d) {
825        validateIsInt32();
826        copy1DRangeFromUnchecked(off, count, d);
827    }
828
829    /**
830     * Copy an array into part of this Allocation.  This variant is type checked
831     * and will generate exceptions if the Allocation type is not a 16 bit
832     * integer type.
833     *
834     * @param off The offset of the first element to be copied.
835     * @param count The number of elements to be copied.
836     * @param d the source data array
837     */
838    public void copy1DRangeFrom(int off, int count, short[] d) {
839        validateIsInt16();
840        copy1DRangeFromUnchecked(off, count, d);
841    }
842
843    /**
844     * Copy an array into part of this Allocation.  This variant is type checked
845     * and will generate exceptions if the Allocation type is not an 8 bit
846     * integer type.
847     *
848     * @param off The offset of the first element to be copied.
849     * @param count The number of elements to be copied.
850     * @param d the source data array
851     */
852    public void copy1DRangeFrom(int off, int count, byte[] d) {
853        validateIsInt8();
854        copy1DRangeFromUnchecked(off, count, d);
855    }
856
857    /**
858     * Copy an array into part of this Allocation.  This variant is type checked
859     * and will generate exceptions if the Allocation type is not a 32 bit float
860     * type.
861     *
862     * @param off The offset of the first element to be copied.
863     * @param count The number of elements to be copied.
864     * @param d the source data array.
865     */
866    public void copy1DRangeFrom(int off, int count, float[] d) {
867        validateIsFloat32();
868        copy1DRangeFromUnchecked(off, count, d);
869    }
870
871     /**
872     * Copy part of an Allocation into this Allocation.
873     *
874     * @param off The offset of the first element to be copied.
875     * @param count The number of elements to be copied.
876     * @param data the source data allocation.
877     * @param dataOff off The offset of the first element in data to
878     *          be copied.
879     */
880    public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
881        mRS.nAllocationData2D(getIDSafe(), off, 0,
882                              mSelectedLOD, mSelectedFace.mID,
883                              count, 1, data.getID(mRS), dataOff, 0,
884                              data.mSelectedLOD, data.mSelectedFace.mID);
885    }
886
887    private void validate2DRange(int xoff, int yoff, int w, int h) {
888        if (mAdaptedAllocation != null) {
889
890        } else {
891
892            if (xoff < 0 || yoff < 0) {
893                throw new RSIllegalArgumentException("Offset cannot be negative.");
894            }
895            if (h < 0 || w < 0) {
896                throw new RSIllegalArgumentException("Height or width cannot be negative.");
897            }
898            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
899                throw new RSIllegalArgumentException("Updated region larger than allocation.");
900            }
901        }
902    }
903
904    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, byte[] data) {
905        mRS.validate();
906        validate2DRange(xoff, yoff, w, h);
907        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
908                              w, h, data, data.length);
909    }
910
911    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, short[] data) {
912        mRS.validate();
913        validate2DRange(xoff, yoff, w, h);
914        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
915                              w, h, data, data.length * 2);
916    }
917
918    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, long[] data) {
919        mRS.validate();
920        validate2DRange(xoff, yoff, w, h);
921        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
922                              w, h, data, data.length * 8);
923    }
924
925    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, int[] data) {
926        mRS.validate();
927        validate2DRange(xoff, yoff, w, h);
928        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
929                              w, h, data, data.length * 4);
930    }
931
932    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, float[] data) {
933        mRS.validate();
934        validate2DRange(xoff, yoff, w, h);
935        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
936                              w, h, data, data.length * 4);
937    }
938
939
940    /**
941     * Copy from an array into a rectangular region in this Allocation.  The
942     * array is assumed to be tightly packed.
943     *
944     * @param xoff X offset of the region to update in this Allocation
945     * @param yoff Y offset of the region to update in this Allocation
946     * @param w Width of the region to update
947     * @param h Height of the region to update
948     * @param data to be placed into the Allocation
949     */
950    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
951        validateIsInt8();
952        copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
953    }
954
955    /**
956     * Copy from an array into a rectangular region in this Allocation.  The
957     * array is assumed to be tightly packed.
958     *
959     * @param xoff X offset of the region to update in this Allocation
960     * @param yoff Y offset of the region to update in this Allocation
961     * @param w Width of the region to update
962     * @param h Height of the region to update
963     * @param data to be placed into the Allocation
964     */
965    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
966        validateIsInt16();
967        copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
968    }
969
970    /**
971     * Copy from an array into a rectangular region in this Allocation.  The
972     * array is assumed to be tightly packed.
973     *
974     * @param xoff X offset of the region to update in this Allocation
975     * @param yoff Y offset of the region to update in this Allocation
976     * @param w Width of the region to update
977     * @param h Height of the region to update
978     * @param data to be placed into the Allocation
979     */
980    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, long[] data) {
981        validateIsInt64();
982        copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
983    }
984
985    /**
986     * Copy from an array into a rectangular region in this Allocation.  The
987     * array is assumed to be tightly packed.
988     *
989     * @param xoff X offset of the region to update in this Allocation
990     * @param yoff Y offset of the region to update in this Allocation
991     * @param w Width of the region to update
992     * @param h Height of the region to update
993     * @param data to be placed into the Allocation
994     */
995    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
996        validateIsInt32();
997        copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
998    }
999
1000    /**
1001     * Copy from an array into a rectangular region in this Allocation.  The
1002     * array is assumed to be tightly packed.
1003     *
1004     * @param xoff X offset of the region to update in this Allocation
1005     * @param yoff Y offset of the region to update in this Allocation
1006     * @param w Width of the region to update
1007     * @param h Height of the region to update
1008     * @param data to be placed into the Allocation
1009     */
1010    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
1011        validateIsFloat32();
1012        copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
1013    }
1014
1015    /**
1016     * Copy a rectangular region from an Allocation into a rectangular region in
1017     * this Allocation.
1018     *
1019     * @param xoff X offset of the region in this Allocation
1020     * @param yoff Y offset of the region in this Allocation
1021     * @param w Width of the region to update.
1022     * @param h Height of the region to update.
1023     * @param data source Allocation.
1024     * @param dataXoff X offset in source Allocation
1025     * @param dataYoff Y offset in source Allocation
1026     */
1027    public void copy2DRangeFrom(int xoff, int yoff, int w, int h,
1028                                Allocation data, int dataXoff, int dataYoff) {
1029        mRS.validate();
1030        validate2DRange(xoff, yoff, w, h);
1031        mRS.nAllocationData2D(getIDSafe(), xoff, yoff,
1032                              mSelectedLOD, mSelectedFace.mID,
1033                              w, h, data.getID(mRS), dataXoff, dataYoff,
1034                              data.mSelectedLOD, data.mSelectedFace.mID);
1035    }
1036
1037    /**
1038     * Copy a {@link android.graphics.Bitmap} into an Allocation.  The height
1039     * and width of the update will use the height and width of the {@link
1040     * android.graphics.Bitmap}.
1041     *
1042     * @param xoff X offset of the region to update in this Allocation
1043     * @param yoff Y offset of the region to update in this Allocation
1044     * @param data the Bitmap to be copied
1045     */
1046    public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
1047        mRS.validate();
1048        if (data.getConfig() == null) {
1049            Bitmap newBitmap = Bitmap.createBitmap(data.getWidth(), data.getHeight(), Bitmap.Config.ARGB_8888);
1050            Canvas c = new Canvas(newBitmap);
1051            c.drawBitmap(data, 0, 0, null);
1052            copy2DRangeFrom(xoff, yoff, newBitmap);
1053            return;
1054        }
1055        validateBitmapFormat(data);
1056        validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
1057        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
1058    }
1059
1060    private void validate3DRange(int xoff, int yoff, int zoff, int w, int h, int d) {
1061        if (mAdaptedAllocation != null) {
1062
1063        } else {
1064
1065            if (xoff < 0 || yoff < 0 || zoff < 0) {
1066                throw new RSIllegalArgumentException("Offset cannot be negative.");
1067            }
1068            if (h < 0 || w < 0 || d < 0) {
1069                throw new RSIllegalArgumentException("Height or width cannot be negative.");
1070            }
1071            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) {
1072                throw new RSIllegalArgumentException("Updated region larger than allocation.");
1073            }
1074        }
1075    }
1076
1077    /**
1078     * @hide
1079     *
1080     */
1081    void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, byte[] data) {
1082        mRS.validate();
1083        validate3DRange(xoff, yoff, zoff, w, h, d);
1084        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
1085                              w, h, d, data, data.length);
1086    }
1087
1088    /**
1089     * @hide
1090     *
1091     */
1092    void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, short[] data) {
1093        mRS.validate();
1094        validate3DRange(xoff, yoff, zoff, w, h, d);
1095        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
1096                              w, h, d, data, data.length * 2);
1097    }
1098
1099    /**
1100     * @hide
1101     *
1102     */
1103    void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, long[] data) {
1104        mRS.validate();
1105        validate3DRange(xoff, yoff, zoff, w, h, d);
1106        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
1107                              w, h, d, data, data.length * 8);
1108    }
1109
1110    /**
1111     * @hide
1112     *
1113     */
1114    void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, int[] data) {
1115        mRS.validate();
1116        validate3DRange(xoff, yoff, zoff, w, h, d);
1117        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
1118                              w, h, d, data, data.length * 4);
1119    }
1120
1121    /**
1122     * @hide
1123     *
1124     */
1125    void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, float[] data) {
1126        mRS.validate();
1127        validate3DRange(xoff, yoff, zoff, w, h, d);
1128        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
1129                              w, h, d, data, data.length * 4);
1130    }
1131
1132
1133    /**
1134     * @hide
1135     * Copy a rectangular region from the array into the allocation.
1136     * The array is assumed to be tightly packed.
1137     *
1138     * @param xoff X offset of the region to update in this Allocation
1139     * @param yoff Y offset of the region to update in this Allocation
1140     * @param zoff Z offset of the region to update in this Allocation
1141     * @param w Width of the region to update
1142     * @param h Height of the region to update
1143     * @param d Depth of the region to update
1144     * @param data to be placed into the allocation
1145     */
1146    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, byte[] data) {
1147        validateIsInt8();
1148        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data);
1149    }
1150
1151    /**
1152     * @hide
1153     *
1154     */
1155    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, short[] data) {
1156        validateIsInt16();
1157        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data);
1158    }
1159
1160    /**
1161     * @hide
1162     *
1163     */
1164    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, long[] data) {
1165        validateIsInt64();
1166        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data);
1167    }
1168
1169    /**
1170     * @hide
1171     *
1172     */
1173    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, int[] data) {
1174        validateIsInt32();
1175        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data);
1176    }
1177
1178    /**
1179     * @hide
1180     *
1181     */
1182    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, float[] data) {
1183        validateIsFloat32();
1184        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data);
1185    }
1186
1187    /**
1188     * @hide
1189     * Copy a rectangular region into the allocation from another
1190     * allocation.
1191     *
1192     * @param xoff X offset of the region to update in this Allocation
1193     * @param yoff Y offset of the region to update in this Allocation
1194     * @param zoff Z offset of the region to update in this Allocation
1195     * @param w Width of the region to update.
1196     * @param h Height of the region to update.
1197     * @param d Depth of the region to update.
1198     * @param data source allocation.
1199     * @param dataXoff X offset of the region in the source Allocation
1200     * @param dataYoff Y offset of the region in the source Allocation
1201     * @param dataZoff Z offset of the region in the source Allocation
1202     */
1203    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d,
1204                                Allocation data, int dataXoff, int dataYoff, int dataZoff) {
1205        mRS.validate();
1206        validate3DRange(xoff, yoff, zoff, w, h, d);
1207        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
1208                              w, h, d, data.getID(mRS), dataXoff, dataYoff, dataZoff,
1209                              data.mSelectedLOD);
1210    }
1211
1212
1213    /**
1214     * Copy from the Allocation into a {@link android.graphics.Bitmap}.  The
1215     * bitmap must match the dimensions of the Allocation.
1216     *
1217     * @param b The bitmap to be set from the Allocation.
1218     */
1219    public void copyTo(Bitmap b) {
1220        mRS.validate();
1221        validateBitmapFormat(b);
1222        validateBitmapSize(b);
1223        mRS.nAllocationCopyToBitmap(getID(mRS), b);
1224    }
1225
1226    /**
1227     * Copy from the Allocation into a byte array.  The array must be at least
1228     * as large as the Allocation.  The allocation must be of an 8 bit integer
1229     * {@link android.support.v8.renderscript.Element} type.
1230     *
1231     * @param d The array to be set from the Allocation.
1232     */
1233    public void copyTo(byte[] d) {
1234        validateIsInt8();
1235        mRS.validate();
1236        mRS.nAllocationRead(getID(mRS), d);
1237    }
1238
1239    /**
1240     * Copy from the Allocation into a short array.  The array must be at least
1241     * as large as the Allocation.  The allocation must be of an 16 bit integer
1242     * {@link android.support.v8.renderscript.Element} type.
1243     *
1244     * @param d The array to be set from the Allocation.
1245     */
1246    public void copyTo(short[] d) {
1247        validateIsInt16();
1248        mRS.validate();
1249        mRS.nAllocationRead(getID(mRS), d);
1250    }
1251
1252    /**
1253     * Copy from the Allocation into a int array.  The array must be at least as
1254     * large as the Allocation.  The allocation must be of an 32 bit integer
1255     * {@link android.support.v8.renderscript.Element} type.
1256     *
1257     * @param d The array to be set from the Allocation.
1258     */
1259    public void copyTo(long[] d) {
1260        validateIsInt64();
1261        mRS.validate();
1262        mRS.nAllocationRead(getID(mRS), d);
1263    }
1264
1265    /**
1266     * Copy from the Allocation into a int array.  The array must be at least as
1267     * large as the Allocation.  The allocation must be of an 32 bit integer
1268     * {@link android.support.v8.renderscript.Element} type.
1269     *
1270     * @param d The array to be set from the Allocation.
1271     */
1272    public void copyTo(int[] d) {
1273        validateIsInt32();
1274        mRS.validate();
1275        mRS.nAllocationRead(getID(mRS), d);
1276    }
1277
1278    /**
1279     * Copy from the Allocation into a float array.  The array must be at least
1280     * as large as the Allocation.  The allocation must be of an 32 bit float
1281     * {@link android.support.v8.renderscript.Element} type.
1282     *
1283     * @param d The array to be set from the Allocation.
1284     */
1285    public void copyTo(float[] d) {
1286        validateIsFloat32();
1287        mRS.validate();
1288        mRS.nAllocationRead(getID(mRS), d);
1289    }
1290
1291    // creation
1292
1293    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
1294    static {
1295        mBitmapOptions.inScaled = false;
1296    }
1297
1298    /**
1299     * Creates a new Allocation with the given {@link
1300     * android.support.v8.renderscript.Type}, mipmap flag, and usage flags.
1301     *
1302     * @param type RenderScript type describing data layout
1303     * @param mips specifies desired mipmap behaviour for the
1304     *             allocation
1305     * @param usage bit field specifying how the Allocation is
1306     *              utilized
1307     */
1308    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
1309        rs.validate();
1310        if (type.getID(rs) == 0) {
1311            throw new RSInvalidStateException("Bad Type");
1312        }
1313
1314        if(!rs.usingIO() && (usage & (USAGE_IO_INPUT | USAGE_IO_INPUT)) != 0) {
1315            throw new RSRuntimeException("USAGE_IO not supported, Allocation creation failed.");
1316        }
1317
1318        long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
1319        if (id == 0) {
1320            throw new RSRuntimeException("Allocation creation failed.");
1321        }
1322        return new Allocation(id, rs, type, usage);
1323    }
1324
1325    /**
1326     * Creates an Allocation with the size specified by the type and no mipmaps
1327     * generated by default
1328     *
1329     * @param rs Context to which the allocation will belong.
1330     * @param type renderscript type describing data layout
1331     * @param usage bit field specifying how the allocation is
1332     *              utilized
1333     *
1334     * @return allocation
1335     */
1336    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
1337        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
1338    }
1339
1340    /**
1341     * Creates an Allocation for use by scripts with a given {@link
1342     * android.support.v8.renderscript.Type} and no mipmaps
1343     *
1344     * @param rs Context to which the Allocation will belong.
1345     * @param type RenderScript Type describing data layout
1346     *
1347     * @return allocation
1348     */
1349    static public Allocation createTyped(RenderScript rs, Type type) {
1350        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
1351    }
1352
1353    /**
1354     * Creates an Allocation with a specified number of given elements
1355     *
1356     * @param rs Context to which the Allocation will belong.
1357     * @param e Element to use in the Allocation
1358     * @param count the number of Elements in the Allocation
1359     * @param usage bit field specifying how the Allocation is
1360     *              utilized
1361     *
1362     * @return allocation
1363     */
1364    static public Allocation createSized(RenderScript rs, Element e,
1365                                         int count, int usage) {
1366        rs.validate();
1367        Type.Builder b = new Type.Builder(rs, e);
1368        b.setX(count);
1369        Type t = b.create();
1370
1371        long id = rs.nAllocationCreateTyped(t.getID(rs), MipmapControl.MIPMAP_NONE.mID, usage, 0);
1372        if (id == 0) {
1373            throw new RSRuntimeException("Allocation creation failed.");
1374        }
1375        return new Allocation(id, rs, t, usage);
1376    }
1377
1378    /**
1379     * Creates an Allocation with a specified number of given elements
1380     *
1381     * @param rs Context to which the Allocation will belong.
1382     * @param e Element to use in the Allocation
1383     * @param count the number of Elements in the Allocation
1384     *
1385     * @return allocation
1386     */
1387    static public Allocation createSized(RenderScript rs, Element e, int count) {
1388        return createSized(rs, e, count, USAGE_SCRIPT);
1389    }
1390
1391    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
1392        final Bitmap.Config bc = b.getConfig();
1393        if (bc == Bitmap.Config.ALPHA_8) {
1394            return Element.A_8(rs);
1395        }
1396        if (bc == Bitmap.Config.ARGB_4444) {
1397            return Element.RGBA_4444(rs);
1398        }
1399        if (bc == Bitmap.Config.ARGB_8888) {
1400            return Element.RGBA_8888(rs);
1401        }
1402        if (bc == Bitmap.Config.RGB_565) {
1403            return Element.RGB_565(rs);
1404        }
1405        throw new RSInvalidStateException("Bad bitmap type: " + bc);
1406    }
1407
1408    static Type typeFromBitmap(RenderScript rs, Bitmap b,
1409                                       MipmapControl mip) {
1410        Element e = elementFromBitmap(rs, b);
1411        Type.Builder tb = new Type.Builder(rs, e);
1412        tb.setX(b.getWidth());
1413        tb.setY(b.getHeight());
1414        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
1415        return tb.create();
1416    }
1417
1418    /**
1419     * Creates an Allocation from a {@link android.graphics.Bitmap}.
1420     *
1421     * @param rs Context to which the allocation will belong.
1422     * @param b Bitmap source for the allocation data
1423     * @param mips specifies desired mipmap behaviour for the
1424     *             allocation
1425     * @param usage bit field specifying how the allocation is
1426     *              utilized
1427     *
1428     * @return Allocation containing bitmap data
1429     *
1430     */
1431    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
1432                                              MipmapControl mips,
1433                                              int usage) {
1434        rs.validate();
1435
1436        // WAR undocumented color formats
1437        if (b.getConfig() == null) {
1438            if ((usage & USAGE_SHARED) != 0) {
1439                throw new RSIllegalArgumentException("USAGE_SHARED cannot be used with a Bitmap that has a null config.");
1440            }
1441            Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
1442            Canvas c = new Canvas(newBitmap);
1443            c.drawBitmap(b, 0, 0, null);
1444            return createFromBitmap(rs, newBitmap, mips, usage);
1445        }
1446
1447        Type t = typeFromBitmap(rs, b, mips);
1448
1449        // enable optimized bitmap path only with no mipmap and script-only usage
1450        if (mips == MipmapControl.MIPMAP_NONE &&
1451            t.getElement().isCompatible(Element.RGBA_8888(rs)) &&
1452            usage == (USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE)) {
1453            long id = rs.nAllocationCreateBitmapBackedAllocation(t.getID(rs), mips.mID, b, usage);
1454            if (id == 0) {
1455                throw new RSRuntimeException("Load failed.");
1456            }
1457
1458            // keep a reference to the Bitmap around to prevent GC
1459            Allocation alloc = new Allocation(id, rs, t, usage);
1460            alloc.setBitmap(b);
1461            return alloc;
1462        }
1463
1464
1465        long id = rs.nAllocationCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
1466        if (id == 0) {
1467            throw new RSRuntimeException("Load failed.");
1468        }
1469        return new Allocation(id, rs, t, usage);
1470    }
1471
1472    /**
1473     * Associate a {@link android.view.Surface} with this Allocation. This
1474     * operation is only valid for Allocations with {@link #USAGE_IO_OUTPUT}.
1475     *
1476     * @param sur Surface to associate with allocation
1477     */
1478    public void setSurface(Surface sur) {
1479        mRS.validate();
1480        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
1481            throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
1482        }
1483        mRS.nAllocationSetSurface(getID(mRS), sur);
1484    }
1485
1486    /**
1487     * Creates an Allocation from a {@link android.graphics.Bitmap}.
1488     *
1489     * <p>This Allocation will be created with {@link #USAGE_SHARED}, and
1490     * {@link #USAGE_SCRIPT}.</p>
1491     *
1492     * @param rs Context to which the allocation will belong.
1493     * @param b bitmap source for the allocation data
1494     *
1495     * @return Allocation containing bitmap data
1496     *
1497     */
1498    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
1499        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
1500                                USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
1501    }
1502
1503    /**
1504     * Creates a cubemap Allocation from a {@link android.graphics.Bitmap}
1505     * containing the horizontal list of cube faces. Each face must be a square,
1506     * have the same size as all other faces, and have a width that is a power
1507     * of 2.
1508     *
1509     * @param rs Context to which the allocation will belong.
1510     * @param b Bitmap with cubemap faces layed out in the following
1511     *          format: right, left, top, bottom, front, back
1512     * @param mips specifies desired mipmap behaviour for the cubemap
1513     * @param usage bit field specifying how the cubemap is utilized
1514     *
1515     * @return allocation containing cubemap data
1516     *
1517     */
1518    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
1519                                                     MipmapControl mips,
1520                                                     int usage) {
1521        rs.validate();
1522
1523        int height = b.getHeight();
1524        int width = b.getWidth();
1525
1526        if (width % 6 != 0) {
1527            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
1528        }
1529        if (width / 6 != height) {
1530            throw new RSIllegalArgumentException("Only square cube map faces supported");
1531        }
1532        boolean isPow2 = (height & (height - 1)) == 0;
1533        if (!isPow2) {
1534            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
1535        }
1536
1537        Element e = elementFromBitmap(rs, b);
1538        Type.Builder tb = new Type.Builder(rs, e);
1539        tb.setX(height);
1540        tb.setY(height);
1541        tb.setFaces(true);
1542        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
1543        Type t = tb.create();
1544
1545        long id = rs.nAllocationCubeCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
1546        if(id == 0) {
1547            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
1548        }
1549        return new Allocation(id, rs, t, usage);
1550    }
1551
1552    /**
1553     * Creates a non-mipmapped cubemap Allocation for use as a graphics texture
1554     * from a {@link android.graphics.Bitmap} containing the horizontal list of
1555     * cube faces. Each face must be a square, have the same size as all other
1556     * faces, and have a width that is a power of 2.
1557     *
1558     * @param rs Context to which the allocation will belong.
1559     * @param b bitmap with cubemap faces layed out in the following
1560     *          format: right, left, top, bottom, front, back
1561     *
1562     * @return allocation containing cubemap data
1563     *
1564     */
1565    static public Allocation createCubemapFromBitmap(RenderScript rs,
1566                                                     Bitmap b) {
1567        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
1568                                       USAGE_GRAPHICS_TEXTURE);
1569    }
1570
1571    /**
1572     * Creates a cubemap Allocation from 6 {@link android.graphics.Bitmap}
1573     * objects containing the cube faces. Each face must be a square, have the
1574     * same size as all other faces, and have a width that is a power of 2.
1575     *
1576     * @param rs Context to which the allocation will belong.
1577     * @param xpos cubemap face in the positive x direction
1578     * @param xneg cubemap face in the negative x direction
1579     * @param ypos cubemap face in the positive y direction
1580     * @param yneg cubemap face in the negative y direction
1581     * @param zpos cubemap face in the positive z direction
1582     * @param zneg cubemap face in the negative z direction
1583     * @param mips specifies desired mipmap behaviour for the cubemap
1584     * @param usage bit field specifying how the cubemap is utilized
1585     *
1586     * @return allocation containing cubemap data
1587     *
1588     */
1589    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
1590                                                        Bitmap xpos,
1591                                                        Bitmap xneg,
1592                                                        Bitmap ypos,
1593                                                        Bitmap yneg,
1594                                                        Bitmap zpos,
1595                                                        Bitmap zneg,
1596                                                        MipmapControl mips,
1597                                                        int usage) {
1598        /*
1599        int height = xpos.getHeight();
1600        if (xpos.getWidth() != height ||
1601            xneg.getWidth() != height || xneg.getHeight() != height ||
1602            ypos.getWidth() != height || ypos.getHeight() != height ||
1603            yneg.getWidth() != height || yneg.getHeight() != height ||
1604            zpos.getWidth() != height || zpos.getHeight() != height ||
1605            zneg.getWidth() != height || zneg.getHeight() != height) {
1606            throw new RSIllegalArgumentException("Only square cube map faces supported");
1607        }
1608        boolean isPow2 = (height & (height - 1)) == 0;
1609        if (!isPow2) {
1610            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
1611        }
1612
1613        Element e = elementFromBitmap(rs, xpos);
1614        Type.Builder tb = new Type.Builder(rs, e);
1615        tb.setX(height);
1616        tb.setY(height);
1617        tb.setFaces(true);
1618        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
1619        Type t = tb.create();
1620        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
1621
1622        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
1623        adapter.setFace(Type.CubemapFace.POSITIVE_X);
1624        adapter.copyFrom(xpos);
1625        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
1626        adapter.copyFrom(xneg);
1627        adapter.setFace(Type.CubemapFace.POSITIVE_Y);
1628        adapter.copyFrom(ypos);
1629        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
1630        adapter.copyFrom(yneg);
1631        adapter.setFace(Type.CubemapFace.POSITIVE_Z);
1632        adapter.copyFrom(zpos);
1633        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
1634        adapter.copyFrom(zneg);
1635
1636        return cubemap;
1637        */
1638        return null;
1639    }
1640
1641    /**
1642     * Creates a non-mipmapped cubemap Allocation for use as a sampler input
1643     * from 6 {@link android.graphics.Bitmap} objects containing the cube
1644     * faces. Each face must be a square, have the same size as all other faces,
1645     * and have a width that is a power of 2.
1646     *
1647     * @param rs Context to which the allocation will belong.
1648     * @param xpos cubemap face in the positive x direction
1649     * @param xneg cubemap face in the negative x direction
1650     * @param ypos cubemap face in the positive y direction
1651     * @param yneg cubemap face in the negative y direction
1652     * @param zpos cubemap face in the positive z direction
1653     * @param zneg cubemap face in the negative z direction
1654     *
1655     * @return allocation containing cubemap data
1656     *
1657     */
1658    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
1659                                                        Bitmap xpos,
1660                                                        Bitmap xneg,
1661                                                        Bitmap ypos,
1662                                                        Bitmap yneg,
1663                                                        Bitmap zpos,
1664                                                        Bitmap zneg) {
1665        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
1666                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
1667                                          USAGE_GRAPHICS_TEXTURE);
1668    }
1669
1670    /**
1671     * Creates an Allocation from the Bitmap referenced
1672     * by resource ID.
1673     *
1674     * @param rs Context to which the allocation will belong.
1675     * @param res application resources
1676     * @param id resource id to load the data from
1677     * @param mips specifies desired mipmap behaviour for the
1678     *             allocation
1679     * @param usage bit field specifying how the allocation is
1680     *              utilized
1681     *
1682     * @return Allocation containing resource data
1683     *
1684     */
1685    static public Allocation createFromBitmapResource(RenderScript rs,
1686                                                      Resources res,
1687                                                      int id,
1688                                                      MipmapControl mips,
1689                                                      int usage) {
1690
1691        rs.validate();
1692        if ((usage & (USAGE_SHARED | USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) {
1693            throw new RSIllegalArgumentException("Unsupported usage specified.");
1694        }
1695        Bitmap b = BitmapFactory.decodeResource(res, id);
1696        Allocation alloc = createFromBitmap(rs, b, mips, usage);
1697        b.recycle();
1698        return alloc;
1699    }
1700
1701    /**
1702     * Creates a non-mipmapped Allocation to use as a graphics texture from the
1703     * {@link android.graphics.Bitmap} referenced by resource ID.
1704     *
1705     * <p>This allocation will be created with {@link #USAGE_SCRIPT} and
1706     * {@link #USAGE_GRAPHICS_TEXTURE}.</p>
1707     *
1708     * @param rs Context to which the allocation will belong.
1709     * @param res application resources
1710     * @param id resource id to load the data from
1711     *
1712     * @return Allocation containing resource data
1713     *
1714     */
1715    static public Allocation createFromBitmapResource(RenderScript rs,
1716                                                      Resources res,
1717                                                      int id) {
1718        return createFromBitmapResource(rs, res, id,
1719                                        MipmapControl.MIPMAP_NONE,
1720                                        USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
1721    }
1722
1723    /**
1724     * Creates an Allocation containing string data encoded in UTF-8 format.
1725     *
1726     * @param rs Context to which the allocation will belong.
1727     * @param str string to create the allocation from
1728     * @param usage bit field specifying how the allocaiton is
1729     *              utilized
1730     *
1731     */
1732    static public Allocation createFromString(RenderScript rs,
1733                                              String str,
1734                                              int usage) {
1735        rs.validate();
1736        byte[] allocArray = null;
1737        try {
1738            allocArray = str.getBytes("UTF-8");
1739            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
1740            alloc.copyFrom(allocArray);
1741            return alloc;
1742        }
1743        catch (Exception e) {
1744            throw new RSRuntimeException("Could not convert string to utf-8.");
1745        }
1746    }
1747
1748    /**
1749     * For USAGE_IO_OUTPUT, destroy() implies setSurface(null).
1750     *
1751     */
1752    @Override
1753    public void destroy() {
1754        if((mUsage & USAGE_IO_OUTPUT) != 0) {
1755            setSurface(null);
1756        }
1757        super.destroy();
1758    }
1759}
1760
1761