Adding a time stamp to transforms to reduce update frequency.

Change-Id: Ief4a9c61886feed03b11c913fbee14613d990dc4
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
index 04a7e4c..55d0fda 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
@@ -92,11 +92,19 @@
             return;
         }
 
+        if (mTransform == null) {
+            throw new RuntimeException("Cameras without transforms are invalid");
+        }
+
         ScriptField_Camera_s.Item cam = new ScriptField_Camera_s.Item();
         cam.horizontalFOV = mFOV;
         cam.near = mNear;
         cam.far = mFar;
+        cam.aspect = 0;
         cam.transformMatrix = mTransform.getRSData().getAllocation();
+        cam.transformTimestamp = 1;
+        cam.timestamp = 1;
+        cam.isDirty = 1;
         cam.name = getNameAlloc(rs);
         mField.set(cam, 0, true);
     }
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
index b136aaa..ad2990a 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
@@ -19,6 +19,8 @@
 import java.lang.Math;
 import java.util.ArrayList;
 
+import com.android.scenegraph.SceneManager;
+
 import android.renderscript.*;
 import android.renderscript.Float3;
 import android.renderscript.Matrix4f;
@@ -31,16 +33,37 @@
 
     public static abstract class Component {
         String mName;
-        Allocation mNameAlloc;
-        int mRsId;
-        Float4 mValue;
         CompoundTransform mParent;
+        int mParentIndex;
+        protected ScriptField_TransformComponent_s.Item mData;
 
-        Allocation getNameAlloc(RenderScriptGL rs) {
-            if (mNameAlloc == null)  {
-                mNameAlloc = SceneManager.getStringAsAllocation(rs, getName());
+        Component(int type, String name) {
+            mData = new ScriptField_TransformComponent_s.Item();
+            mData.type = type;
+            mName = name;
+        }
+
+        void setNameAlloc() {
+            RenderScriptGL rs = SceneManager.getRS();
+            if (mData.name != null)  {
+                return;
             }
-            return mNameAlloc;
+            mData.name = SceneManager.getCachedAlloc(getName());
+            if (mData.name == null) {
+                mData.name = SceneManager.getStringAsAllocation(rs, getName());
+                SceneManager.cacheAlloc(getName(), mData.name);
+            }
+        }
+
+        ScriptField_TransformComponent_s.Item getRSData() {
+            setNameAlloc();
+            return mData;
+        }
+
+        protected void update() {
+            if (mParent != null) {
+                mParent.updateRSComponent(this);
+            }
         }
 
         public String getName() {
@@ -50,67 +73,63 @@
 
     public static class TranslateComponent extends Component {
         public TranslateComponent(String name, Float3 translate) {
-            mRsId = RS_ID_TRANSLATE;
-            mName = name;
-            mValue = new Float4(translate.x, translate.y, translate.z, 0);
+            super(RS_ID_TRANSLATE, name);
+            setValue(translate);
         }
         public Float3 getValue() {
-            return new Float3(mValue.x, mValue.y, mValue.z);
+            return new Float3(mData.value.x, mData.value.y, mData.value.z);
         }
         public void setValue(Float3 val) {
-            mValue.x = val.x;
-            mValue.y = val.y;
-            mValue.z = val.z;
-            mParent.updateRSComponents(true);
+            mData.value.x = val.x;
+            mData.value.y = val.y;
+            mData.value.z = val.z;
+            update();
         }
     }
 
     public static class RotateComponent extends Component {
         public RotateComponent(String name, Float3 axis, float angle) {
-            mRsId = RS_ID_ROTATE;
-            mName = name;
-            mValue = new Float4(axis.x, axis.y, axis.z, angle);
+            super(RS_ID_ROTATE, name);
+            setAxis(axis);
+            setAngle(angle);
         }
         public Float3 getAxis() {
-            return new Float3(mValue.x, mValue.y, mValue.z);
+            return new Float3(mData.value.x, mData.value.y, mData.value.z);
         }
         public float getAngle() {
-            return mValue.w;
+            return mData.value.w;
         }
         public void setAxis(Float3 val) {
-            mValue.x = val.x;
-            mValue.y = val.y;
-            mValue.z = val.z;
-            mParent.updateRSComponents(true);
+            mData.value.x = val.x;
+            mData.value.y = val.y;
+            mData.value.z = val.z;
+            update();
         }
         public void setAngle(float val) {
-            mValue.w = val;
-            mParent.updateRSComponents(true);
+            mData.value.w = val;
+            update();
         }
     }
 
     public static class ScaleComponent extends Component {
         public ScaleComponent(String name, Float3 scale) {
-            mRsId = RS_ID_SCALE;
-            mName = name;
-            mValue = new Float4(scale.x, scale.y, scale.z, 0);
+            super(RS_ID_SCALE, name);
+            setValue(scale);
         }
         public Float3 getValue() {
-            return new Float3(mValue.x, mValue.y, mValue.z);
+            return new Float3(mData.value.x, mData.value.y, mData.value.z);
         }
         public void setValue(Float3 val) {
-            mValue.x = val.x;
-            mValue.y = val.y;
-            mValue.z = val.z;
-            mParent.updateRSComponents(true);
+            mData.value.x = val.x;
+            mData.value.y = val.y;
+            mData.value.z = val.z;
+            update();
         }
     }
 
+    ScriptField_TransformComponent_s mComponentField;
     public ArrayList<Component> mTransformComponents;
 
-    Matrix4f mLocalMatrix;
-    Matrix4f mGlobalMatrix;
-
     public CompoundTransform() {
         mTransformComponents = new ArrayList<Component>();
     }
@@ -120,42 +139,55 @@
             throw new IllegalArgumentException("Transform components may not be shared");
         }
         c.mParent = this;
+        c.mParentIndex = mTransformComponents.size();
         mTransformComponents.add(c);
-        updateRSComponents(true);
+        updateRSComponentAllocation();
     }
 
     public void setComponent(int index, Component c) {
         if (c.mParent != null) {
             throw new IllegalArgumentException("Transform components may not be shared");
         }
+        if (index >= mTransformComponents.size()) {
+            throw new IllegalArgumentException("Invalid component index");
+        }
         c.mParent = this;
+        c.mParentIndex = index;
         mTransformComponents.set(index, c);
-        updateRSComponents(true);
+        updateRSComponent(c);
     }
 
-    // TODO: Will need to optimize this function a bit, we copy more data than we need to
-    void updateRSComponents(boolean copy) {
+    void updateRSComponent(Component c) {
+        if (mField == null || mComponentField == null) {
+            return;
+        }
+        mComponentField.set(c.getRSData(), c.mParentIndex, true);
+        mField.set_isDirty(0, 1, true);
+    }
+
+    void updateRSComponentAllocation() {
         if (mField == null) {
             return;
         }
-        RenderScriptGL rs = SceneManager.getRS();
-        int numElements = mTransformComponents.size();
-        for (int i = 0; i < numElements; i ++) {
-            Component ith = mTransformComponents.get(i);
-            mTransformData.transforms[i] = ith.mValue;
-            mTransformData.transformTypes[i] = ith.mRsId;
-            mTransformData.transformNames[i] = ith.getNameAlloc(rs);
-        }
-        // "null" terminate the array
-        mTransformData.transformTypes[numElements] = RS_ID_NONE;
-        mTransformData.isDirty = 1;
-        if (copy) {
-            mField.set(mTransformData, 0, true);
-        }
+        initLocalData();
+
+        mField.set_components(0, mTransformData.components, false);
+        mField.set_isDirty(0, 1, true);
     }
 
     void initLocalData() {
-        updateRSComponents(false);
+        RenderScriptGL rs = SceneManager.getRS();
+        int numComponenets = mTransformComponents.size();
+        if (numComponenets > 0) {
+            mComponentField = new ScriptField_TransformComponent_s(rs, numComponenets);
+            for (int i = 0; i < numComponenets; i ++) {
+                Component ith = mTransformComponents.get(i);
+                mComponentField.set(ith.getRSData(), i, false);
+            }
+            mComponentField.copyAll();
+
+            mTransformData.components = mComponentField.getAllocation();
+        }
     }
 }
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
index fbda50f..c417544 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
@@ -124,17 +124,17 @@
     }
 
     int getTypeFromName() {
-        int paramType = FLOAT4_DATA;
+        int paramType = SceneManager.getConst().get_shaderParam_FLOAT4_DATA();
         if (mParamName.equalsIgnoreCase(cameraPos)) {
-            paramType = FLOAT4_CAMERA_POS;
+            paramType = SceneManager.getConst().get_shaderParam_FLOAT4_CAMERA_POS();
         } else if(mParamName.equalsIgnoreCase(cameraDir)) {
-            paramType = FLOAT4_CAMERA_DIR;
+            paramType = SceneManager.getConst().get_shaderParam_FLOAT4_CAMERA_DIR();
         } else if(mParamName.startsWith(lightColor) && findLight(lightColor)) {
-            paramType = FLOAT4_LIGHT_COLOR;
+            paramType = SceneManager.getConst().get_shaderParam_FLOAT4_LIGHT_COLOR();
         } else if(mParamName.startsWith(lightPos) && findLight(lightPos)) {
-            paramType = FLOAT4_LIGHT_POS;
+            paramType = SceneManager.getConst().get_shaderParam_FLOAT4_LIGHT_POS();
         } else if(mParamName.startsWith(lightDir) && findLight(lightDir)) {
-            paramType = FLOAT4_LIGHT_DIR;
+            paramType = SceneManager.getConst().get_shaderParam_FLOAT4_LIGHT_DIR();
         }
         return paramType;
     }
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
index 1e5f0fd..6d70bc9 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
@@ -42,8 +42,6 @@
     }
 
     void initLocalData() {
-        // "null" terminate the array
-        mTransformData.transformTypes[0] = RS_ID_NONE;
         mTransformData.localMat = mLocalMatrix;
     }
 
@@ -51,9 +49,8 @@
         if (mField == null) {
             return;
         }
-        mTransformData.localMat = mLocalMatrix;
-        mTransformData.isDirty = 1;
-        mField.set(mTransformData, 0, true);
+        mField.set_localMat(0, mLocalMatrix, false);
+        mField.set_isDirty(0, 1, true);
     }
 }
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
index 2411e92..930b569 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
@@ -48,6 +48,8 @@
  */
 public class SceneManager extends SceneGraphBase {
 
+    HashMap<String, Allocation> mAllocationMap;
+
     ScriptC_render mRenderLoop;
     ScriptC mCameraScript;
     ScriptC mLightScript;
@@ -56,6 +58,7 @@
     ScriptC mVertexParamsScript;
     ScriptC mCullScript;
     ScriptC_transform mTransformScript;
+    ScriptC_export mExportScript;
 
     RenderScriptGL mRS;
     Resources mRes;
@@ -150,6 +153,20 @@
         }
     }
 
+    static Allocation getCachedAlloc(String str) {
+        if (sSceneManager == null) {
+            throw new RuntimeException("Scene manager not initialized");
+        }
+        return sSceneManager.mAllocationMap.get(str);
+    }
+
+    static void cacheAlloc(String str, Allocation alloc) {
+        if (sSceneManager == null) {
+            throw new RuntimeException("Scene manager not initialized");
+        }
+        sSceneManager.mAllocationMap.put(str, alloc);
+    }
+
     public static class SceneLoadedCallback implements Runnable {
         public Scene mLoadedScene;
         public String mName;
@@ -179,6 +196,11 @@
         return sSceneManager.mRes;
     }
 
+    // Constants exported from native to java
+    static ScriptC_export getConst() {
+        return sSceneManager.mExportScript;
+    }
+
     public static SceneManager getInstance() {
         if (sSceneManager == null) {
             sSceneManager = new SceneManager();
@@ -234,6 +256,10 @@
     public void initRS(RenderScriptGL rs, Resources res, int w, int h) {
         mRS = rs;
         mRes = res;
+        mAllocationMap = new HashMap<String, Allocation>();
+
+        mExportScript = new ScriptC_export(rs, res, R.raw.export);
+
         mTransformScript = new ScriptC_transform(rs, res, R.raw.transform);
         mTransformScript.set_gTransformScript(mTransformScript);
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
index 742b14d..39aa1ee 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
@@ -34,22 +34,6 @@
  * @hide
  */
 public abstract class ShaderParam extends SceneGraphBase {
-    static final int FLOAT4_DATA = 0;
-    static final int FLOAT4_CAMERA_POS = 1;
-    static final int FLOAT4_CAMERA_DIR = 2;
-    static final int FLOAT4_LIGHT_COLOR = 3;
-    static final int FLOAT4_LIGHT_POS = 4;
-    static final int FLOAT4_LIGHT_DIR = 5;
-
-    static final int TRANSFORM_DATA = 100;
-    static final int TRANSFORM_VIEW = 101;
-    static final int TRANSFORM_PROJ = 102;
-    static final int TRANSFORM_VIEW_PROJ = 103;
-    static final int TRANSFORM_MODEL = 104;
-    static final int TRANSFORM_MODEL_VIEW = 105;
-    static final int TRANSFORM_MODEL_VIEW_PROJ = 106;
-
-    static final int TEXTURE = 200;
 
     static final String cameraPos        = "cameraPos";
     static final String cameraDir        = "cameraDir";
@@ -120,6 +104,7 @@
         }
 
         mRsFieldItem = new ScriptField_ShaderParam_s.Item();
+        mRsFieldItem.transformTimestamp = 0;
         initLocalData(rs);
         return mRsFieldItem;
     }
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
index 359fad4..b434365 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
@@ -88,6 +88,7 @@
         mTransformData = new ScriptField_SgTransform.Item();
         mTransformData.name = getNameAlloc(rs);
         mTransformData.isDirty = 1;
+        mTransformData.timestamp = 1;
 
         initLocalData();
         updateRSChildData(false);
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
index e082013..87c124b 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
@@ -49,19 +49,19 @@
     }
 
     int getTypeFromName() {
-        int paramType = TRANSFORM_DATA;
+        int paramType = SceneManager.getConst().get_shaderParam_TRANSFORM_DATA();
         if (mParamName.equalsIgnoreCase(view)) {
-            paramType = TRANSFORM_VIEW;
+            paramType = SceneManager.getConst().get_shaderParam_TRANSFORM_VIEW();
         } else if(mParamName.equalsIgnoreCase(proj)) {
-            paramType = TRANSFORM_PROJ;
+            paramType = SceneManager.getConst().get_shaderParam_TRANSFORM_PROJ();
         } else if(mParamName.equalsIgnoreCase(viewProj)) {
-            paramType = TRANSFORM_VIEW_PROJ;
+            paramType = SceneManager.getConst().get_shaderParam_TRANSFORM_VIEW_PROJ();
         } else if(mParamName.equalsIgnoreCase(model)) {
-            paramType = TRANSFORM_MODEL;
+            paramType = SceneManager.getConst().get_shaderParam_TRANSFORM_MODEL();
         } else if(mParamName.equalsIgnoreCase(modelView)) {
-            paramType = TRANSFORM_MODEL_VIEW;
+            paramType = SceneManager.getConst().get_shaderParam_TRANSFORM_MODEL_VIEW();
         } else if(mParamName.equalsIgnoreCase(modelViewProj)) {
-            paramType = TRANSFORM_MODEL_VIEW_PROJ;
+            paramType = SceneManager.getConst().get_shaderParam_TRANSFORM_MODEL_VIEW_PROJ();
         }
         return paramType;
     }
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
index 50554a0..dc0a885 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
@@ -23,26 +23,43 @@
 
     SgCamera *cam = (SgCamera *)rsGetElementAt(*v_in, 0);
     float aspect = *usrData;
-    cam->aspect = aspect;
+    if (cam->aspect != aspect) {
+        cam->isDirty = 1;
+        cam->aspect = aspect;
+    }
+    if (cam->isDirty) {
+        rsMatrixLoadPerspective(&cam->proj, cam->horizontalFOV, cam->aspect, cam->near, cam->far);
+    }
+
     const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
+    //rsDebug("Camera stamp", cam->transformTimestamp);
+    //rsDebug("Transform stamp", camTransform->timestamp);
+    if (camTransform->timestamp != cam->transformTimestamp || cam->isDirty) {
+        cam->isDirty = 1;
+        rs_matrix4x4 camPosMatrix;
+        rsMatrixLoad(&camPosMatrix, &camTransform->globalMat);
+        float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
+        cam->position = rsMatrixMultiply(&camPosMatrix, zero);
 
-    rsMatrixLoadPerspective(&cam->proj, cam->horizontalFOV, cam->aspect, cam->near, cam->far);
+        rsMatrixInverse(&camPosMatrix);
+        rsMatrixLoad(&cam->view, &camPosMatrix);
 
-    rs_matrix4x4 camPosMatrix;
-    rsMatrixLoad(&camPosMatrix, &camTransform->globalMat);
-    float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
-    cam->position = rsMatrixMultiply(&camPosMatrix, zero);
+        rsMatrixLoad(&cam->viewProj, &cam->proj);
+        rsMatrixMultiply(&cam->viewProj, &cam->view);
 
-    rsMatrixInverse(&camPosMatrix);
-    rsMatrixLoad(&cam->view, &camPosMatrix);
+        rsExtractFrustumPlanes(&cam->viewProj,
+                               &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+                               &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+                               &cam->frustumPlanes[3], &cam->frustumPlanes[4]);
+    }
 
-    rsMatrixLoad(&cam->viewProj, &cam->proj);
-    rsMatrixMultiply(&cam->viewProj, &cam->view);
+    if (cam->isDirty) {
+        cam->timestamp ++;
+    }
 
-    rsExtractFrustumPlanes(&cam->viewProj,
-                           &cam->frustumPlanes[0], &cam->frustumPlanes[1],
-                           &cam->frustumPlanes[2], &cam->frustumPlanes[3],
-                           &cam->frustumPlanes[3], &cam->frustumPlanes[4]);
+    cam->isDirty = 0;
+    cam->transformTimestamp = camTransform->timestamp;
+
 #ifdef DEBUG_CAMERA
     printCameraInfo(cam);
 #endif //DEBUG_CAMERA
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
index cd46c14..9cbde617 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
@@ -19,7 +19,28 @@
 // The sole purpose of this script is to have various structs exposed
 // so that java reflected classes are generated
 #include "scenegraph_objects.rsh"
+
+// Export our native constants to java so that we don't have parallel definitions
+const int shaderParam_FLOAT4_DATA = SHADER_PARAM_FLOAT4_DATA;
+const int shaderParam_TRANSFORM_DATA = SHADER_PARAM_TRANSFORM_DATA;
+const int shaderParam_TRANSFORM_MODEL = SHADER_PARAM_TRANSFORM_MODEL;
+
+const int shaderParam_FLOAT4_CAMERA_POS = SHADER_PARAM_FLOAT4_CAMERA_POS;
+const int shaderParam_FLOAT4_CAMERA_DIR = SHADER_PARAM_FLOAT4_CAMERA_DIR;
+const int shaderParam_TRANSFORM_VIEW = SHADER_PARAM_TRANSFORM_VIEW;
+const int shaderParam_TRANSFORM_PROJ = SHADER_PARAM_TRANSFORM_PROJ;
+const int shaderParam_TRANSFORM_VIEW_PROJ = SHADER_PARAM_TRANSFORM_VIEW_PROJ;
+const int shaderParam_TRANSFORM_MODEL_VIEW = SHADER_PARAM_TRANSFORM_MODEL_VIEW;
+const int shaderParam_TRANSFORM_MODEL_VIEW_PROJ = SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ;
+
+const int shaderParam_FLOAT4_LIGHT_COLOR = SHADER_PARAM_FLOAT4_LIGHT_COLOR;
+const int shaderParam_FLOAT4_LIGHT_POS = SHADER_PARAM_FLOAT4_LIGHT_POS;
+const int shaderParam_FLOAT4_LIGHT_DIR = SHADER_PARAM_FLOAT4_LIGHT_DIR;
+
+const int shaderParam_TEXTURE = SHADER_PARAM_TEXTURE;
+
 SgTransform *exportPtr;
+SgTransformComponent *componentPtr;
 SgRenderState *sExport;
 SgRenderable *drExport;
 SgRenderPass *pExport;
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
index 16a877d..3e61971 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
@@ -20,6 +20,27 @@
 
 //#define DEBUG_PARAMS
 
+static void debugParam(SgShaderParam *p, uint8_t *constantBuffer, const SgCamera *currentCam) {
+    rsDebug("____________ Param bufferOffset", p->bufferOffset);
+    rsDebug("Param Type ", p->type);
+
+    uint8_t *dataPtr = constantBuffer + p->bufferOffset;
+    const SgTransform *pTransform = NULL;
+    if (rsIsObject(p->transform)) {
+        pTransform = (const SgTransform *)rsGetElementAt(p->transform, 0);
+
+        rsDebug("Param transform", pTransform);
+        printName(pTransform->name);
+    }
+
+    const SgLight *pLight = NULL;
+    if (rsIsObject(p->light)) {
+        pLight = (const SgLight *)rsGetElementAt(p->light, 0);
+        printLightInfo(pLight);
+    }
+}
+
+
 static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) {
 #ifdef DEBUG_PARAMS
     rsDebug("Writing value ", *input);
@@ -42,31 +63,25 @@
     }
 }
 
-static void processParam(SgShaderParam *p, uint8_t *constantBuffer, const SgCamera *currentCam) {
-#ifdef DEBUG_PARAMS
-    rsDebug("____________ Param bufferOffset", p->bufferOffset);
-    rsDebug("Param Type ", p->type);
-#endif // DEBUG_PARAMS
-
-    uint8_t *dataPtr = constantBuffer + p->bufferOffset;
+static bool processParam(SgShaderParam *p, uint8_t *constantBuffer, const SgCamera *currentCam) {
     const SgTransform *pTransform = NULL;
     if (rsIsObject(p->transform)) {
         pTransform = (const SgTransform *)rsGetElementAt(p->transform, 0);
-
-#ifdef DEBUG_PARAMS
-        rsDebug("Param transform", pTransform);
-        printName(pTransform->name);
-#endif // DEBUG_PARAMS
+        // If we are a transform param and our transform is unchanged, nothing to do
+        bool isTransformOnly = (p->type > SHADER_PARAM_DATA_ONLY);
+        if (p->transformTimestamp == pTransform->timestamp && isTransformOnly) {
+            return false;
+        }
+        p->transformTimestamp = pTransform->timestamp;
     }
 
     const SgLight *pLight = NULL;
     if (rsIsObject(p->light)) {
         pLight = (const SgLight *)rsGetElementAt(p->light, 0);
-#ifdef DEBUG_PARAMS
-        printLightInfo(pLight);
-#endif // DEBUG_PARAMS
     }
 
+    uint8_t *dataPtr = constantBuffer + p->bufferOffset;
+
     switch(p->type) {
     case SHADER_PARAM_FLOAT4_DATA:
         writeFloatData((float*)dataPtr, &p->float_value, p->float_vecSize);
@@ -111,6 +126,7 @@
                              &pTransform->globalMat);
         break;
     }
+    return true;
 }
 
 static void processAllParams(rs_allocation shaderConst,
@@ -123,9 +139,13 @@
         if (rsIsObject(allParams)) {
             numParams = rsAllocationGetDimX(allParams);
         }
+        bool updated = false;
         for (int i = 0; i < numParams; i ++) {
             SgShaderParam *current = (SgShaderParam*)rsGetElementAt(allParams, i);
-            processParam(current, constantBuffer, camera);
+#ifdef DEBUG_PARAMS
+            debugParam(current, constantBuffer, camera);
+#endif // DEBUG_PARAMS
+            updated = processParam(current, constantBuffer, camera) || updated;
         }
     }
 }
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
index 6c9890b..9a5224b 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
@@ -32,36 +32,52 @@
 #define LIGHT_POINT 0
 #define LIGHT_DIRECTIONAL 1
 
-#define SHADER_PARAM_FLOAT4_DATA 0
-#define SHADER_PARAM_FLOAT4_CAMERA_POS 1
-#define SHADER_PARAM_FLOAT4_CAMERA_DIR 2
-#define SHADER_PARAM_FLOAT4_LIGHT_COLOR 3
-#define SHADER_PARAM_FLOAT4_LIGHT_POS 4
-#define SHADER_PARAM_FLOAT4_LIGHT_DIR 5
+// Shader params that involve only data
+#define SHADER_PARAM_DATA_ONLY       10000
+#define SHADER_PARAM_FLOAT4_DATA     10001
+#define SHADER_PARAM_TRANSFORM_DATA  10002
+#define SHADER_PARAM_TRANSFORM_MODEL 10003
 
-#define SHADER_PARAM_TRANSFORM_DATA 100
-#define SHADER_PARAM_TRANSFORM_VIEW 101
-#define SHADER_PARAM_TRANSFORM_PROJ 102
-#define SHADER_PARAM_TRANSFORM_VIEW_PROJ 103
-#define SHADER_PARAM_TRANSFORM_MODEL 104
-#define SHADER_PARAM_TRANSFORM_MODEL_VIEW 105
-#define SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ 106
+// Shader params that involve camera
+#define SHADER_PARAM_CAMERA                    1000
+#define SHADER_PARAM_FLOAT4_CAMERA_POS         1001
+#define SHADER_PARAM_FLOAT4_CAMERA_DIR         1002
+#define SHADER_PARAM_TRANSFORM_VIEW            1003
+#define SHADER_PARAM_TRANSFORM_PROJ            1004
+#define SHADER_PARAM_TRANSFORM_VIEW_PROJ       1005
+#define SHADER_PARAM_TRANSFORM_MODEL_VIEW      1006
+#define SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ 1007
 
-#define SHADER_PARAM_TEXTURE 200
+// Shader Params that only involve lights
+#define SHADER_PARAM_LIGHT                     100
+#define SHADER_PARAM_FLOAT4_LIGHT_COLOR        103
+#define SHADER_PARAM_FLOAT4_LIGHT_POS          104
+#define SHADER_PARAM_FLOAT4_LIGHT_DIR          105
+
+#define SHADER_PARAM_TEXTURE 10
+
+#define TEXTURE_NONE 0
+#define TEXTURE_2D 1
+#define TEXTURE_CUBE 2
+
+typedef struct TransformComponent_s {
+    float4 value;
+    int type;
+    rs_allocation name;
+} SgTransformComponent;
 
 typedef struct __attribute__((packed, aligned(4))) SgTransform {
     rs_matrix4x4 globalMat;
     rs_matrix4x4 localMat;
 
-    float4 transforms[16];
-    int transformTypes[16];
-    rs_allocation transformNames[16];
-
+    rs_allocation components;
     int isDirty;
 
     rs_allocation children;
-
     rs_allocation name;
+
+    // Used to check whether transform params need to be updated
+    uint32_t timestamp;
 } SgTransform;
 
 typedef struct VertexShader_s {
@@ -138,6 +154,12 @@
     rs_allocation name;
     rs_allocation transformMatrix;
     float4 frustumPlanes[6];
+
+    int isDirty;
+    // Timestamp of the camera itself to signal params if anything changes
+    uint32_t timestamp;
+    // Timestamp of our transform
+    uint32_t transformTimestamp;
 } SgCamera;
 
 typedef struct __attribute__((packed, aligned(4))) Light_s {
@@ -157,15 +179,21 @@
     float4 float_value;
     // Use one param type to handle all vector types for now
     uint32_t float_vecSize;
-
     rs_allocation camera;
     rs_allocation light;
     rs_allocation transform;
+    // Used to check whether transform params need to be updated
+    uint32_t transformTimestamp;
     rs_allocation texture;
 } SgShaderParam;
 
+// This represents a texture object
+typedef struct Texture_s {
+    uint32_t type;
+    rs_allocation texture;
+} SgTexture;
+
 static void printName(rs_allocation name) {
-    rsDebug("Object Name: ", 0);
     if (!rsIsObject(name)) {
         rsDebug("no name", 0);
         return;
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
index ce5e999..941b5a8 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
@@ -16,8 +16,6 @@
 
 #pragma rs java_package_name(com.android.modelviewer)
 
-//#define DEBUG_TRANSFORMS
-
 #include "scenegraph_objects.rsh"
 
 rs_script gTransformScript;
@@ -27,6 +25,35 @@
     rs_matrix4x4 *mat;
 } ParentData;
 
+//#define DEBUG_TRANSFORMS
+static void debugTransform(SgTransform *data, const ParentData *parent) {
+    rsDebug("****** <Transform> ******", (int)data);
+    printName(data->name);
+    rsDebug("isDirty", data->isDirty);
+    rsDebug("parent", (int)parent);
+    rsDebug("child ", rsIsObject(data->children));
+
+    // Refresh matrices if dirty
+    if (data->isDirty && rsIsObject(data->components)) {
+        uint32_t numComponenets = rsAllocationGetDimX(data->components);
+        for (int i = 0; i < numComponenets; i ++) {
+            const SgTransformComponent *comp = NULL;
+            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
+
+            if (rsIsObject(comp->name)) {
+                rsDebug((const char*)rsGetElementAt(comp->name, 0), comp->value);
+                rsDebug("Type", comp->type);
+            } else {
+                rsDebug("no name", comp->value);
+                rsDebug("Type", comp->type);
+            }
+        }
+    }
+
+    rsDebug("timestamp", data->timestamp);
+    rsDebug("****** </Transform> ******", (int)data);
+}
+
 static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) {
     rs_matrix4x4 temp;
 
@@ -50,51 +77,31 @@
     const ParentData *parent = (const ParentData *)usrData;
 
 #ifdef DEBUG_TRANSFORMS
-    rsDebug("**** Transform data", (int)data);
-    rsDebug("Transform is dirty", data->isDirty);
-    rsDebug("Transform parent", (int)parent);
-    rsDebug("Transform child ", (int)data->children.p);
-    printName(data->name);
+    debugTransform(data, parent);
 #endif //DEBUG_TRANSFORMS
 
     rs_matrix4x4 *localMat = &data->localMat;
     rs_matrix4x4 *globalMat = &data->globalMat;
 
-    ParentData toChild;
-    toChild.changed = 0;
-    toChild.mat = globalMat;
-
     // Refresh matrices if dirty
-    if (data->isDirty) {
-        toChild.changed = 1;
-
+    if (data->isDirty && rsIsObject(data->components)) {
         bool resetLocal = false;
-        for (int i = 0; i < 16; i ++) {
-            if (data->transformTypes[i] == TRANSFORM_NONE) {
-                break;
-            }
+        uint32_t numComponenets = rsAllocationGetDimX(data->components);
+        for (int i = 0; i < numComponenets; i ++) {
             if (!resetLocal) {
                 // Reset our local matrix only for component transforms
                 rsMatrixLoadIdentity(localMat);
                 resetLocal = true;
             }
-#ifdef DEBUG_TRANSFORMS
-            if (rsIsObject(data->transformNames[i])) {
-                rsDebug((const char*)rsGetElementAt(data->transformNames[i], 0),
-                        data->transforms[i]);
-            } else {
-                rsDebug("Transform adding transformation type", data->transformTypes[i]);
-                rsDebug("Transform adding transformation", data->transforms[i]);
-            }
-#endif //DEBUG_TRANSFORMS
-            appendTransformation(data->transformTypes[i], data->transforms[i], localMat);
+            const SgTransformComponent *comp = NULL;
+            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
+            appendTransformation(comp->type, comp->value, localMat);
         }
     }
 
     if (parent) {
-        if (parent->changed || data->isDirty) {
-            toChild.changed = 1;
-
+        data->isDirty = (parent->changed || data->isDirty) ? 1 : 0;
+        if (data->isDirty) {
             rsMatrixLoad(globalMat, parent->mat);
             rsMatrixMultiply(globalMat, localMat);
         }
@@ -102,6 +109,15 @@
         rsMatrixLoad(globalMat, localMat);
     }
 
+    ParentData toChild;
+    toChild.changed = 0;
+    toChild.mat = globalMat;
+
+    if (data->isDirty) {
+        toChild.changed = 1;
+        data->timestamp ++;
+    }
+
     if (rsIsObject(data->children)) {
         rs_allocation nullAlloc;
         rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild));