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