Implement more of copy2DRange*

Change-Id: Id6be481c4abc968df27e5bba1ed044262ec0f293
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 0c33a5f..6b309e1 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -162,12 +162,7 @@
         copy1DRangeFrom(0, mType.getCount(), i);
     }
 
-    private void validateBitmap(Bitmap b) {
-        mRS.validate();
-        if(mType.getX() != b.getWidth() ||
-           mType.getY() != b.getHeight()) {
-            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
-        }
+    private void validateBitmapFormat(Bitmap b) {
         Bitmap.Config bc = b.getConfig();
         switch (bc) {
         case ALPHA_8:
@@ -213,6 +208,13 @@
         }
     }
 
+    private void validateBitmapSize(Bitmap b) {
+        if(mType.getX() != b.getWidth() ||
+           mType.getY() != b.getHeight()) {
+            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
+        }
+    }
+
     public void copyFrom(int[] d) {
         mRS.validate();
         copy1DRangeFrom(0, mType.getCount(), d);
@@ -230,7 +232,9 @@
         copy1DRangeFrom(0, mType.getCount(), d);
     }
     public void copyFrom(Bitmap b) {
-        validateBitmap(b);
+        mRS.validate();
+        validateBitmapSize(b);
+        validateBitmapFormat(b);
         mRS.nAllocationCopyFromBitmap(getID(), b);
     }
 
@@ -338,6 +342,18 @@
         mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
     }
 
+    private void validate2DRange(int xoff, int yoff, int w, int h) {
+        if (xoff < 0 || yoff < 0) {
+            throw new RSIllegalArgumentException("Offset cannot be negative.");
+        }
+        if (h < 0 || w < 0) {
+            throw new RSIllegalArgumentException("Height or width cannot be negative.");
+        }
+        if ((xoff + w) > mType.mDimX ||
+            (yoff + h) > mType.mDimY) {
+            throw new RSIllegalArgumentException("Updated region larger than allocation.");
+        }
+    }
 
     /**
      * Copy a rectanglular region from the array into the
@@ -352,21 +368,25 @@
      */
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
         mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length);
     }
 
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
         mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 2);
     }
 
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
         mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 4);
     }
 
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
         mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 4);
     }
 
@@ -381,12 +401,16 @@
      */
     public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
         mRS.validate();
+        validateBitmapFormat(data);
+        validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
         mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, data);
     }
 
 
     public void copyTo(Bitmap b) {
-        validateBitmap(b);
+        mRS.validate();
+        validateBitmapFormat(b);
+        validateBitmapSize(b);
         mRS.nAllocationCopyToBitmap(getID(), b);
     }
 
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index a7913d7e..35db786 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -535,6 +535,28 @@
 }
 
 static void
+nAllocationData2D_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face,
+                    jint w, jint h, jshortArray data, int sizeBytes)
+{
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocation2DData_s, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len);
+    jshort *ptr = _env->GetShortArrayElements(data, NULL);
+    rsAllocation2DData(con, (RsAllocation)alloc, xoff, yoff, lod, (RsAllocationCubemapFace)face, w, h, ptr, sizeBytes);
+    _env->ReleaseShortArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationData2D_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face,
+                    jint w, jint h, jbyteArray data, int sizeBytes)
+{
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocation2DData_b, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len);
+    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+    rsAllocation2DData(con, (RsAllocation)alloc, xoff, yoff, lod, (RsAllocationCubemapFace)face, w, h, ptr, sizeBytes);
+    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
 nAllocationData2D_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face,
                     jint w, jint h, jintArray data, int sizeBytes)
 {
@@ -567,6 +589,26 @@
 }
 
 static void
+nAllocationRead_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jshortArray data)
+{
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
+    jshort *ptr = _env->GetShortArrayElements(data, NULL);
+    rsAllocationRead(con, (RsAllocation)alloc, ptr);
+    _env->ReleaseShortArrayElements(data, ptr, 0);
+}
+
+static void
+nAllocationRead_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jbyteArray data)
+{
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
+    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+    rsAllocationRead(con, (RsAllocation)alloc, ptr);
+    _env->ReleaseByteArrayElements(data, ptr, 0);
+}
+
+static void
 nAllocationRead_f(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jfloatArray data)
 {
     jint len = _env->GetArrayLength(data);
@@ -1216,8 +1258,12 @@
 {"rsnAllocationData1D",              "(IIIII[FI)V",                           (void*)nAllocationData1D_f },
 {"rsnAllocationElementData1D",       "(IIIII[BI)V",                           (void*)nAllocationElementData1D },
 {"rsnAllocationData2D",              "(IIIIIIII[II)V",                        (void*)nAllocationData2D_i },
+{"rsnAllocationData2D",              "(IIIIIIII[SI)V",                        (void*)nAllocationData2D_s },
+{"rsnAllocationData2D",              "(IIIIIIII[BI)V",                        (void*)nAllocationData2D_b },
 {"rsnAllocationData2D",              "(IIIIIIII[FI)V",                        (void*)nAllocationData2D_f },
 {"rsnAllocationRead",                "(II[I)V",                               (void*)nAllocationRead_i },
+{"rsnAllocationRead",                "(II[S)V",                               (void*)nAllocationRead_s },
+{"rsnAllocationRead",                "(II[B)V",                               (void*)nAllocationRead_b },
 {"rsnAllocationRead",                "(II[F)V",                               (void*)nAllocationRead_f },
 {"rsnAllocationGetType",             "(II)I",                                 (void*)nAllocationGetType},
 {"rsnAllocationResize1D",            "(III)V",                                (void*)nAllocationResize1D },
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index cf394c0..2ed7774 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -202,6 +202,17 @@
     rsc->checkError("Allocation::uploadToTexture");
 }
 
+void Allocation::update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff,
+                                 uint32_t lod, RsAllocationCubemapFace face,
+                                 uint32_t w, uint32_t h) {
+    GLenum type = mType->getElement()->getComponent().getGLType();
+    GLenum format = mType->getElement()->getComponent().getGLFormat();
+    GLenum target = (GLenum)getGLTarget();
+    glBindTexture(target, mTextureID);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glTexSubImage2D(GL_TEXTURE_2D, lod, xoff, yoff, w, h, format, type, ptr);
+}
+
 void Allocation::upload2DTexture(bool isFirstUpload, const void *ptr) {
     GLenum type = mType->getElement()->getComponent().getGLType();
     GLenum format = mType->getElement()->getComponent().getGLFormat();
@@ -368,12 +379,13 @@
         sendDirty();
         mUploadDefered = true;
     } else {
-        upload2DTexture(false, data);
+        update2DTexture(data, xoff, yoff, lod, face, w, h);
     }
 }
 
-void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t lod, RsAllocationCubemapFace face,
-             uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
+void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff,
+                      uint32_t lod, RsAllocationCubemapFace face,
+                      uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
 }
 
 void Allocation::elementData(Context *rsc, uint32_t x, const void *data,
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index a8d086e..a160765 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -106,6 +106,8 @@
     }
 
     void upload2DTexture(bool isFirstUpload, const void *ptr);
+    void update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff,
+                         uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h);
 
 protected:
     ObjectBaseRef<const Type> mType;