SubElementData data upload functions.

Change-Id: I5f8c738b5457ae7f6085fc4cd331cf3d13ad75cf
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 6775c08..ee5dbc1 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -90,7 +90,7 @@
         subData1D(0, mType.getElementCount(), d);
     }
 
-    public void subData(int off, FieldPacker fp) {
+    public void subData(int xoff, FieldPacker fp) {
         int eSize = mType.mElement.getSizeBytes();
         final byte[] data = fp.getData();
 
@@ -99,8 +99,28 @@
             throw new IllegalArgumentException("Field packer length " + data.length +
                                                " not divisible by element size " + eSize + ".");
         }
-        data1DChecks(off, count, data.length, data.length);
-        mRS.nAllocationSubData1D(mID, off, count, data, data.length);
+        data1DChecks(xoff, count, data.length, data.length);
+        mRS.nAllocationSubData1D(mID, xoff, count, data, data.length);
+    }
+
+
+    public void subElementData(int xoff, int component_number, FieldPacker fp) {
+        if (component_number >= mType.mElement.mElements.length) {
+            throw new IllegalArgumentException("Component_number " + component_number + " out of range.");
+        }
+        if(xoff < 0) {
+            throw new IllegalArgumentException("Offset must be >= 0.");
+        }
+
+        final byte[] data = fp.getData();
+        int eSize = mType.mElement.mElements[component_number].getSizeBytes();
+
+        if (data.length != eSize) {
+            throw new IllegalArgumentException("Field packer sizelength " + data.length +
+                                               " does not match component size " + eSize + ".");
+        }
+
+        mRS.nAllocationSubElementData1D(mID, xoff, component_number, data, data.length);
     }
 
     private void data1DChecks(int off, int count, int len, int dataSize) {
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 08ba7e2..d51257b 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -232,6 +232,10 @@
     synchronized void nAllocationSubData1D(int id, int off, int count, byte[] d, int sizeBytes) {
         rsnAllocationSubData1D(mContext, id, off, count, d, sizeBytes);
     }
+    native void rsnAllocationSubElementData1D(int con, int id, int xoff, int compIdx, byte[] d, int sizeBytes);
+    synchronized void nAllocationSubElementData1D(int id, int xoff, int compIdx, byte[] d, int sizeBytes) {
+        rsnAllocationSubElementData1D(mContext, id, xoff, compIdx, d, sizeBytes);
+    }
     native void rsnAllocationSubData1D(int con, int id, int off, int count, float[] d, int sizeBytes);
     synchronized void nAllocationSubData1D(int id, int off, int count, float[] d, int sizeBytes) {
         rsnAllocationSubData1D(mContext, id, off, count, d, sizeBytes);
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 81f08e9..23b71b0 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -649,6 +649,17 @@
 }
 
 static void
+//    native void rsnAllocationSubElementData1D(int con, int id, int xoff, int compIdx, byte[] d, int sizeBytes);
+nAllocationSubElementData1D(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint compIdx, jbyteArray data, int sizeBytes)
+{
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocationSubElementData1D, con(%p), alloc(%p), offset(%i), comp(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, compIdx, len, sizeBytes);
+    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+    rsAllocation1DSubElementData(con, (RsAllocation)alloc, offset, ptr, compIdx, sizeBytes);
+    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
 nAllocationSubData2D_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint w, jint h, jintArray data, int sizeBytes)
 {
     jint len = _env->GetArrayLength(data);
@@ -1401,6 +1412,7 @@
 {"rsnAllocationSubData1D",           "(IIII[SI)V",                            (void*)nAllocationSubData1D_s },
 {"rsnAllocationSubData1D",           "(IIII[BI)V",                            (void*)nAllocationSubData1D_b },
 {"rsnAllocationSubData1D",           "(IIII[FI)V",                            (void*)nAllocationSubData1D_f },
+{"rsnAllocationSubElementData1D",    "(IIII[BI)V",                            (void*)nAllocationSubElementData1D },
 {"rsnAllocationSubData2D",           "(IIIIII[II)V",                          (void*)nAllocationSubData2D_i },
 {"rsnAllocationSubData2D",           "(IIIIII[FI)V",                          (void*)nAllocationSubData2D_f },
 {"rsnAllocationRead",                "(II[I)V",                               (void*)nAllocationRead_i },
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 781dbea..ad162bb 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -184,6 +184,16 @@
 	togglePlay
 	}
 
+Allocation1DSubElementData {
+	param RsAllocation va
+	param uint32_t x
+	param const void *data
+	param uint32_t comp_offset
+	param uint32_t bytes
+	handcodeApi
+	togglePlay
+	}
+
 Allocation2DSubData {
 	param RsAllocation va
 	param uint32_t xoff
@@ -194,6 +204,15 @@
 	param uint32_t bytes
 	}
 
+Allocation2DSubElementData {
+	param RsAllocation va
+	param uint32_t x
+	param uint32_t y
+	param const void *data
+	param uint32_t element_offset
+	param uint32_t bytes
+	}
+
 AllocationRead {
 	param RsAllocation va
 	param void * data
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 7e44fea..60998c31 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -230,7 +230,7 @@
 }
 
 
-void Allocation::data(const void *data, uint32_t sizeBytes)
+void Allocation::data(Context *rsc, const void *data, uint32_t sizeBytes)
 {
     uint32_t size = mType->getSizeBytes();
     if (size != sizeBytes) {
@@ -253,7 +253,7 @@
     memcpy(data, mPtr, mType->getSizeBytes());
 }
 
-void Allocation::subData(uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
+void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
 {
     uint32_t eSize = mType->getElementSizeBytes();
     uint8_t * ptr = static_cast<uint8_t *>(mPtr);
@@ -276,7 +276,7 @@
     mUploadDefered = true;
 }
 
-void Allocation::subData(uint32_t xoff, uint32_t yoff,
+void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t yoff,
              uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
 {
     uint32_t eSize = mType->getElementSizeBytes();
@@ -306,11 +306,93 @@
     mUploadDefered = true;
 }
 
-void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
+void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff,
              uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes)
 {
 }
 
+void Allocation::subElementData(Context *rsc, uint32_t x, const void *data,
+                                uint32_t cIdx, uint32_t sizeBytes)
+{
+    uint32_t eSize = mType->getElementSizeBytes();
+    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+    ptr += eSize * x;
+
+    if (cIdx >= mType->getElement()->getFieldCount()) {
+        LOGE("Error Allocation::subElementData component %i out of range.", cIdx);
+        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range.");
+        return;
+    }
+
+    if (x >= mType->getDimX()) {
+        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
+        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
+        return;
+    }
+
+    const Element * e = mType->getElement()->getField(cIdx);
+    ptr += mType->getElement()->getFieldOffsetBytes(cIdx);
+
+    if (sizeBytes != e->getSizeBytes()) {
+        LOGE("Error Allocation::subElementData data size %i does not match field size %i.", sizeBytes, e->getSizeBytes());
+        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
+        return;
+    }
+
+    if (e->getHasReferences()) {
+        e->incRefs(data);
+        e->decRefs(ptr);
+    }
+
+    memcpy(ptr, data, sizeBytes);
+    sendDirty();
+    mUploadDefered = true;
+}
+
+void Allocation::subElementData(Context *rsc, uint32_t x, uint32_t y,
+                                const void *data, uint32_t cIdx, uint32_t sizeBytes)
+{
+    uint32_t eSize = mType->getElementSizeBytes();
+    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+    ptr += eSize * (x + y * mType->getDimX());
+
+    if (x >= mType->getDimX()) {
+        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
+        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
+        return;
+    }
+
+    if (y >= mType->getDimY()) {
+        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
+        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
+        return;
+    }
+
+    if (cIdx >= mType->getElement()->getFieldCount()) {
+        LOGE("Error Allocation::subElementData component %i out of range.", cIdx);
+        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range.");
+        return;
+    }
+
+    const Element * e = mType->getElement()->getField(cIdx);
+    ptr += mType->getElement()->getFieldOffsetBytes(cIdx);
+
+    if (sizeBytes != e->getSizeBytes()) {
+        LOGE("Error Allocation::subElementData data size %i does not match field size %i.", sizeBytes, e->getSizeBytes());
+        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
+        return;
+    }
+
+    if (e->getHasReferences()) {
+        e->incRefs(data);
+        e->decRefs(ptr);
+    }
+
+    memcpy(ptr, data, sizeBytes);
+    sendDirty();
+    mUploadDefered = true;
+}
+
 void Allocation::addProgramToDirty(const Program *p)
 {
     mToDirtyList.push(p);
@@ -394,7 +476,7 @@
     alloc->setName(name.string(), name.size());
 
     // Read in all of our allocation data
-    alloc->data(stream->getPtr() + stream->getPos(), dataSize);
+    alloc->data(rsc, stream->getPtr() + stream->getPos(), dataSize);
     stream->reset(stream->getPos() + dataSize);
 
     return alloc;
@@ -662,16 +744,19 @@
     }
 
     ElementConverter_t cvt = pickConverter(dst, src);
-    cvt(texAlloc->getPtr(), data, w * h);
-
-    if (genMips) {
-        Adapter2D adapt(rsc, texAlloc);
-        Adapter2D adapt2(rsc, texAlloc);
-        for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
-            adapt.setLOD(lod);
-            adapt2.setLOD(lod + 1);
-            mip(adapt2, adapt);
+    if (cvt) {
+        cvt(texAlloc->getPtr(), data, w * h);
+        if (genMips) {
+            Adapter2D adapt(rsc, texAlloc);
+            Adapter2D adapt2(rsc, texAlloc);
+            for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
+                adapt.setLOD(lod);
+                adapt2.setLOD(lod + 1);
+                mip(adapt2, adapt);
+            }
         }
+    } else {
+        rsc->setError(RS_ERROR_BAD_VALUE, "Unsupported bitmap format");
     }
 
     return texAlloc;
@@ -708,19 +793,31 @@
 void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes)
 {
     Allocation *a = static_cast<Allocation *>(va);
-    a->data(data, sizeBytes);
+    a->data(rsc, data, sizeBytes);
 }
 
 void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
 {
     Allocation *a = static_cast<Allocation *>(va);
-    a->subData(xoff, count, data, sizeBytes);
+    a->subData(rsc, xoff, count, data, sizeBytes);
+}
+
+void rsi_Allocation2DSubElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, const void *data, uint32_t eoff, uint32_t sizeBytes)
+{
+    Allocation *a = static_cast<Allocation *>(va);
+    a->subElementData(rsc, x, y, data, eoff, sizeBytes);
+}
+
+void rsi_Allocation1DSubElementData(Context *rsc, RsAllocation va, uint32_t x, const void *data, uint32_t eoff, uint32_t sizeBytes)
+{
+    Allocation *a = static_cast<Allocation *>(va);
+    a->subElementData(rsc, x, data, eoff, sizeBytes);
 }
 
 void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
 {
     Allocation *a = static_cast<Allocation *>(va);
-    a->subData(xoff, yoff, w, h, data, sizeBytes);
+    a->subData(rsc, xoff, yoff, w, h, data, sizeBytes);
 }
 
 void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 177d5a4..967f220 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -56,13 +56,18 @@
     uint32_t getBufferObjectID() const {return mBufferID;}
 
 
-    void data(const void *data, uint32_t sizeBytes);
-    void subData(uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes);
-    void subData(uint32_t xoff, uint32_t yoff,
+    void data(Context *rsc, const void *data, uint32_t sizeBytes);
+    void subData(Context *rsc, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes);
+    void subData(Context *rsc, uint32_t xoff, uint32_t yoff,
                  uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes);
-    void subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
+    void subData(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff,
                  uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes);
 
+    void subElementData(Context *rsc, uint32_t x,
+                        const void *data, uint32_t elementOff, uint32_t sizeBytes);
+    void subElementData(Context *rsc, uint32_t x, uint32_t y,
+                        const void *data, uint32_t elementOff, uint32_t sizeBytes);
+
     void read(void *data);
 
     void enableGLVertexBuffers() const;
diff --git a/libs/rs/rsHandcode.h b/libs/rs/rsHandcode.h
index 353b73a..c02fd42 100644
--- a/libs/rs/rsHandcode.h
+++ b/libs/rs/rsHandcode.h
@@ -96,3 +96,26 @@
 
 }
 
+static inline void rsHCAPI_Allocation1DSubElementData (RsContext rsc, RsAllocation va, uint32_t x, const void * data, uint32_t comp_offset, uint32_t sizeBytes)
+{
+    ThreadIO *io = &((Context *)rsc)->mIO;
+    uint32_t size = sizeof(RS_CMD_Allocation1DSubElementData);
+    if (sizeBytes < DATA_SYNC_SIZE) {
+        size += (sizeBytes + 3) & ~3;
+    }
+    RS_CMD_Allocation1DSubElementData *cmd = static_cast<RS_CMD_Allocation1DSubElementData *>(io->mToCore.reserve(size));
+    cmd->va = va;
+    cmd->x = x;
+    cmd->data = data;
+    cmd->comp_offset = comp_offset;
+    cmd->bytes = sizeBytes;
+    if (sizeBytes < DATA_SYNC_SIZE) {
+        cmd->data = (void *)(cmd+1);
+        memcpy(cmd+1, data, sizeBytes);
+        io->mToCore.commit(RS_CMD_ID_Allocation1DSubElementData, size);
+    } else {
+        io->mToCore.commitSync(RS_CMD_ID_Allocation1DSubElementData, size);
+    }
+
+}
+
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 41d8247..e1628f4 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -331,10 +331,10 @@
 {
     Matrix m;
     m.loadOrtho(0,rsc->getWidth(), rsc->getHeight(),0, -1,1);
-    mDefaultAlloc->subData(RS_PROGRAM_VERTEX_PROJECTION_OFFSET, 16, &m.m[0], 16*4);
+    mDefaultAlloc->subData(rsc, RS_PROGRAM_VERTEX_PROJECTION_OFFSET, 16, &m.m[0], 16*4);
 
     m.loadIdentity();
-    mDefaultAlloc->subData(RS_PROGRAM_VERTEX_MODELVIEW_OFFSET, 16, &m.m[0], 16*4);
+    mDefaultAlloc->subData(rsc, RS_PROGRAM_VERTEX_MODELVIEW_OFFSET, 16, &m.m[0], 16*4);
 }
 
 void ProgramVertexState::deinit(Context *rsc)