Fix dirty state tracking of allocation attached to ProgramVertex objects when being updated while not attached.
diff --git a/rsAllocation.cpp b/rsAllocation.cpp
index 8ac9c26..5e0959a 100644
--- a/rsAllocation.cpp
+++ b/rsAllocation.cpp
@@ -125,6 +125,7 @@
         return;
     }
     memcpy(mPtr, data, size);
+    sendDirty();
 }
 
 void Allocation::read(void *data)
@@ -145,6 +146,7 @@
         return;
     }
     memcpy(ptr, data, size);
+    sendDirty();
 }
 
 void Allocation::subData(uint32_t xoff, uint32_t yoff,
@@ -169,6 +171,7 @@
         src += lineSize;
         dst += destW * eSize;
     }
+    sendDirty();
 }
 
 void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
@@ -176,7 +179,28 @@
 {
 }
 
+void Allocation::addProgramToDirty(const Program *p)
+{
+    mToDirtyList.add(p);
+}
 
+void Allocation::removeProgramToDirty(const Program *p)
+{
+    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
+        if (mToDirtyList[ct] == p) {
+            mToDirtyList.removeAt(ct);
+            return;
+        }
+    }
+    rsAssert(0);
+}
+
+void Allocation::sendDirty() const
+{
+    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
+        mToDirtyList[ct]->forceDirty();
+    }
+}
 
 /////////////////
 //
@@ -412,31 +436,24 @@
     RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, _dst, _src, genMips, tmp);
     free(tmp);
     return ret;
-
-
-
-
 }
 
 void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes)
 {
     Allocation *a = static_cast<Allocation *>(va);
     a->data(data, sizeBytes);
-    rsc->allocationCheck(a);
 }
 
 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);
-    rsc->allocationCheck(a);
 }
 
 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);
-    rsc->allocationCheck(a);
 }
 
 void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
diff --git a/rsAllocation.h b/rsAllocation.h
index 1b83267..cf3ea9e 100644
--- a/rsAllocation.h
+++ b/rsAllocation.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace renderscript {
 
-
+class Program;
 
 class Allocation : public ObjectBase
 {
@@ -65,11 +65,17 @@
     void enableGLVertexBuffers() const;
     void setupGLIndexBuffers() const;
 
+    void addProgramToDirty(const Program *);
+    void removeProgramToDirty(const Program *);
 
 protected:
+    void sendDirty() const;
+
     ObjectBaseRef<const Type> mType;
     void * mPtr;
 
+    Vector<const Program *> mToDirtyList;
+
     // Usage restrictions
     bool mCpuWrite;
     bool mCpuRead;
diff --git a/rsContext.cpp b/rsContext.cpp
index cc39dac..463f63f 100644
--- a/rsContext.cpp
+++ b/rsContext.cpp
@@ -424,13 +424,6 @@
     }
 }
 
-void Context::allocationCheck(const Allocation *a)
-{
-    mVertex->checkUpdatedAllocation(a);
-    mFragment->checkUpdatedAllocation(a);
-    mFragmentStore->checkUpdatedAllocation(a);
-}
-
 void Context::setVertex(ProgramVertex *pv)
 {
     if (pv == NULL) {
@@ -438,7 +431,6 @@
     } else {
         mVertex.set(pv);
     }
-    mVertex->forceDirty();
 }
 
 void Context::assignName(ObjectBase *obj, const char *name, uint32_t len)
diff --git a/rsContext.h b/rsContext.h
index 0dd90ed..dcdd65a 100644
--- a/rsContext.h
+++ b/rsContext.h
@@ -89,7 +89,6 @@
     const ProgramVertex * getVertex() {return mVertex.get();}
 
     void setupCheck();
-    void allocationCheck(const Allocation *);
 
     void pause();
     void resume();
diff --git a/rsProgram.cpp b/rsProgram.cpp
index 5f2a609..ed5918b 100644
--- a/rsProgram.cpp
+++ b/rsProgram.cpp
@@ -32,19 +32,23 @@
 
 Program::~Program()
 {
+    bindAllocation(NULL);
 }
 
 
 void Program::bindAllocation(Allocation *alloc)
 {
+    if (mConstants.get() == alloc) {
+        return;
+    }
+    if (mConstants.get()) {
+        mConstants.get()->removeProgramToDirty(this);
+    }
     mConstants.set(alloc);
+    if (alloc) {
+        alloc->addProgramToDirty(this);
+    }
     mDirty = true;
 }
 
-void Program::checkUpdatedAllocation(const Allocation *alloc)
-{
-    if (mConstants.get() == alloc) {
-        mDirty = true;
-    }
-}
 
diff --git a/rsProgram.h b/rsProgram.h
index 57c654f..86a46e2 100644
--- a/rsProgram.h
+++ b/rsProgram.h
@@ -33,7 +33,6 @@
     virtual ~Program();
 
     void bindAllocation(Allocation *);
-    void checkUpdatedAllocation(const Allocation *);
 
 protected:
     // Components not listed in "in" will be passed though
@@ -47,7 +46,7 @@
 
 
 public:
-    void forceDirty() {mDirty = true;}
+    void forceDirty() const {mDirty = true;}
 };