Allocation.java revision 615e7cee03d1a53072b0369fa9f247811ac56845
1/*
2 * Copyright (C) 2008 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 android.content.res.Resources;
22import android.content.res.AssetManager;
23import android.graphics.Bitmap;
24import android.graphics.BitmapFactory;
25import android.graphics.SurfaceTexture;
26import android.util.Log;
27import android.util.TypedValue;
28
29/**
30 * <p>
31 * Memory allocation class for renderscript.  An allocation combines a
32 * {@link android.renderscript.Type} with the memory to provide storage for user data and objects.
33 * This implies that all memory in Renderscript is typed.
34 * </p>
35 *
36 * <p>Allocations are the primary way data moves into and out of scripts. Memory is user
37 * synchronized and it's possible for allocations to exist in multiple memory spaces
38 * concurrently. Currently those spaces are:</p>
39 * <ul>
40 * <li>Script: accessable by RS scripts.</li>
41 * <li>Graphics Texture: accessable as a graphics texture.</li>
42 * <li>Graphics Vertex: accessable as graphical vertex data.</li>
43 * <li>Graphics Constants: Accessable as constants in user shaders</li>
44 * </ul>
45 * </p>
46 * <p>
47 * For example, when creating a allocation for a texture, the user can
48 * specify its memory spaces as both script and textures. This means that it can both
49 * be used as script binding and as a GPU texture for rendering. To maintain
50 * synchronization if a script modifies an allocation used by other targets it must
51 * call a synchronizing function to push the updates to the memory, otherwise the results
52 * are undefined.
53 * </p>
54 * <p>By default, Android system side updates are always applied to the script accessable
55 * memory. If this is not present, they are then applied to the various HW
56 * memory types.  A {@link android.renderscript.Allocation#syncAll syncAll()}
57 * call is necessary after the script data is updated to
58 * keep the other memory spaces in sync.</p>
59 *
60 * <p>Allocation data is uploaded in one of two primary ways. For simple
61 * arrays there are copyFrom() functions that take an array from the control code and
62 * copy it to the slave memory store. Both type checked and unchecked copies are provided.
63 * The unchecked variants exist to allow apps to copy over arrays of structures from a
64 * control language that does not support structures.</p>
65 *
66 * <div class="special reference">
67 * <h3>Developer Guides</h3>
68 * <p>For more information about creating an application that uses Renderscript, read the
69 * <a href="{@docRoot}guide/topics/graphics/renderscript.html">Renderscript</a> developer guide.</p>
70 * </div>
71 **/
72public class Allocation extends BaseObj {
73    Type mType;
74    Bitmap mBitmap;
75    int mUsage;
76    Allocation mAdaptedAllocation;
77
78    boolean mConstrainedLOD;
79    boolean mConstrainedFace;
80    boolean mConstrainedY;
81    boolean mConstrainedZ;
82    boolean mReadAllowed = true;
83    boolean mWriteAllowed = true;
84    int mSelectedY;
85    int mSelectedZ;
86    int mSelectedLOD;
87    Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
88
89    int mCurrentDimX;
90    int mCurrentDimY;
91    int mCurrentDimZ;
92    int mCurrentCount;
93
94
95    /**
96     * The usage of the allocation.  These signal to renderscript
97     * where to place the allocation in memory.
98     *
99     * SCRIPT The allocation will be bound to and accessed by
100     * scripts.
101     */
102    public static final int USAGE_SCRIPT = 0x0001;
103
104    /**
105     * GRAPHICS_TEXTURE The allcation will be used as a texture
106     * source by one or more graphics programs.
107     *
108     */
109    public static final int USAGE_GRAPHICS_TEXTURE = 0x0002;
110
111    /**
112     * GRAPHICS_VERTEX The allocation will be used as a graphics
113     * mesh.
114     *
115     */
116    public static final int USAGE_GRAPHICS_VERTEX = 0x0004;
117
118
119    /**
120     * GRAPHICS_CONSTANTS The allocation will be used as the source
121     * of shader constants by one or more programs.
122     *
123     */
124    public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008;
125
126    /**
127     * USAGE_GRAPHICS_RENDER_TARGET The allcation will be used as a
128     * target for offscreen rendering
129     *
130     */
131    public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010;
132
133    /**
134     * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be
135     * used with a SurfaceTexture object.  This usage will cause the
136     * allocation to be created read only.
137     *
138     * @hide
139     */
140    public static final int USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020;
141
142    /**
143     * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be
144     * used with a SurfaceTexture object.  This usage will cause the
145     * allocation to be created read only.
146     *
147     * @hide
148     */
149
150    public static final int USAGE_IO_INPUT = 0x0040;
151    /**
152     * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be
153     * used with a SurfaceTexture object.  This usage will cause the
154     * allocation to be created read only.
155     *
156     * @hide
157     */
158    public static final int USAGE_IO_OUTPUT = 0x0080;
159
160    /**
161     * Controls mipmap behavior when using the bitmap creation and
162     * update functions.
163     */
164    public enum MipmapControl {
165        /**
166         * No mipmaps will be generated and the type generated from the
167         * incoming bitmap will not contain additional LODs.
168         */
169        MIPMAP_NONE(0),
170
171        /**
172         * A Full mipmap chain will be created in script memory.  The
173         * type of the allocation will contain a full mipmap chain.  On
174         * upload to graphics the full chain will be transfered.
175         */
176        MIPMAP_FULL(1),
177
178        /**
179         * The type of the allocation will be the same as MIPMAP_NONE.
180         * It will not contain mipmaps.  On upload to graphics the
181         * graphics copy of the allocation data will contain a full
182         * mipmap chain generated from the top level in script memory.
183         */
184        MIPMAP_ON_SYNC_TO_TEXTURE(2);
185
186        int mID;
187        MipmapControl(int id) {
188            mID = id;
189        }
190    }
191
192
193    private int getIDSafe() {
194        if (mAdaptedAllocation != null) {
195            return mAdaptedAllocation.getID();
196        }
197        return getID();
198    }
199
200    private void updateCacheInfo(Type t) {
201        mCurrentDimX = t.getX();
202        mCurrentDimY = t.getY();
203        mCurrentDimZ = t.getZ();
204        mCurrentCount = mCurrentDimX;
205        if (mCurrentDimY > 1) {
206            mCurrentCount *= mCurrentDimY;
207        }
208        if (mCurrentDimZ > 1) {
209            mCurrentCount *= mCurrentDimZ;
210        }
211    }
212
213    Allocation(int id, RenderScript rs, Type t, int usage) {
214        super(id, rs);
215        if ((usage & ~(USAGE_SCRIPT |
216                       USAGE_GRAPHICS_TEXTURE |
217                       USAGE_GRAPHICS_VERTEX |
218                       USAGE_GRAPHICS_CONSTANTS |
219                       USAGE_GRAPHICS_RENDER_TARGET |
220                       USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
221                       USAGE_IO_INPUT |
222                       USAGE_IO_OUTPUT)) != 0) {
223            throw new RSIllegalArgumentException("Unknown usage specified.");
224        }
225
226        if ((usage & (USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE | USAGE_IO_INPUT)) != 0) {
227            mWriteAllowed = false;
228
229            if ((usage & ~(USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
230                           USAGE_IO_INPUT |
231                           USAGE_GRAPHICS_TEXTURE |
232                           USAGE_SCRIPT)) != 0) {
233                throw new RSIllegalArgumentException("Invalid usage combination.");
234            }
235        }
236
237        mType = t;
238        mUsage = usage;
239
240        if (t != null) {
241            updateCacheInfo(t);
242        }
243    }
244
245    private void validateIsInt32() {
246        if ((mType.mElement.mType == Element.DataType.SIGNED_32) ||
247            (mType.mElement.mType == Element.DataType.UNSIGNED_32)) {
248            return;
249        }
250        throw new RSIllegalArgumentException(
251            "32 bit integer source does not match allocation type " + mType.mElement.mType);
252    }
253
254    private void validateIsInt16() {
255        if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
256            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
257            return;
258        }
259        throw new RSIllegalArgumentException(
260            "16 bit integer source does not match allocation type " + mType.mElement.mType);
261    }
262
263    private void validateIsInt8() {
264        if ((mType.mElement.mType == Element.DataType.SIGNED_8) ||
265            (mType.mElement.mType == Element.DataType.UNSIGNED_8)) {
266            return;
267        }
268        throw new RSIllegalArgumentException(
269            "8 bit integer source does not match allocation type " + mType.mElement.mType);
270    }
271
272    private void validateIsFloat32() {
273        if (mType.mElement.mType == Element.DataType.FLOAT_32) {
274            return;
275        }
276        throw new RSIllegalArgumentException(
277            "32 bit float source does not match allocation type " + mType.mElement.mType);
278    }
279
280    private void validateIsObject() {
281        if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) ||
282            (mType.mElement.mType == Element.DataType.RS_TYPE) ||
283            (mType.mElement.mType == Element.DataType.RS_ALLOCATION) ||
284            (mType.mElement.mType == Element.DataType.RS_SAMPLER) ||
285            (mType.mElement.mType == Element.DataType.RS_SCRIPT) ||
286            (mType.mElement.mType == Element.DataType.RS_MESH) ||
287            (mType.mElement.mType == Element.DataType.RS_PROGRAM_FRAGMENT) ||
288            (mType.mElement.mType == Element.DataType.RS_PROGRAM_VERTEX) ||
289            (mType.mElement.mType == Element.DataType.RS_PROGRAM_RASTER) ||
290            (mType.mElement.mType == Element.DataType.RS_PROGRAM_STORE)) {
291            return;
292        }
293        throw new RSIllegalArgumentException(
294            "Object source does not match allocation type " + mType.mElement.mType);
295    }
296
297    @Override
298    void updateFromNative() {
299        super.updateFromNative();
300        int typeID = mRS.nAllocationGetType(getID());
301        if(typeID != 0) {
302            mType = new Type(typeID, mRS);
303            mType.updateFromNative();
304            updateCacheInfo(mType);
305        }
306    }
307
308    public Type getType() {
309        return mType;
310    }
311
312    public void syncAll(int srcLocation) {
313        switch (srcLocation) {
314        case USAGE_SCRIPT:
315        case USAGE_GRAPHICS_CONSTANTS:
316        case USAGE_GRAPHICS_TEXTURE:
317        case USAGE_GRAPHICS_VERTEX:
318            break;
319        default:
320            throw new RSIllegalArgumentException("Source must be exactly one usage type.");
321        }
322        mRS.validate();
323        mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
324    }
325
326    public void copyFrom(BaseObj[] d) {
327        mRS.validate();
328        validateIsObject();
329        if (d.length != mCurrentCount) {
330            throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
331                                                 mCurrentCount + ", array length = " + d.length);
332        }
333        int i[] = new int[d.length];
334        for (int ct=0; ct < d.length; ct++) {
335            i[ct] = d[ct].getID();
336        }
337        copy1DRangeFromUnchecked(0, mCurrentCount, i);
338    }
339
340    private void validateBitmapFormat(Bitmap b) {
341        Bitmap.Config bc = b.getConfig();
342        switch (bc) {
343        case ALPHA_8:
344            if (mType.getElement().mKind != Element.DataKind.PIXEL_A) {
345                throw new RSIllegalArgumentException("Allocation kind is " +
346                                                     mType.getElement().mKind + ", type " +
347                                                     mType.getElement().mType +
348                                                     " of " + mType.getElement().getSizeBytes() +
349                                                     " bytes, passed bitmap was " + bc);
350            }
351            break;
352        case ARGB_8888:
353            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
354                (mType.getElement().getSizeBytes() != 4)) {
355                throw new RSIllegalArgumentException("Allocation kind is " +
356                                                     mType.getElement().mKind + ", type " +
357                                                     mType.getElement().mType +
358                                                     " of " + mType.getElement().getSizeBytes() +
359                                                     " bytes, passed bitmap was " + bc);
360            }
361            break;
362        case RGB_565:
363            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) ||
364                (mType.getElement().getSizeBytes() != 2)) {
365                throw new RSIllegalArgumentException("Allocation kind is " +
366                                                     mType.getElement().mKind + ", type " +
367                                                     mType.getElement().mType +
368                                                     " of " + mType.getElement().getSizeBytes() +
369                                                     " bytes, passed bitmap was " + bc);
370            }
371            break;
372        case ARGB_4444:
373            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
374                (mType.getElement().getSizeBytes() != 2)) {
375                throw new RSIllegalArgumentException("Allocation kind is " +
376                                                     mType.getElement().mKind + ", type " +
377                                                     mType.getElement().mType +
378                                                     " of " + mType.getElement().getSizeBytes() +
379                                                     " bytes, passed bitmap was " + bc);
380            }
381            break;
382
383        }
384    }
385
386    private void validateBitmapSize(Bitmap b) {
387        if((mCurrentDimX != b.getWidth()) || (mCurrentDimY != b.getHeight())) {
388            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
389        }
390    }
391
392    /**
393     * Copy an allocation from an array.  This variant is not type
394     * checked which allows an application to fill in structured
395     * data from an array.
396     *
397     * @param d the source data array
398     */
399    public void copyFromUnchecked(int[] d) {
400        mRS.validate();
401        copy1DRangeFromUnchecked(0, mCurrentCount, d);
402    }
403    /**
404     * Copy an allocation from an array.  This variant is not type
405     * checked which allows an application to fill in structured
406     * data from an array.
407     *
408     * @param d the source data array
409     */
410    public void copyFromUnchecked(short[] d) {
411        mRS.validate();
412        copy1DRangeFromUnchecked(0, mCurrentCount, d);
413    }
414    /**
415     * Copy an allocation from an array.  This variant is not type
416     * checked which allows an application to fill in structured
417     * data from an array.
418     *
419     * @param d the source data array
420     */
421    public void copyFromUnchecked(byte[] d) {
422        mRS.validate();
423        copy1DRangeFromUnchecked(0, mCurrentCount, d);
424    }
425    /**
426     * Copy an allocation from an array.  This variant is not type
427     * checked which allows an application to fill in structured
428     * data from an array.
429     *
430     * @param d the source data array
431     */
432    public void copyFromUnchecked(float[] d) {
433        mRS.validate();
434        copy1DRangeFromUnchecked(0, mCurrentCount, d);
435    }
436
437    /**
438     * Copy an allocation from an array.  This variant is type
439     * checked and will generate exceptions if the Allocation type
440     * is not a 32 bit integer type.
441     *
442     * @param d the source data array
443     */
444    public void copyFrom(int[] d) {
445        mRS.validate();
446        copy1DRangeFrom(0, mCurrentCount, d);
447    }
448
449    /**
450     * Copy an allocation from an array.  This variant is type
451     * checked and will generate exceptions if the Allocation type
452     * is not a 16 bit integer type.
453     *
454     * @param d the source data array
455     */
456    public void copyFrom(short[] d) {
457        mRS.validate();
458        copy1DRangeFrom(0, mCurrentCount, d);
459    }
460
461    /**
462     * Copy an allocation from an array.  This variant is type
463     * checked and will generate exceptions if the Allocation type
464     * is not a 8 bit integer type.
465     *
466     * @param d the source data array
467     */
468    public void copyFrom(byte[] d) {
469        mRS.validate();
470        copy1DRangeFrom(0, mCurrentCount, d);
471    }
472
473    /**
474     * Copy an allocation from an array.  This variant is type
475     * checked and will generate exceptions if the Allocation type
476     * is not a 32 bit float type.
477     *
478     * @param d the source data array
479     */
480    public void copyFrom(float[] d) {
481        mRS.validate();
482        copy1DRangeFrom(0, mCurrentCount, d);
483    }
484
485    /**
486     * Copy an allocation from a bitmap.  The height, width, and
487     * format of the bitmap must match the existing allocation.
488     *
489     * @param b the source bitmap
490     */
491    public void copyFrom(Bitmap b) {
492        mRS.validate();
493        validateBitmapSize(b);
494        validateBitmapFormat(b);
495        mRS.nAllocationCopyFromBitmap(getID(), b);
496    }
497
498    /**
499     * This is only intended to be used by auto-generate code reflected from the
500     * renderscript script files.
501     *
502     * @param xoff
503     * @param fp
504     */
505    public void setFromFieldPacker(int xoff, FieldPacker fp) {
506        int eSize = mType.mElement.getSizeBytes();
507        final byte[] data = fp.getData();
508
509        int count = data.length / eSize;
510        if ((eSize * count) != data.length) {
511            throw new RSIllegalArgumentException("Field packer length " + data.length +
512                                               " not divisible by element size " + eSize + ".");
513        }
514        copy1DRangeFromUnchecked(xoff, count, data);
515    }
516
517    /**
518     * This is only intended to be used by auto-generate code reflected from the
519     * renderscript script files.
520     *
521     * @param xoff
522     * @param component_number
523     * @param fp
524     */
525    public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
526        if (component_number >= mType.mElement.mElements.length) {
527            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
528        }
529        if(xoff < 0) {
530            throw new RSIllegalArgumentException("Offset must be >= 0.");
531        }
532
533        final byte[] data = fp.getData();
534        int eSize = mType.mElement.mElements[component_number].getSizeBytes();
535
536        if (data.length != eSize) {
537            throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
538                                               " does not match component size " + eSize + ".");
539        }
540
541        mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD,
542                                     component_number, data, data.length);
543    }
544
545    private void data1DChecks(int off, int count, int len, int dataSize) {
546        mRS.validate();
547        if(off < 0) {
548            throw new RSIllegalArgumentException("Offset must be >= 0.");
549        }
550        if(count < 1) {
551            throw new RSIllegalArgumentException("Count must be >= 1.");
552        }
553        if((off + count) > mCurrentCount) {
554            throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
555                                               ", got " + count + " at offset " + off + ".");
556        }
557        if(len < dataSize) {
558            throw new RSIllegalArgumentException("Array too small for allocation type.");
559        }
560    }
561
562    /**
563     * Generate a mipmap chain.  Requires the type of the allocation
564     * include mipmaps.
565     *
566     * This function will generate a complete set of mipmaps from
567     * the top level lod and place them into the script memoryspace.
568     *
569     * If the allocation is also using other memory spaces a
570     * followup sync will be required.
571     */
572    public void generateMipmaps() {
573        mRS.nAllocationGenerateMipmaps(getID());
574    }
575
576    /**
577     * Copy part of an allocation from an array.  This variant is
578     * not type checked which allows an application to fill in
579     * structured data from an array.
580     *
581     * @param off The offset of the first element to be copied.
582     * @param count The number of elements to be copied.
583     * @param d the source data array
584     */
585    public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
586        int dataSize = mType.mElement.getSizeBytes() * count;
587        data1DChecks(off, count, d.length * 4, dataSize);
588        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
589    }
590    /**
591     * Copy part of an allocation from an array.  This variant is
592     * not type checked which allows an application to fill in
593     * structured data from an array.
594     *
595     * @param off The offset of the first element to be copied.
596     * @param count The number of elements to be copied.
597     * @param d the source data array
598     */
599    public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
600        int dataSize = mType.mElement.getSizeBytes() * count;
601        data1DChecks(off, count, d.length * 2, dataSize);
602        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
603    }
604    /**
605     * Copy part of an allocation from an array.  This variant is
606     * not type checked which allows an application to fill in
607     * structured data from an array.
608     *
609     * @param off The offset of the first element to be copied.
610     * @param count The number of elements to be copied.
611     * @param d the source data array
612     */
613    public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
614        int dataSize = mType.mElement.getSizeBytes() * count;
615        data1DChecks(off, count, d.length, dataSize);
616        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
617    }
618    /**
619     * Copy part of an allocation from an array.  This variant is
620     * not type checked which allows an application to fill in
621     * structured data from an array.
622     *
623     * @param off The offset of the first element to be copied.
624     * @param count The number of elements to be copied.
625     * @param d the source data array
626     */
627    public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
628        int dataSize = mType.mElement.getSizeBytes() * count;
629        data1DChecks(off, count, d.length * 4, dataSize);
630        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
631    }
632
633    /**
634     * Copy part of an allocation from an array.  This variant is
635     * type checked and will generate exceptions if the Allocation
636     * type is not a 32 bit integer type.
637     *
638     * @param off The offset of the first element to be copied.
639     * @param count The number of elements to be copied.
640     * @param d the source data array
641     */
642    public void copy1DRangeFrom(int off, int count, int[] d) {
643        validateIsInt32();
644        copy1DRangeFromUnchecked(off, count, d);
645    }
646
647    /**
648     * Copy part of an allocation from an array.  This variant is
649     * type checked and will generate exceptions if the Allocation
650     * type is not a 16 bit integer type.
651     *
652     * @param off The offset of the first element to be copied.
653     * @param count The number of elements to be copied.
654     * @param d the source data array
655     */
656    public void copy1DRangeFrom(int off, int count, short[] d) {
657        validateIsInt16();
658        copy1DRangeFromUnchecked(off, count, d);
659    }
660
661    /**
662     * Copy part of an allocation from an array.  This variant is
663     * type checked and will generate exceptions if the Allocation
664     * type is not a 8 bit integer type.
665     *
666     * @param off The offset of the first element to be copied.
667     * @param count The number of elements to be copied.
668     * @param d the source data array
669     */
670    public void copy1DRangeFrom(int off, int count, byte[] d) {
671        validateIsInt8();
672        copy1DRangeFromUnchecked(off, count, d);
673    }
674
675    /**
676     * Copy part of an allocation from an array.  This variant is
677     * type checked and will generate exceptions if the Allocation
678     * type is not a 32 bit float type.
679     *
680     * @param off The offset of the first element to be copied.
681     * @param count The number of elements to be copied.
682     * @param d the source data array.
683     */
684    public void copy1DRangeFrom(int off, int count, float[] d) {
685        validateIsFloat32();
686        copy1DRangeFromUnchecked(off, count, d);
687    }
688
689     /**
690     * Copy part of an allocation from another allocation.
691     *
692     * @param off The offset of the first element to be copied.
693     * @param count The number of elements to be copied.
694     * @param data the source data allocation.
695     * @param dataOff off The offset of the first element in data to
696     *          be copied.
697     */
698    public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
699        mRS.nAllocationData2D(getIDSafe(), off, 0,
700                              mSelectedLOD, mSelectedFace.mID,
701                              count, 1, data.getID(), dataOff, 0,
702                              data.mSelectedLOD, data.mSelectedFace.mID);
703    }
704
705    private void validate2DRange(int xoff, int yoff, int w, int h) {
706        if (mAdaptedAllocation != null) {
707
708        } else {
709
710            if (xoff < 0 || yoff < 0) {
711                throw new RSIllegalArgumentException("Offset cannot be negative.");
712            }
713            if (h < 0 || w < 0) {
714                throw new RSIllegalArgumentException("Height or width cannot be negative.");
715            }
716            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
717                throw new RSIllegalArgumentException("Updated region larger than allocation.");
718            }
719        }
720    }
721
722    /**
723     * Copy a rectangular region from the array into the allocation.
724     * The incoming array is assumed to be tightly packed.
725     *
726     * @param xoff X offset of the region to update
727     * @param yoff Y offset of the region to update
728     * @param w Width of the incoming region to update
729     * @param h Height of the incoming region to update
730     * @param data to be placed into the allocation
731     */
732    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
733        mRS.validate();
734        validate2DRange(xoff, yoff, w, h);
735        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
736                              w, h, data, data.length);
737    }
738
739    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
740        mRS.validate();
741        validate2DRange(xoff, yoff, w, h);
742        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
743                              w, h, data, data.length * 2);
744    }
745
746    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
747        mRS.validate();
748        validate2DRange(xoff, yoff, w, h);
749        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
750                              w, h, data, data.length * 4);
751    }
752
753    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
754        mRS.validate();
755        validate2DRange(xoff, yoff, w, h);
756        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
757                              w, h, data, data.length * 4);
758    }
759
760    /**
761     * Copy a rectangular region into the allocation from another
762     * allocation.
763     *
764     * @param xoff X offset of the region to update.
765     * @param yoff Y offset of the region to update.
766     * @param w Width of the incoming region to update.
767     * @param h Height of the incoming region to update.
768     * @param data source allocation.
769     * @param dataXoff X offset in data of the region to update.
770     * @param dataYoff Y offset in data of the region to update.
771     */
772    public void copy2DRangeFrom(int xoff, int yoff, int w, int h,
773                                Allocation data, int dataXoff, int dataYoff) {
774        mRS.validate();
775        validate2DRange(xoff, yoff, w, h);
776        mRS.nAllocationData2D(getIDSafe(), xoff, yoff,
777                              mSelectedLOD, mSelectedFace.mID,
778                              w, h, data.getID(), dataXoff, dataYoff,
779                              data.mSelectedLOD, data.mSelectedFace.mID);
780    }
781
782    /**
783     * Copy a bitmap into an allocation.  The height and width of
784     * the update will use the height and width of the incoming
785     * bitmap.
786     *
787     * @param xoff X offset of the region to update
788     * @param yoff Y offset of the region to update
789     * @param data the bitmap to be copied
790     */
791    public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
792        mRS.validate();
793        validateBitmapFormat(data);
794        validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
795        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
796    }
797
798
799    /**
800     * Copy from the Allocation into a Bitmap.  The bitmap must
801     * match the dimensions of the Allocation.
802     *
803     * @param b The bitmap to be set from the Allocation.
804     */
805    public void copyTo(Bitmap b) {
806        mRS.validate();
807        validateBitmapFormat(b);
808        validateBitmapSize(b);
809        mRS.nAllocationCopyToBitmap(getID(), b);
810    }
811
812    /**
813     * Copy from the Allocation into a byte array.  The array must
814     * be at least as large as the Allocation.  The allocation must
815     * be of an 8 bit elemental type.
816     *
817     * @param d The array to be set from the Allocation.
818     */
819    public void copyTo(byte[] d) {
820        validateIsInt8();
821        mRS.validate();
822        mRS.nAllocationRead(getID(), d);
823    }
824
825    /**
826     * Copy from the Allocation into a short array.  The array must
827     * be at least as large as the Allocation.  The allocation must
828     * be of an 16 bit elemental type.
829     *
830     * @param d The array to be set from the Allocation.
831     */
832    public void copyTo(short[] d) {
833        validateIsInt16();
834        mRS.validate();
835        mRS.nAllocationRead(getID(), d);
836    }
837
838    /**
839     * Copy from the Allocation into a int array.  The array must be
840     * at least as large as the Allocation.  The allocation must be
841     * of an 32 bit elemental type.
842     *
843     * @param d The array to be set from the Allocation.
844     */
845    public void copyTo(int[] d) {
846        validateIsInt32();
847        mRS.validate();
848        mRS.nAllocationRead(getID(), d);
849    }
850
851    /**
852     * Copy from the Allocation into a float array.  The array must
853     * be at least as large as the Allocation.  The allocation must
854     * be of an 32 bit float elemental type.
855     *
856     * @param d The array to be set from the Allocation.
857     */
858    public void copyTo(float[] d) {
859        validateIsFloat32();
860        mRS.validate();
861        mRS.nAllocationRead(getID(), d);
862    }
863
864    /**
865     * Resize a 1D allocation.  The contents of the allocation are
866     * preserved.  If new elements are allocated objects are created
867     * with null contents and the new region is otherwise undefined.
868     *
869     * If the new region is smaller the references of any objects
870     * outside the new region will be released.
871     *
872     * A new type will be created with the new dimension.
873     *
874     * @param dimX The new size of the allocation.
875     */
876    public synchronized void resize(int dimX) {
877        if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
878            throw new RSInvalidStateException("Resize only support for 1D allocations at this time.");
879        }
880        mRS.nAllocationResize1D(getID(), dimX);
881        mRS.finish();  // Necessary because resize is fifoed and update is async.
882
883        int typeID = mRS.nAllocationGetType(getID());
884        mType = new Type(typeID, mRS);
885        mType.updateFromNative();
886        updateCacheInfo(mType);
887    }
888
889    /*
890    public void resize(int dimX, int dimY) {
891        if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
892            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
893        }
894        if (mType.getY() == 0) {
895            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
896        }
897        mRS.nAllocationResize2D(getID(), dimX, dimY);
898    }
899    */
900
901
902
903    // creation
904
905    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
906    static {
907        mBitmapOptions.inScaled = false;
908    }
909
910    /**
911     *
912     * @param type renderscript type describing data layout
913     * @param mips specifies desired mipmap behaviour for the
914     *             allocation
915     * @param usage bit field specifying how the allocation is
916     *              utilized
917     */
918    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
919        rs.validate();
920        if (type.getID() == 0) {
921            throw new RSInvalidStateException("Bad Type");
922        }
923        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, 0);
924        if (id == 0) {
925            throw new RSRuntimeException("Allocation creation failed.");
926        }
927        return new Allocation(id, rs, type, usage);
928    }
929
930    /**
931     * @hide
932     * This API is hidden and only intended to be used for
933     * transitional purposes.
934     *
935     * @param type renderscript type describing data layout
936     * @param mips specifies desired mipmap behaviour for the
937     *             allocation
938     * @param usage bit field specifying how the allocation is
939     *              utilized
940     */
941    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips,
942                                         int usage, int pointer) {
943        rs.validate();
944        if (type.getID() == 0) {
945            throw new RSInvalidStateException("Bad Type");
946        }
947        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, pointer);
948        if (id == 0) {
949            throw new RSRuntimeException("Allocation creation failed.");
950        }
951        return new Allocation(id, rs, type, usage);
952    }
953
954    /**
955     * Creates a renderscript allocation with the size specified by
956     * the type and no mipmaps generated by default
957     *
958     * @param rs Context to which the allocation will belong.
959     * @param type renderscript type describing data layout
960     * @param usage bit field specifying how the allocation is
961     *              utilized
962     *
963     * @return allocation
964     */
965    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
966        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
967    }
968
969    /**
970     * Creates a renderscript allocation for use by the script with
971     * the size specified by the type and no mipmaps generated by
972     * default
973     *
974     * @param rs Context to which the allocation will belong.
975     * @param type renderscript type describing data layout
976     *
977     * @return allocation
978     */
979    static public Allocation createTyped(RenderScript rs, Type type) {
980        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
981    }
982
983    /**
984     * Creates a renderscript allocation with a specified number of
985     * given elements
986     *
987     * @param rs Context to which the allocation will belong.
988     * @param e describes what each element of an allocation is
989     * @param count specifies the number of element in the allocation
990     * @param usage bit field specifying how the allocation is
991     *              utilized
992     *
993     * @return allocation
994     */
995    static public Allocation createSized(RenderScript rs, Element e,
996                                         int count, int usage) {
997        rs.validate();
998        Type.Builder b = new Type.Builder(rs, e);
999        b.setX(count);
1000        Type t = b.create();
1001
1002        int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage, 0);
1003        if (id == 0) {
1004            throw new RSRuntimeException("Allocation creation failed.");
1005        }
1006        return new Allocation(id, rs, t, usage);
1007    }
1008
1009    /**
1010     * Creates a renderscript allocation with a specified number of
1011     * given elements
1012     *
1013     * @param rs Context to which the allocation will belong.
1014     * @param e describes what each element of an allocation is
1015     * @param count specifies the number of element in the allocation
1016     *
1017     * @return allocation
1018     */
1019    static public Allocation createSized(RenderScript rs, Element e, int count) {
1020        return createSized(rs, e, count, USAGE_SCRIPT);
1021    }
1022
1023    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
1024        final Bitmap.Config bc = b.getConfig();
1025        if (bc == Bitmap.Config.ALPHA_8) {
1026            return Element.A_8(rs);
1027        }
1028        if (bc == Bitmap.Config.ARGB_4444) {
1029            return Element.RGBA_4444(rs);
1030        }
1031        if (bc == Bitmap.Config.ARGB_8888) {
1032            return Element.RGBA_8888(rs);
1033        }
1034        if (bc == Bitmap.Config.RGB_565) {
1035            return Element.RGB_565(rs);
1036        }
1037        throw new RSInvalidStateException("Bad bitmap type: " + bc);
1038    }
1039
1040    static Type typeFromBitmap(RenderScript rs, Bitmap b,
1041                                       MipmapControl mip) {
1042        Element e = elementFromBitmap(rs, b);
1043        Type.Builder tb = new Type.Builder(rs, e);
1044        tb.setX(b.getWidth());
1045        tb.setY(b.getHeight());
1046        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
1047        return tb.create();
1048    }
1049
1050    /**
1051     * Creates a renderscript allocation from a bitmap
1052     *
1053     * @param rs Context to which the allocation will belong.
1054     * @param b bitmap source for the allocation data
1055     * @param mips specifies desired mipmap behaviour for the
1056     *             allocation
1057     * @param usage bit field specifying how the allocation is
1058     *              utilized
1059     *
1060     * @return renderscript allocation containing bitmap data
1061     *
1062     */
1063    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
1064                                              MipmapControl mips,
1065                                              int usage) {
1066        rs.validate();
1067        Type t = typeFromBitmap(rs, b, mips);
1068
1069        int id = rs.nAllocationCreateFromBitmap(t.getID(), mips.mID, b, usage);
1070        if (id == 0) {
1071            throw new RSRuntimeException("Load failed.");
1072        }
1073        return new Allocation(id, rs, t, usage);
1074    }
1075
1076    /**
1077     *
1078     *
1079     * @hide
1080     *
1081     */
1082    public SurfaceTexture getSurfaceTexture() {
1083        if ((mUsage & USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) == 0) {
1084            throw new RSInvalidStateException("Allocation is not a surface texture.");
1085        }
1086
1087        int id = mRS.nAllocationGetSurfaceTextureID(getID());
1088        return new SurfaceTexture(id);
1089
1090    }
1091
1092
1093    /**
1094     * Creates a non-mipmapped renderscript allocation to use as a
1095     * graphics texture
1096     *
1097     * @param rs Context to which the allocation will belong.
1098     * @param b bitmap source for the allocation data
1099     *
1100     * @return renderscript allocation containing bitmap data
1101     *
1102     */
1103    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
1104        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
1105                                USAGE_GRAPHICS_TEXTURE);
1106    }
1107
1108    /**
1109     * Creates a cubemap allocation from a bitmap containing the
1110     * horizontal list of cube faces. Each individual face must be
1111     * the same size and power of 2
1112     *
1113     * @param rs Context to which the allocation will belong.
1114     * @param b bitmap with cubemap faces layed out in the following
1115     *          format: right, left, top, bottom, front, back
1116     * @param mips specifies desired mipmap behaviour for the cubemap
1117     * @param usage bit field specifying how the cubemap is utilized
1118     *
1119     * @return allocation containing cubemap data
1120     *
1121     */
1122    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
1123                                                     MipmapControl mips,
1124                                                     int usage) {
1125        rs.validate();
1126
1127        int height = b.getHeight();
1128        int width = b.getWidth();
1129
1130        if (width % 6 != 0) {
1131            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
1132        }
1133        if (width / 6 != height) {
1134            throw new RSIllegalArgumentException("Only square cube map faces supported");
1135        }
1136        boolean isPow2 = (height & (height - 1)) == 0;
1137        if (!isPow2) {
1138            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
1139        }
1140
1141        Element e = elementFromBitmap(rs, b);
1142        Type.Builder tb = new Type.Builder(rs, e);
1143        tb.setX(height);
1144        tb.setY(height);
1145        tb.setFaces(true);
1146        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
1147        Type t = tb.create();
1148
1149        int id = rs.nAllocationCubeCreateFromBitmap(t.getID(), mips.mID, b, usage);
1150        if(id == 0) {
1151            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
1152        }
1153        return new Allocation(id, rs, t, usage);
1154    }
1155
1156    /**
1157     * Creates a non-mipmapped cubemap allocation for use as a
1158     * graphics texture from a bitmap containing the horizontal list
1159     * of cube faces. Each individual face must be the same size and
1160     * power of 2
1161     *
1162     * @param rs Context to which the allocation will belong.
1163     * @param b bitmap with cubemap faces layed out in the following
1164     *          format: right, left, top, bottom, front, back
1165     *
1166     * @return allocation containing cubemap data
1167     *
1168     */
1169    static public Allocation createCubemapFromBitmap(RenderScript rs,
1170                                                     Bitmap b) {
1171        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
1172                                       USAGE_GRAPHICS_TEXTURE);
1173    }
1174
1175    /**
1176     * Creates a cubemap allocation from 6 bitmaps containing
1177     * the cube faces. All the faces must be the same size and
1178     * power of 2
1179     *
1180     * @param rs Context to which the allocation will belong.
1181     * @param xpos cubemap face in the positive x direction
1182     * @param xneg cubemap face in the negative x direction
1183     * @param ypos cubemap face in the positive y direction
1184     * @param yneg cubemap face in the negative y direction
1185     * @param zpos cubemap face in the positive z direction
1186     * @param zneg cubemap face in the negative z direction
1187     * @param mips specifies desired mipmap behaviour for the cubemap
1188     * @param usage bit field specifying how the cubemap is utilized
1189     *
1190     * @return allocation containing cubemap data
1191     *
1192     */
1193    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
1194                                                        Bitmap xpos,
1195                                                        Bitmap xneg,
1196                                                        Bitmap ypos,
1197                                                        Bitmap yneg,
1198                                                        Bitmap zpos,
1199                                                        Bitmap zneg,
1200                                                        MipmapControl mips,
1201                                                        int usage) {
1202        int height = xpos.getHeight();
1203        if (xpos.getWidth() != height ||
1204            xneg.getWidth() != height || xneg.getHeight() != height ||
1205            ypos.getWidth() != height || ypos.getHeight() != height ||
1206            yneg.getWidth() != height || yneg.getHeight() != height ||
1207            zpos.getWidth() != height || zpos.getHeight() != height ||
1208            zneg.getWidth() != height || zneg.getHeight() != height) {
1209            throw new RSIllegalArgumentException("Only square cube map faces supported");
1210        }
1211        boolean isPow2 = (height & (height - 1)) == 0;
1212        if (!isPow2) {
1213            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
1214        }
1215
1216        Element e = elementFromBitmap(rs, xpos);
1217        Type.Builder tb = new Type.Builder(rs, e);
1218        tb.setX(height);
1219        tb.setY(height);
1220        tb.setFaces(true);
1221        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
1222        Type t = tb.create();
1223        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
1224
1225        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
1226        adapter.setFace(Type.CubemapFace.POSITIVE_X);
1227        adapter.copyFrom(xpos);
1228        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
1229        adapter.copyFrom(xneg);
1230        adapter.setFace(Type.CubemapFace.POSITIVE_Y);
1231        adapter.copyFrom(ypos);
1232        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
1233        adapter.copyFrom(yneg);
1234        adapter.setFace(Type.CubemapFace.POSITIVE_Z);
1235        adapter.copyFrom(zpos);
1236        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
1237        adapter.copyFrom(zneg);
1238
1239        return cubemap;
1240    }
1241
1242    /**
1243     * Creates a non-mipmapped cubemap allocation for use as a
1244     * graphics texture from 6 bitmaps containing
1245     * the cube faces. All the faces must be the same size and
1246     * power of 2
1247     *
1248     * @param rs Context to which the allocation will belong.
1249     * @param xpos cubemap face in the positive x direction
1250     * @param xneg cubemap face in the negative x direction
1251     * @param ypos cubemap face in the positive y direction
1252     * @param yneg cubemap face in the negative y direction
1253     * @param zpos cubemap face in the positive z direction
1254     * @param zneg cubemap face in the negative z direction
1255     *
1256     * @return allocation containing cubemap data
1257     *
1258     */
1259    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
1260                                                        Bitmap xpos,
1261                                                        Bitmap xneg,
1262                                                        Bitmap ypos,
1263                                                        Bitmap yneg,
1264                                                        Bitmap zpos,
1265                                                        Bitmap zneg) {
1266        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
1267                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
1268                                          USAGE_GRAPHICS_TEXTURE);
1269    }
1270
1271    /**
1272     * Creates a renderscript allocation from the bitmap referenced
1273     * by resource id
1274     *
1275     * @param rs Context to which the allocation will belong.
1276     * @param res application resources
1277     * @param id resource id to load the data from
1278     * @param mips specifies desired mipmap behaviour for the
1279     *             allocation
1280     * @param usage bit field specifying how the allocation is
1281     *              utilized
1282     *
1283     * @return renderscript allocation containing resource data
1284     *
1285     */
1286    static public Allocation createFromBitmapResource(RenderScript rs,
1287                                                      Resources res,
1288                                                      int id,
1289                                                      MipmapControl mips,
1290                                                      int usage) {
1291
1292        rs.validate();
1293        Bitmap b = BitmapFactory.decodeResource(res, id);
1294        Allocation alloc = createFromBitmap(rs, b, mips, usage);
1295        b.recycle();
1296        return alloc;
1297    }
1298
1299    /**
1300     * Creates a non-mipmapped renderscript allocation to use as a
1301     * graphics texture from the bitmap referenced by resource id
1302     *
1303     * @param rs Context to which the allocation will belong.
1304     * @param res application resources
1305     * @param id resource id to load the data from
1306     *
1307     * @return renderscript allocation containing resource data
1308     *
1309     */
1310    static public Allocation createFromBitmapResource(RenderScript rs,
1311                                                      Resources res,
1312                                                      int id) {
1313        return createFromBitmapResource(rs, res, id,
1314                                        MipmapControl.MIPMAP_NONE,
1315                                        USAGE_GRAPHICS_TEXTURE);
1316    }
1317
1318    /**
1319     * Creates a renderscript allocation containing string data
1320     * encoded in UTF-8 format
1321     *
1322     * @param rs Context to which the allocation will belong.
1323     * @param str string to create the allocation from
1324     * @param usage bit field specifying how the allocaiton is
1325     *              utilized
1326     *
1327     */
1328    static public Allocation createFromString(RenderScript rs,
1329                                              String str,
1330                                              int usage) {
1331        rs.validate();
1332        byte[] allocArray = null;
1333        try {
1334            allocArray = str.getBytes("UTF-8");
1335            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
1336            alloc.copyFrom(allocArray);
1337            return alloc;
1338        }
1339        catch (Exception e) {
1340            throw new RSRuntimeException("Could not convert string to utf-8.");
1341        }
1342    }
1343}
1344
1345
1346