Refcounting in allocations.

Change-Id: Ida2dfb404b2cd832e622d981d73a938d5bc5b821
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 6560101..d62fa55 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -234,6 +234,12 @@
         LOGE("Allocation::data called with mismatched size expected %i, got %i", size, sizeBytes);
         return;
     }
+
+    if (mType->getElement()->getHasReferences()) {
+        incRefs(data, sizeBytes / mType->getElement()->getSizeBytes());
+        decRefs(mPtr, sizeBytes / mType->getElement()->getSizeBytes());
+    }
+
     memcpy(mPtr, data, size);
     sendDirty();
     mUploadDefered = true;
@@ -256,6 +262,12 @@
         mType->dumpLOGV("type info");
         return;
     }
+
+    if (mType->getElement()->getHasReferences()) {
+        incRefs(data, count);
+        decRefs(ptr, count);
+    }
+
     memcpy(ptr, data, size);
     sendDirty();
     mUploadDefered = true;
@@ -279,6 +291,10 @@
 
     for (uint32_t line=yoff; line < (yoff+h); line++) {
         uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+        if (mType->getElement()->getHasReferences()) {
+            incRefs(src, w);
+            decRefs(dst, w);
+        }
         memcpy(dst, src, lineSize);
         src += lineSize;
         dst += destW * eSize;
@@ -387,6 +403,32 @@
     }
 }
 
+void Allocation::incRefs(const void *ptr, size_t ct) const
+{
+    const uint8_t *p = static_cast<const uint8_t *>(ptr);
+    const Element *e = mType->getElement();
+    uint32_t stride = e->getSizeBytes();
+
+    while (ct > 0) {
+        e->incRefs(p);
+        ct --;
+        p += stride;
+    }
+}
+
+void Allocation::decRefs(const void *ptr, size_t ct) const
+{
+    const uint8_t *p = static_cast<const uint8_t *>(ptr);
+    const Element *e = mType->getElement();
+    uint32_t stride = e->getSizeBytes();
+
+    while (ct > 0) {
+        e->decRefs(p);
+        ct --;
+        p += stride;
+    }
+}
+
 /////////////////
 //
 
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 8273165..177d5a4 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -81,6 +81,9 @@
     bool getIsTexture() const {return mIsTexture;}
     bool getIsBufferObject() const {return mIsVertexBuffer;}
 
+    void incRefs(const void *ptr, size_t ct) const;
+    void decRefs(const void *ptr, size_t ct) const;
+
 protected:
     void sendDirty() const;
 
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
index 8e509ad..fbaa75f 100644
--- a/libs/rs/rsComponent.cpp
+++ b/libs/rs/rsComponent.cpp
@@ -161,6 +161,10 @@
     mBits = mTypeBits * mVectorSize;
 }
 
+bool Component::isReference() const
+{
+    return (mType >= RS_TYPE_ELEMENT);
+}
 
 
 
diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h
index 15fd5dd..a775051 100644
--- a/libs/rs/rsComponent.h
+++ b/libs/rs/rsComponent.h
@@ -51,6 +51,8 @@
     void serialize(OStream *stream) const;
     void loadFromStream(IStream *stream);
 
+    bool isReference() const;
+
 protected:
     RsDataType mType;
     RsDataKind mKind;
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 37b8bd6..05902f9 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -34,6 +34,7 @@
     mAllocLine = __LINE__;
     mFields = NULL;
     mFieldCount = 0;
+    mHasReference = false;
 }
 
 
@@ -53,6 +54,7 @@
     delete [] mFields;
     mFields = NULL;
     mFieldCount = 0;
+    mHasReference = false;
 }
 
 size_t Element::getSizeBits() const
@@ -68,15 +70,6 @@
     return total;
 }
 
-size_t Element::getFieldOffsetBits(uint32_t componentNumber) const
-{
-    size_t offset = 0;
-    for (uint32_t ct = 0; ct < componentNumber; ct++) {
-        offset += mFields[ct].e->mBits;
-    }
-    return offset;
-}
-
 void Element::dumpLOGV(const char *prefix) const
 {
     ObjectBase::dumpLOGV(prefix);
@@ -124,11 +117,14 @@
 
     elem->mFieldCount = stream->loadU32();
     if(elem->mFieldCount) {
+        uint32_t offset = 0;
         elem->mFields = new ElementField_t [elem->mFieldCount];
         for(uint32_t ct = 0; ct < elem->mFieldCount; ct ++) {
             stream->loadString(&elem->mFields[ct].name);
             Element *fieldElem = Element::createFromStream(rsc, stream);
             elem->mFields[ct].e.set(fieldElem);
+            elem->mFields[ct].offsetBits = offset;
+            offset += fieldElem->getSizeBits();
         }
     }
 
@@ -193,6 +189,7 @@
     Element *e = new Element(rsc);
     e->mComponent.set(dt, dk, isNorm, vecSize);
     e->mBits = e->mComponent.getBits();
+    e->mHasReference = e->mComponent.isReference();
     rsc->mStateElement.mElements.push(e);
     return e;
 }
@@ -223,9 +220,16 @@
     Element *e = new Element(rsc);
     e->mFields = new ElementField_t [count];
     e->mFieldCount = count;
+    size_t bits = 0;
     for (size_t ct=0; ct < count; ct++) {
         e->mFields[ct].e.set(ein[ct]);
         e->mFields[ct].name.setTo(nin[ct], lengths[ct]);
+        e->mFields[ct].offsetBits = bits;
+        bits += ein[ct]->getSizeBits();
+
+        if (ein[ct]->mHasReference) {
+            e->mHasReference = true;
+        }
     }
 
     rsc->mStateElement.mElements.push(e);
@@ -251,6 +255,43 @@
     return s;
 }
 
+void Element::incRefs(const void *ptr) const
+{
+    if (!mFieldCount) {
+        if (mComponent.isReference()) {
+            ObjectBase *const*obp = static_cast<ObjectBase *const*>(ptr);
+            ObjectBase *ob = obp[0];
+            ob->incSysRef();
+        }
+        return;
+    }
+
+    const uint8_t *p = static_cast<const uint8_t *>(ptr);
+    for (uint32_t i=0; i < mFieldCount; i++) {
+        if (mFields[i].e->mHasReference) {
+            mFields[i].e->incRefs(&p[mFields[i].offsetBits >> 3]);
+        }
+    }
+}
+
+void Element::decRefs(const void *ptr) const
+{
+    if (!mFieldCount) {
+        if (mComponent.isReference()) {
+            ObjectBase *const*obp = static_cast<ObjectBase *const*>(ptr);
+            ObjectBase *ob = obp[0];
+            ob->decSysRef();
+        }
+        return;
+    }
+
+    const uint8_t *p = static_cast<const uint8_t *>(ptr);
+    for (uint32_t i=0; i < mFieldCount; i++) {
+        if (mFields[i].e->mHasReference) {
+            mFields[i].e->decRefs(&p[mFields[i].offsetBits >> 3]);
+        }
+    }
+}
 
 
 ElementState::ElementState()
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index 90e7cc8..b5dad7a2 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -40,9 +40,11 @@
         return (getSizeBits() + 7) >> 3;
     }
 
-    size_t getFieldOffsetBits(uint32_t componentNumber) const;
+    size_t getFieldOffsetBits(uint32_t componentNumber) const {
+        return mFields[componentNumber].offsetBits;
+    }
     size_t getFieldOffsetBytes(uint32_t componentNumber) const {
-        return (getFieldOffsetBits(componentNumber) + 7) >> 3;
+        return mFields[componentNumber].offsetBits >> 3;
     }
 
     uint32_t getFieldCount() const {return mFieldCount;}
@@ -66,6 +68,10 @@
     static const Element * create(Context *rsc, size_t count, const Element **,
                             const char **, const size_t * lengths);
 
+    void incRefs(const void *) const;
+    void decRefs(const void *) const;
+    bool getHasReferences() const {return mHasReference;}
+
 protected:
     // deallocate any components that are part of this element.
     void clear();
@@ -73,9 +79,11 @@
     typedef struct {
         String8 name;
         ObjectBaseRef<const Element> e;
+        uint32_t offsetBits;
     } ElementField_t;
     ElementField_t *mFields;
     size_t mFieldCount;
+    bool mHasReference;
 
 
     Element(Context *);