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