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