am 2a3cdf57: Merge "Implement array types"
automerge: 6e0ad25

* commit '6e0ad25ca8def88a48c9cc6436b12da7ff4600c2':
  Implement array types
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index e979a1be..4af6688 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -58,15 +58,13 @@
     Allocation mAdaptedAllocation;
     int mSize;
 
-    boolean mConstrainedLOD;
-    boolean mConstrainedFace;
-    boolean mConstrainedY;
-    boolean mConstrainedZ;
     boolean mReadAllowed = true;
     boolean mWriteAllowed = true;
+    int mSelectedX;
     int mSelectedY;
     int mSelectedZ;
     int mSelectedLOD;
+    int mSelectedArray[];
     Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
 
     int mCurrentDimX;
diff --git a/rs/java/android/renderscript/AllocationAdapter.java b/rs/java/android/renderscript/AllocationAdapter.java
index 3522a52..9e28f7c 100644
--- a/rs/java/android/renderscript/AllocationAdapter.java
+++ b/rs/java/android/renderscript/AllocationAdapter.java
@@ -21,76 +21,20 @@
  *
  **/
 public class AllocationAdapter extends Allocation {
-    AllocationAdapter(long id, RenderScript rs, Allocation alloc) {
+    Type mWindow;
+
+    AllocationAdapter(long id, RenderScript rs, Allocation alloc, Type t) {
         super(id, rs, alloc.mType, alloc.mUsage);
         mAdaptedAllocation = alloc;
+        mWindow = t;
     }
 
+    /*
     long getID(RenderScript rs) {
         throw new RSInvalidStateException(
             "This operation is not supported with adapters at this time.");
     }
-
-    /**
-     * @hide
-     */
-    public void subData(int xoff, FieldPacker fp) {
-        super.setFromFieldPacker(xoff, fp);
-    }
-    /**
-     * @hide
-     */
-    public void subElementData(int xoff, int component_number, FieldPacker fp) {
-        super.setFromFieldPacker(xoff, component_number, fp);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, int[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, short[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, byte[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, float[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
-        super.copy2DRangeFrom(xoff, yoff, w, h, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData2D(int xoff, int yoff, int w, int h, float[] d) {
-        super.copy2DRangeFrom(xoff, yoff, w, h, d);
-    }
-    /**
-     * @hide
-     */
-    public void readData(int[] d) {
-        super.copyTo(d);
-    }
-    /**
-     * @hide
-     */
-    public void readData(float[] d) {
-        super.copyTo(d);
-    }
+    */
 
     void initLOD(int lod) {
         if (lod < 0) {
@@ -125,6 +69,26 @@
         mSelectedZ = 0;
     }
 
+    private void updateOffsets() {
+        int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
+
+        if (mSelectedArray.length > 0) {
+            a1 = mSelectedArray[0];
+        }
+        if (mSelectedArray.length > 1) {
+            a2 = mSelectedArray[2];
+        }
+        if (mSelectedArray.length > 2) {
+            a3 = mSelectedArray[2];
+        }
+        if (mSelectedArray.length > 3) {
+            a4 = mSelectedArray[3];
+        }
+        mRS.nAllocationAdapterOffset(getID(mRS), mSelectedX, mSelectedY, mSelectedZ,
+                                     mSelectedLOD, mSelectedFace.mID, a1, a2, a3, a4);
+
+    }
+
     /**
      * Set the active LOD.  The LOD must be within the range for the
      * type being adapted.  The base allocation must have mipmaps.
@@ -138,11 +102,13 @@
         if (!mAdaptedAllocation.getType().hasMipmaps()) {
             throw new RSInvalidStateException("Cannot set LOD when the allocation type does not include mipmaps.");
         }
-        if (!mConstrainedLOD) {
+        if (mWindow.hasMipmaps()) {
             throw new RSInvalidStateException("Cannot set LOD when the adapter includes mipmaps.");
         }
 
         initLOD(lod);
+        mSelectedLOD = lod;
+        updateOffsets();
     }
 
     /**
@@ -155,14 +121,38 @@
         if (!mAdaptedAllocation.getType().hasFaces()) {
             throw new RSInvalidStateException("Cannot set Face when the allocation type does not include faces.");
         }
-        if (!mConstrainedFace) {
-            throw new RSInvalidStateException("Cannot set LOD when the adapter includes mipmaps.");
+        if (mWindow.hasFaces()) {
+            throw new RSInvalidStateException("Cannot set face when the adapter includes faces.");
         }
         if (cf == null) {
             throw new RSIllegalArgumentException("Cannot set null face.");
         }
 
         mSelectedFace = cf;
+        updateOffsets();
+    }
+
+
+    /**
+     * @hide
+     * Set the active X.  The x value must be within the range for
+     * the allocation being adapted.
+     *
+     * @param x The x to make active.
+     */
+    public void setX(int x) {
+        if (mAdaptedAllocation.getType().getX() <= x) {
+            throw new RSInvalidStateException("Cannot set X greater than dimension of allocation.");
+        }
+        if (mWindow.getX() == mAdaptedAllocation.getType().getX()) {
+            throw new RSInvalidStateException("Cannot set X when the adapter includes X.");
+        }
+        if ((mWindow.getX() + x) >= mAdaptedAllocation.getType().getX()) {
+            throw new RSInvalidStateException("Cannot set (X + window) which would be larger than dimension of allocation.");
+        }
+
+        mSelectedX = x;
+        updateOffsets();
     }
 
     /**
@@ -179,11 +169,15 @@
         if (mAdaptedAllocation.getType().getY() <= y) {
             throw new RSInvalidStateException("Cannot set Y greater than dimension of allocation.");
         }
-        if (!mConstrainedY) {
+        if (mWindow.getY() == mAdaptedAllocation.getType().getY()) {
             throw new RSInvalidStateException("Cannot set Y when the adapter includes Y.");
         }
+        if ((mWindow.getY() + y) >= mAdaptedAllocation.getType().getY()) {
+            throw new RSInvalidStateException("Cannot set (Y + window) which would be larger than dimension of allocation.");
+        }
 
         mSelectedY = y;
+        updateOffsets();
     }
 
     /**
@@ -200,35 +194,112 @@
         if (mAdaptedAllocation.getType().getZ() <= z) {
             throw new RSInvalidStateException("Cannot set Z greater than dimension of allocation.");
         }
-        if (!mConstrainedZ) {
+        if (mWindow.getZ() == mAdaptedAllocation.getType().getZ()) {
             throw new RSInvalidStateException("Cannot set Z when the adapter includes Z.");
         }
+        if ((mWindow.getZ() + z) >= mAdaptedAllocation.getType().getZ()) {
+            throw new RSInvalidStateException("Cannot set (Z + window) which would be larger than dimension of allocation.");
+        }
 
         mSelectedZ = z;
+        updateOffsets();
+    }
+
+    /**
+     * @hide
+     */
+    public void setArray(int arrayNum, int arrayVal) {
+        if (mAdaptedAllocation.getType().getArray(arrayNum) == 0) {
+            throw new RSInvalidStateException("Cannot set arrayNum when the allocation type does not include arrayNum dim.");
+        }
+        if (mAdaptedAllocation.getType().getArray(arrayNum) <= arrayVal) {
+            throw new RSInvalidStateException("Cannot set arrayNum greater than dimension of allocation.");
+        }
+        if (mWindow.getArray(arrayNum) == mAdaptedAllocation.getType().getArray(arrayNum)) {
+            throw new RSInvalidStateException("Cannot set arrayNum when the adapter includes arrayNum.");
+        }
+        if ((mWindow.getArray(arrayNum) + arrayVal) >= mAdaptedAllocation.getType().getArray(arrayNum)) {
+            throw new RSInvalidStateException("Cannot set (arrayNum + window) which would be larger than dimension of allocation.");
+        }
+
+        mSelectedArray[arrayNum] = arrayVal;
+        updateOffsets();
     }
 
     static public AllocationAdapter create1D(RenderScript rs, Allocation a) {
         rs.validate();
-        AllocationAdapter aa = new AllocationAdapter(0, rs, a);
-        aa.mConstrainedLOD = true;
-        aa.mConstrainedFace = true;
-        aa.mConstrainedY = true;
-        aa.mConstrainedZ = true;
-        aa.initLOD(0);
-        return aa;
+        Type t = Type.createX(rs, a.getElement(), a.getType().getX());
+        return createTyped(rs, a, t);
     }
 
+
     static public AllocationAdapter create2D(RenderScript rs, Allocation a) {
         rs.validate();
-        AllocationAdapter aa = new AllocationAdapter(0, rs, a);
-        aa.mConstrainedLOD = true;
-        aa.mConstrainedFace = true;
-        aa.mConstrainedY = false;
-        aa.mConstrainedZ = true;
-        aa.initLOD(0);
-        return aa;
+        Type t = Type.createXY(rs, a.getElement(), a.getType().getX(), a.getType().getY());
+        return createTyped(rs, a, t);
     }
 
+    /**
+     * @hide
+     *
+     * Create an arbitrary window into the base allocation
+     * The type describes the shape of the window.
+     *
+     * Any dimensions present in the type must be equal or smaller
+     * to the dimensions in the source allocation.  A dimension
+     * present in the allocation that is not present in the type
+     * will be constrained away with the selectors
+     *
+     * If a dimension is present in the type and allcation one of
+     * two things will happen
+     *
+     * If the type is smaller than the allocation a window will be
+     * created, the selected value in the adapter for that dimension
+     * will act as the base address and the type will describe the
+     * size of the view starting at that point.
+     *
+     * If the type and allocation dimension are of the same size
+     * then setting the selector for the dimension will be an error.
+     */
+    static public AllocationAdapter createTyped(RenderScript rs, Allocation a, Type t) {
+        rs.validate();
+
+        if (a.mAdaptedAllocation != null) {
+            throw new RSInvalidStateException("Adapters cannot be nested.");
+        }
+
+        if (!a.getType().getElement().equals(t.getElement())) {
+            throw new RSInvalidStateException("Element must match Allocation type.");
+        }
+
+        if (t.hasFaces() || t.hasMipmaps()) {
+            throw new RSInvalidStateException("Adapters do not support window types with Mipmaps or Faces.");
+        }
+
+        Type at = a.getType();
+        if ((t.getX() > at.getX()) ||
+            (t.getY() > at.getY()) ||
+            (t.getZ() > at.getZ()) ||
+            (t.getArrayCount() > at.getArrayCount())) {
+
+            throw new RSInvalidStateException("Type cannot have dimension larger than the source allocation.");
+        }
+
+        if (t.getArrayCount() > 0) {
+            for (int i = 0; i < t.getArray(i); i++) {
+                if (t.getArray(i) > at.getArray(i)) {
+                    throw new RSInvalidStateException("Type cannot have dimension larger than the source allocation.");
+                }
+            }
+        }
+
+        // Create the object
+        long id = rs.nAllocationAdapterCreate(a.getID(rs), t.getID(rs));
+        if (id == 0) {
+            throw new RSRuntimeException("AllocationAdapter creation failed.");
+        }
+        return new AllocationAdapter(id, rs, a, t);
+    }
 
     /**
      * Override the Allocation resize.  Resizing adapters is not
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 94aa857..5e150e9 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -591,6 +591,20 @@
         rsnAllocationResize1D(mContext, id, dimX);
     }
 
+    native long  rsnAllocationAdapterCreate(long con, long allocId, long typeId);
+    synchronized long nAllocationAdapterCreate(long allocId, long typeId) {
+        validate();
+        return rsnAllocationAdapterCreate(mContext, allocId, typeId);
+    }
+
+    native void  rsnAllocationAdapterOffset(long con, long id, int x, int y, int z,
+                                            int mip, int face, int a1, int a2, int a3, int a4);
+    synchronized void nAllocationAdapterOffset(long id, int x, int y, int z,
+                                               int mip, int face, int a1, int a2, int a3, int a4) {
+        validate();
+        rsnAllocationAdapterOffset(mContext, id, x, y, z, mip, face, a1, a2, a3, a4);
+    }
+
     native long rsnFileA3DCreateFromAssetStream(long con, long assetStream);
     synchronized long nFileA3DCreateFromAssetStream(long assetStream) {
         validate();
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index 98aeaa9..a58e42c 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -52,6 +52,9 @@
     int mDimYuv;
     int mElementCount;
     Element mElement;
+    int mArrays[];
+
+    static final int mMaxArrays = 4;
 
     public enum CubemapFace {
         POSITIVE_X (0),
@@ -146,6 +149,30 @@
         return mElementCount;
     }
 
+    /**
+     * @hide
+     */
+    public int getArray(int dim) {
+        if ((dim < 0) || (dim >= mMaxArrays)) {
+            throw new RSIllegalArgumentException("Array dimension out of range.");
+        }
+
+        if (mArrays == null || dim >= mArrays.length) {
+            // Dimension in range but no array for that dimension allocated
+            return 0;
+        }
+
+        return mArrays[dim];
+    }
+
+    /**
+     * @hide
+     */
+    public int getArrayCount() {
+        if (mArrays != null) return mArrays.length;
+        return 0;
+    }
+
     void calcElementCount() {
         boolean hasLod = hasMipmaps();
         int x = getX();
@@ -180,6 +207,13 @@
 
             count += x * y * z * faces;
         }
+
+        if (mArrays != null) {
+            for (int ct = 0; ct < mArrays.length; ct++) {
+                count *= mArrays[ct];
+            }
+        }
+
         mElementCount = count;
     }
 
@@ -296,6 +330,7 @@
         boolean mDimMipmaps;
         boolean mDimFaces;
         int mYuv;
+        int[] mArray = new int[mMaxArrays];
 
         Element mElement;
 
@@ -341,6 +376,22 @@
             return this;
         }
 
+        /**
+         * @hide
+         *
+         * @param dim
+         * @param value
+         *
+         * @return Builder
+         */
+        public Builder setArray(int dim, int value) {
+            if(dim < 0 || dim >= mMaxArrays) {
+                throw new RSIllegalArgumentException("Array dimension out of range.");
+            }
+            mArray[dim] = value;
+            return this;
+        }
+
         public Builder setMipmaps(boolean value) {
             mDimMipmaps = value;
             return this;
@@ -405,6 +456,16 @@
                 }
             }
 
+            int[] arrays = null;
+            for (int ct = mMaxArrays - 1; ct >= 0; ct--) {
+                if (mArray[ct] != 0 && arrays == null) {
+                    arrays = new int[ct];
+                }
+                if ((mArray[ct] == 0) && (arrays != null)) {
+                    throw new RSInvalidStateException("Array dimensions must be contigous from 0.");
+                }
+            }
+
             long id = mRS.nTypeCreate(mElement.getID(mRS),
                                      mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mYuv);
             Type t = new Type(id, mRS);
@@ -415,6 +476,7 @@
             t.mDimMipmaps = mDimMipmaps;
             t.mDimFaces = mDimFaces;
             t.mDimYuv = mYuv;
+            t.mArrays = arrays;
 
             t.calcElementCount();
             return t;
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index b25dd41..198cabe 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -1047,6 +1047,37 @@
     rsAllocationResize1D((RsContext)con, (RsAllocation)alloc, dimX);
 }
 
+
+static jlong
+nAllocationAdapterCreate(JNIEnv *_env, jobject _this, jlong con, jlong basealloc, jlong type)
+{
+    if (kLogApi) {
+        ALOGD("nAllocationAdapterCreate, con(%p), base(%p), type(%p)",
+              (RsContext)con, (RsAllocation)basealloc, (RsElement)type);
+    }
+    return (jlong)(uintptr_t) rsAllocationAdapterCreate((RsContext)con, (RsType)type,
+                                                        (RsAllocation)basealloc);
+
+}
+
+static void
+nAllocationAdapterOffset(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
+                        jint x, jint y, jint z, jint face, jint lod,
+                        jint a1, jint a2, jint a3, jint a4)
+{
+    uint32_t params[] = {
+        (uint32_t)x, (uint32_t)y, (uint32_t)z, (uint32_t)face,
+        (uint32_t)lod, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4
+    };
+    if (kLogApi) {
+        ALOGD("nAllocationAdapterOffset, con(%p), alloc(%p), x(%i), y(%i), z(%i), face(%i), lod(%i), arrays(%i %i %i %i)",
+              (RsContext)con, (RsAllocation)alloc, x, y, z, face, lod, a1, a2, a3, a4);
+    }
+    rsAllocationAdapterOffset((RsContext)con, (RsAllocation)alloc,
+                              params, sizeof(params));
+}
+
+
 // -----------------------------------
 
 static jlong
@@ -2028,6 +2059,9 @@
 {"rsnAllocationResize1D",            "(JJI)V",                                (void*)nAllocationResize1D },
 {"rsnAllocationGenerateMipmaps",     "(JJ)V",                                 (void*)nAllocationGenerateMipmaps },
 
+{"rsnAllocationAdapterCreate",       "(JJJ)J",                                (void*)nAllocationAdapterCreate },
+{"rsnAllocationAdapterOffset",       "(JJIIIIIIIII)V",                        (void*)nAllocationAdapterOffset },
+
 {"rsnScriptBindAllocation",          "(JJJI)V",                               (void*)nScriptBindAllocation },
 {"rsnScriptSetTimeZone",             "(JJ[B)V",                               (void*)nScriptSetTimeZone },
 {"rsnScriptInvoke",                  "(JJI)V",                                (void*)nScriptInvoke },