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