am f6a7e1f7: Merge "Don\'t wait for current activity to pause before resuming next."

* commit 'f6a7e1f7cd12fbbb2e35391850aec7d7d57b8f66':
  Don't wait for current activity to pause before resuming next.
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 11c2427..88ee362 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -22,6 +22,7 @@
 import android.content.res.AssetManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.SurfaceTexture;
 import android.util.Log;
 import android.util.TypedValue;
 
@@ -78,6 +79,8 @@
     boolean mConstrainedFace;
     boolean mConstrainedY;
     boolean mConstrainedZ;
+    boolean mReadAllowed = true;
+    boolean mWriteAllowed = true;
     int mSelectedY;
     int mSelectedZ;
     int mSelectedLOD;
@@ -127,6 +130,32 @@
      */
     public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010;
 
+    /**
+     * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be
+     * used with a SurfaceTexture object.  This usage will cause the
+     * allocation to be created read only.
+     *
+     * @hide
+     */
+    public static final int USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020;
+
+    /**
+     * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be
+     * used with a SurfaceTexture object.  This usage will cause the
+     * allocation to be created read only.
+     *
+     * @hide
+     */
+
+    public static final int USAGE_IO_INPUT = 0x0040;
+    /**
+     * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be
+     * used with a SurfaceTexture object.  This usage will cause the
+     * allocation to be created read only.
+     *
+     * @hide
+     */
+    public static final int USAGE_IO_OUTPUT = 0x0080;
 
     /**
      * Controls mipmap behavior when using the bitmap creation and
@@ -187,10 +216,26 @@
                        USAGE_GRAPHICS_TEXTURE |
                        USAGE_GRAPHICS_VERTEX |
                        USAGE_GRAPHICS_CONSTANTS |
-                       USAGE_GRAPHICS_RENDER_TARGET)) != 0) {
+                       USAGE_GRAPHICS_RENDER_TARGET |
+                       USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
+                       USAGE_IO_INPUT |
+                       USAGE_IO_OUTPUT)) != 0) {
             throw new RSIllegalArgumentException("Unknown usage specified.");
         }
+
+        if ((usage & (USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE | USAGE_IO_INPUT)) != 0) {
+            mWriteAllowed = false;
+
+            if ((usage & ~(USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
+                           USAGE_IO_INPUT |
+                           USAGE_GRAPHICS_TEXTURE |
+                           USAGE_SCRIPT)) != 0) {
+                throw new RSIllegalArgumentException("Invalid usage combination.");
+            }
+        }
+
         mType = t;
+        mUsage = usage;
 
         if (t != null) {
             updateCacheInfo(t);
@@ -876,7 +921,31 @@
         if (type.getID() == 0) {
             throw new RSInvalidStateException("Bad Type");
         }
-        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage);
+        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, 0);
+        if (id == 0) {
+            throw new RSRuntimeException("Allocation creation failed.");
+        }
+        return new Allocation(id, rs, type, usage);
+    }
+
+    /**
+     * @hide
+     * This API is hidden and only intended to be used for
+     * transitional purposes.
+     *
+     * @param type renderscript type describing data layout
+     * @param mips specifies desired mipmap behaviour for the
+     *             allocation
+     * @param usage bit field specifying how the allocation is
+     *              utilized
+     */
+    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips,
+                                         int usage, int pointer) {
+        rs.validate();
+        if (type.getID() == 0) {
+            throw new RSInvalidStateException("Bad Type");
+        }
+        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, pointer);
         if (id == 0) {
             throw new RSRuntimeException("Allocation creation failed.");
         }
@@ -931,7 +1000,7 @@
         b.setX(count);
         Type t = b.create();
 
-        int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage);
+        int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage, 0);
         if (id == 0) {
             throw new RSRuntimeException("Allocation creation failed.");
         }
@@ -1006,6 +1075,23 @@
     }
 
     /**
+     *
+     *
+     * @hide
+     *
+     */
+    public SurfaceTexture getSurfaceTexture() {
+        if ((mUsage & USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) == 0) {
+            throw new RSInvalidStateException("Allocation is not a surface texture.");
+        }
+
+        int id = mRS.nAllocationGetSurfaceTextureID(getID());
+        return new SurfaceTexture(id);
+
+    }
+
+
+    /**
      * Creates a non-mipmapped renderscript allocation to use as a
      * graphics texture
      *
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 22ef7bb..f6a0281 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -54,26 +54,59 @@
     int[] mArraySizes;
     int[] mOffsetInBytes;
 
+    int[] mVisibleElementMap;
+
     DataType mType;
     DataKind mKind;
     boolean mNormalized;
     int mVectorSize;
 
+    private void updateVisibleSubElements() {
+        if (mElements == null) {
+            return;
+        }
+
+        int noPaddingFieldCount = 0;
+        int fieldCount = mElementNames.length;
+        // Find out how many elements are not padding
+        for (int ct = 0; ct < fieldCount; ct ++) {
+            if (mElementNames[ct].charAt(0) != '#') {
+                noPaddingFieldCount ++;
+            }
+        }
+        mVisibleElementMap = new int[noPaddingFieldCount];
+
+        // Make a map that points us at non-padding elements
+        for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) {
+            if (mElementNames[ct].charAt(0) != '#') {
+                mVisibleElementMap[ctNoPadding ++] = ct;
+            }
+        }
+    }
+
     /**
     * @hide
     * @return element size in bytes
     */
     public int getSizeBytes() {return mSize;}
 
+    /**
+    * @hide
+    * @return element vector size
+    */
+    public int getVectorSize() {return mVectorSize;}
+
 
     /**
      * DataType represents the basic type information for a basic element.  The
-     * naming convention follows.  For numeric types its FLOAT, SIGNED, UNSIGNED
-     * followed by the _BITS where BITS is the size of the data.  BOOLEAN is a
-     * true / false (1,0) represented in an 8 bit container.  The UNSIGNED
-     * variants with multiple bit definitions are for packed graphical data
-     * formats and represents vectors with per vector member sizes which are
-     * treated as a single unit for packing and alignment purposes.
+     * naming convention follows.  For numeric types it is FLOAT,
+     * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
+     * size of the data.  BOOLEAN is a true / false (1,0)
+     * represented in an 8 bit container.  The UNSIGNED variants
+     * with multiple bit definitions are for packed graphical data
+     * formats and represent vectors with per vector member sizes
+     * which are treated as a single unit for packing and alignment
+     * purposes.
      *
      * MATRIX the three matrix types contain FLOAT_32 elements and are treated
      * as 32 bits for alignment purposes.
@@ -81,6 +114,11 @@
      * RS_* objects.  32 bit opaque handles.
      */
     public enum DataType {
+        /**
+        * @hide
+        * new enum
+        */
+        NONE (0, 0),
         //FLOAT_16 (1, 2),
         FLOAT_32 (2, 4),
         FLOAT_64 (3, 8),
@@ -167,10 +205,10 @@
     * @return number of sub-elements in this element
     */
     public int getSubElementCount() {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             return 0;
         }
-        return mElements.length;
+        return mVisibleElementMap.length;
     }
 
     /**
@@ -179,13 +217,13 @@
     * @return sub-element in this element at given index
     */
     public Element getSubElement(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mElements[index];
+        return mElements[mVisibleElementMap[index]];
     }
 
     /**
@@ -194,13 +232,13 @@
     * @return sub-element in this element at given index
     */
     public String getSubElementName(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mElementNames[index];
+        return mElementNames[mVisibleElementMap[index]];
     }
 
     /**
@@ -209,13 +247,13 @@
     * @return array size of sub-element in this element at given index
     */
     public int getSubElementArraySize(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mArraySizes[index];
+        return mArraySizes[mVisibleElementMap[index]];
     }
 
     /**
@@ -224,13 +262,29 @@
     * @return offset in bytes of sub-element in this element at given index
     */
     public int getSubElementOffsetBytes(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mOffsetInBytes[index];
+        return mOffsetInBytes[mVisibleElementMap[index]];
+    }
+
+    /**
+    * @hide
+    * @return element data type
+    */
+    public DataType getDataType() {
+        return mType;
+    }
+
+    /**
+    * @hide
+    * @return element data kind
+    */
+    public DataKind getDataKind() {
+        return mKind;
     }
 
     /**
@@ -681,14 +735,18 @@
     Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) {
         super(id, rs);
         mSize = 0;
+        mVectorSize = 1;
         mElements = e;
         mElementNames = n;
         mArraySizes = as;
+        mType = DataType.NONE;
+        mKind = DataKind.USER;
         mOffsetInBytes = new int[mElements.length];
         for (int ct = 0; ct < mElements.length; ct++ ) {
             mOffsetInBytes[ct] = mSize;
             mSize += mElements[ct].mSize * mArraySizes[ct];
         }
+        updateVisibleSubElements();
     }
 
     Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
@@ -753,7 +811,7 @@
                 mSize += mElements[i].mSize * mArraySizes[i];
             }
         }
-
+        updateVisibleSubElements();
     }
 
     /**
diff --git a/graphics/java/android/renderscript/Path.java b/graphics/java/android/renderscript/Path.java
new file mode 100644
index 0000000..83ae150
--- /dev/null
+++ b/graphics/java/android/renderscript/Path.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.util.Vector;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ */
+public class Path extends BaseObj {
+
+    public enum Primitive {
+        QUADRATIC_BEZIER(0),
+        CUBIC_BEZIER(1);
+
+        int mID;
+        Primitive(int id) {
+            mID = id;
+        }
+    }
+
+    Allocation mVertexBuffer;
+    Allocation mLoopBuffer;
+    Primitive mPrimitive;
+    float mQuality;
+    boolean mCoverageToAlpha;
+
+    Path(int id, RenderScript rs, Primitive p, Allocation vtx, Allocation loop, float q) {
+        super(id, rs);
+        mVertexBuffer = vtx;
+        mLoopBuffer = loop;
+        mPrimitive = p;
+        mQuality = q;
+    }
+
+    public Allocation getVertexAllocation() {
+        return mVertexBuffer;
+    }
+
+    public Allocation getLoopAllocation() {
+        return mLoopBuffer;
+    }
+
+    public Primitive getPrimitive() {
+        return mPrimitive;
+    }
+
+    @Override
+    void updateFromNative() {
+    }
+
+
+    public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx) {
+        int id = rs.nPathCreate(p.mID, false, vtx.getID(), 0, quality);
+        Path newPath = new Path(id, rs, p, null, null, quality);
+        return newPath;
+    }
+
+    public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) {
+        return null;
+    }
+
+    public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx) {
+        return null;
+    }
+
+    public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) {
+        return null;
+    }
+
+
+}
+
+
diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java
index a1b1ba3..3f769ee 100644
--- a/graphics/java/android/renderscript/Program.java
+++ b/graphics/java/android/renderscript/Program.java
@@ -77,6 +77,40 @@
     }
 
     /**
+     * @hide
+     */
+    public int getConstantCount() {
+        return mConstants != null ? mConstants.length : 0;
+    }
+
+    /**
+     * @hide
+     */
+    public Type getConstant(int slot) {
+        if (slot < 0 || slot >= mConstants.length) {
+            throw new IllegalArgumentException("Slot ID out of range.");
+        }
+        return mConstants[slot];
+    }
+
+    /**
+     * @hide
+     */
+    public int getTextureCount() {
+        return mTextureCount;
+    }
+
+    /**
+     * @hide
+     */
+    public TextureType getTextureType(int slot) {
+        if ((slot < 0) || (slot >= mTextureCount)) {
+            throw new IllegalArgumentException("Slot ID out of range.");
+        }
+        return mTextures[slot];
+    }
+
+    /**
      * Binds a constant buffer to be used as uniform inputs to the
      * program
      *
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index 56bb836..b3c1bd9 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -55,6 +55,23 @@
     }
 
     /**
+     * @hide
+     */
+    public int getInputCount() {
+        return mInputs != null ? mInputs.length : 0;
+    }
+
+    /**
+     * @hide
+     */
+    public Element getInput(int slot) {
+        if (slot < 0 || slot >= mInputs.length) {
+            throw new IllegalArgumentException("Slot ID out of range.");
+        }
+        return mInputs[slot];
+    }
+
+    /**
     * Builder class for creating ProgramVertex objects.
     * The builder starts empty and the user must minimally provide
     * the GLSL shader code, and the varying inputs. Constant, or
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index bfe412c..d3c801f2 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -231,10 +231,10 @@
         rsnTypeGetNativeData(mContext, id, typeData);
     }
 
-    native int  rsnAllocationCreateTyped(int con, int type, int mip, int usage);
-    synchronized int nAllocationCreateTyped(int type, int mip, int usage) {
+    native int  rsnAllocationCreateTyped(int con, int type, int mip, int usage, int pointer);
+    synchronized int nAllocationCreateTyped(int type, int mip, int usage, int pointer) {
         validate();
-        return rsnAllocationCreateTyped(mContext, type, mip, usage);
+        return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
     }
     native int  rsnAllocationCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage);
     synchronized int nAllocationCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) {
@@ -269,6 +269,12 @@
         validate();
         rsnAllocationSyncAll(mContext, alloc, src);
     }
+    native int rsnAllocationGetSurfaceTextureID(int con, int alloc);
+    synchronized int nAllocationGetSurfaceTextureID(int alloc) {
+        validate();
+        return rsnAllocationGetSurfaceTextureID(mContext, alloc);
+    }
+
     native void rsnAllocationGenerateMipmaps(int con, int alloc);
     synchronized void nAllocationGenerateMipmaps(int alloc) {
         validate();
@@ -584,6 +590,11 @@
         rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
     }
 
+    native int  rsnPathCreate(int con, int prim, boolean isStatic, int vtx, int loop, float q);
+    synchronized int nPathCreate(int prim, boolean isStatic, int vtx, int loop, float q) {
+        validate();
+        return rsnPathCreate(mContext, prim, isStatic, vtx, loop, q);
+    }
 
     int     mDev;
     int     mContext;
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 9622bd2..94f19b3 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -430,10 +430,10 @@
 // -----------------------------------
 
 static jint
-nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage)
+nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage, jint pointer)
 {
-    LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i)", con, (RsElement)type, mips, usage);
-    return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage);
+    LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)", con, (RsElement)type, mips, usage, (void *)pointer);
+    return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uint32_t)pointer);
 }
 
 static void
@@ -443,6 +443,13 @@
     rsAllocationSyncAll(con, (RsAllocation)a, (RsAllocationUsageType)bits);
 }
 
+static jint
+nAllocationGetSurfaceTextureID(JNIEnv *_env, jobject _this, RsContext con, jint a)
+{
+    LOG_API("nAllocationGetSurfaceTextureID, con(%p), a(%p)", con, (RsAllocation)a);
+    return rsAllocationGetSurfaceTextureID(con, (RsAllocation)a);
+}
+
 static void
 nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, RsContext con, jint alloc)
 {
@@ -1122,6 +1129,17 @@
 
 // ---------------------------------------------------------------------------
 
+//native int  rsnPathCreate(int con, int prim, boolean isStatic, int vtx, int loop, float q);
+static jint
+nPathCreate(JNIEnv *_env, jobject _this, RsContext con, jint prim, jboolean isStatic, jint _vtx, jint _loop, jfloat q) {
+    LOG_API("nPathCreate, con(%p)", con);
+
+    int id = (int)rsPathCreate(con, (RsPathPrimitive)prim, isStatic,
+                               (RsAllocation)_vtx,
+                               (RsAllocation)_loop, q);
+    return id;
+}
+
 static jint
 nMeshCreate(JNIEnv *_env, jobject _this, RsContext con, jintArray _vtx, jintArray _idx, jintArray _prim)
 {
@@ -1250,7 +1268,7 @@
 {"rsnTypeCreate",                    "(IIIIIZZ)I",                            (void*)nTypeCreate },
 {"rsnTypeGetNativeData",             "(II[I)V",                               (void*)nTypeGetNativeData },
 
-{"rsnAllocationCreateTyped",         "(IIII)I",                               (void*)nAllocationCreateTyped },
+{"rsnAllocationCreateTyped",         "(IIIII)I",                               (void*)nAllocationCreateTyped },
 {"rsnAllocationCreateFromBitmap",    "(IIILandroid/graphics/Bitmap;I)I",      (void*)nAllocationCreateFromBitmap },
 {"rsnAllocationCubeCreateFromBitmap","(IIILandroid/graphics/Bitmap;I)I",      (void*)nAllocationCubeCreateFromBitmap },
 
@@ -1258,6 +1276,7 @@
 {"rsnAllocationCopyToBitmap",        "(IILandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyToBitmap },
 
 {"rsnAllocationSyncAll",             "(III)V",                                (void*)nAllocationSyncAll },
+{"rsnAllocationGetSurfaceTextureID", "(II)I",                                 (void*)nAllocationGetSurfaceTextureID },
 {"rsnAllocationData1D",              "(IIIII[II)V",                           (void*)nAllocationData1D_i },
 {"rsnAllocationData1D",              "(IIIII[SI)V",                           (void*)nAllocationData1D_s },
 {"rsnAllocationData1D",              "(IIIII[BI)V",                           (void*)nAllocationData1D_b },
@@ -1310,6 +1329,7 @@
 
 {"rsnSamplerCreate",                 "(IIIIIIF)I",                            (void*)nSamplerCreate },
 
+{"rsnPathCreate",                    "(IIZIIF)I",                             (void*)nPathCreate },
 {"rsnMeshCreate",                    "(I[I[I[I)I",                            (void*)nMeshCreate },
 
 {"rsnMeshGetVertexBufferCount",      "(II)I",                                 (void*)nMeshGetVertexBufferCount },
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 2166ce7..9c5d06b 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -95,6 +95,7 @@
 	rsMatrix4x4.cpp \
 	rsMesh.cpp \
 	rsMutex.cpp \
+	rsPath.cpp \
 	rsProgram.cpp \
 	rsProgramFragment.cpp \
 	rsProgramStore.cpp \
@@ -117,6 +118,7 @@
 	driver/rsdGL.cpp \
 	driver/rsdMesh.cpp \
 	driver/rsdMeshObj.cpp \
+	driver/rsdPath.cpp \
 	driver/rsdProgram.cpp \
 	driver/rsdProgramRaster.cpp \
 	driver/rsdProgramStore.cpp \
@@ -201,6 +203,7 @@
 	rsMatrix4x4.cpp \
 	rsMesh.cpp \
 	rsMutex.cpp \
+	rsPath.cpp \
 	rsProgram.cpp \
 	rsProgramFragment.cpp \
 	rsProgramStore.cpp \
diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/RenderScriptDefines.h
index d092520..990ef26 100644
--- a/libs/rs/RenderScriptDefines.h
+++ b/libs/rs/RenderScriptDefines.h
@@ -41,6 +41,7 @@
 typedef void * RsSampler;
 typedef void * RsScript;
 typedef void * RsMesh;
+typedef void * RsPath;
 typedef void * RsType;
 typedef void * RsObjectBase;
 
@@ -99,8 +100,11 @@
     RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004,
     RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008,
     RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET = 0x0010,
+    RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020,
+    RS_ALLOCATION_USAGE_IO_INPUT = 0x0040,
+    RS_ALLOCATION_USAGE_IO_OUTPUT = 0x0080,
 
-    RS_ALLOCATION_USAGE_ALL = 0x000F
+    RS_ALLOCATION_USAGE_ALL = 0x00FF
 };
 
 enum RsAllocationMipmapControl {
@@ -152,6 +156,8 @@
     RS_TYPE_PROGRAM_VERTEX,
     RS_TYPE_PROGRAM_RASTER,
     RS_TYPE_PROGRAM_STORE,
+
+    RS_TYPE_INVALID = 10000,
 };
 
 enum RsDataKind {
@@ -163,6 +169,8 @@
     RS_KIND_PIXEL_RGB,
     RS_KIND_PIXEL_RGBA,
     RS_KIND_PIXEL_DEPTH,
+
+    RS_KIND_INVALID = 100,
 };
 
 enum RsSamplerParam {
@@ -181,6 +189,8 @@
     RS_SAMPLER_WRAP,
     RS_SAMPLER_CLAMP,
     RS_SAMPLER_LINEAR_MIP_NEAREST,
+
+    RS_SAMPLER_INVALID = 100,
 };
 
 enum RsTextureTarget {
@@ -221,7 +231,8 @@
     RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,   // 5
     RS_BLEND_SRC_DST_ALPHA,             // 6
     RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,   // 7
-    RS_BLEND_SRC_SRC_ALPHA_SATURATE     // 8
+    RS_BLEND_SRC_SRC_ALPHA_SATURATE,    // 8
+    RS_BLEND_SRC_INVALID = 100,
 };
 
 enum RsBlendDstFunc {
@@ -232,7 +243,9 @@
     RS_BLEND_DST_SRC_ALPHA,             // 4
     RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,   // 5
     RS_BLEND_DST_DST_ALPHA,             // 6
-    RS_BLEND_DST_ONE_MINUS_DST_ALPHA    // 7
+    RS_BLEND_DST_ONE_MINUS_DST_ALPHA,   // 7
+
+    RS_BLEND_DST_INVALID = 100,
 };
 
 enum RsTexEnvMode {
@@ -255,7 +268,14 @@
     RS_PRIMITIVE_LINE_STRIP,
     RS_PRIMITIVE_TRIANGLE,
     RS_PRIMITIVE_TRIANGLE_STRIP,
-    RS_PRIMITIVE_TRIANGLE_FAN
+    RS_PRIMITIVE_TRIANGLE_FAN,
+
+    RS_PRIMITIVE_INVALID = 100,
+};
+
+enum RsPathPrimitive {
+    RS_PATH_PRIMITIVE_QUADRATIC_BEZIER,
+    RS_PATH_PRIMITIVE_CUBIC_BEZIER
 };
 
 enum RsError {
@@ -309,7 +329,8 @@
 enum RsCullMode {
     RS_CULL_BACK,
     RS_CULL_FRONT,
-    RS_CULL_NONE
+    RS_CULL_NONE,
+    RS_CULL_INVALID = 100,
 };
 
 typedef struct {
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index 1f70e66..ea92192 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -134,6 +134,13 @@
 static void UploadToTexture(const Context *rsc, const Allocation *alloc) {
     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
 
+    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) {
+        if (!drv->textureID) {
+            RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
+        }
+        return;
+    }
+
     if (!drv->glType || !drv->glFormat) {
         return;
     }
@@ -212,10 +219,13 @@
         return false;
     }
 
-    void * ptr = malloc(alloc->mHal.state.type->getSizeBytes());
+    void * ptr = alloc->mHal.state.usrPtr;
     if (!ptr) {
-        free(drv);
-        return false;
+        ptr = malloc(alloc->mHal.state.type->getSizeBytes());
+        if (!ptr) {
+            free(drv);
+            return false;
+        }
     }
 
     drv->glTarget = GL_NONE;
@@ -269,7 +279,7 @@
         drv->renderTargetID = 0;
     }
 
-    if (drv->mallocPtr) {
+    if (drv->mallocPtr && !alloc->mHal.state.usrPtr) {
         free(drv->mallocPtr);
         drv->mallocPtr = NULL;
     }
@@ -370,6 +380,12 @@
     drv->uploadDeferred = true;
 }
 
+int32_t rsdAllocationInitSurfaceTexture(const Context *rsc, const Allocation *alloc) {
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+    UploadToTexture(rsc, alloc);
+    return drv->textureID;
+}
+
 void rsdAllocationData1D(const Context *rsc, const Allocation *alloc,
                          uint32_t xoff, uint32_t lod, uint32_t count,
                          const void *data, uint32_t sizeBytes) {
diff --git a/libs/rs/driver/rsdAllocation.h b/libs/rs/driver/rsdAllocation.h
index 4fc4419..230804b 100644
--- a/libs/rs/driver/rsdAllocation.h
+++ b/libs/rs/driver/rsdAllocation.h
@@ -67,6 +67,8 @@
                           RsAllocationUsageType src);
 void rsdAllocationMarkDirty(const android::renderscript::Context *rsc,
                             const android::renderscript::Allocation *alloc);
+int32_t rsdAllocationInitSurfaceTexture(const android::renderscript::Context *rsc,
+                                        const android::renderscript::Allocation *alloc);
 
 void rsdAllocationData1D(const android::renderscript::Context *rsc,
                          const android::renderscript::Allocation *alloc,
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 1a535d0..e011955 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -18,6 +18,7 @@
 #include "rsdAllocation.h"
 #include "rsdBcc.h"
 #include "rsdGL.h"
+#include "rsdPath.h"
 #include "rsdProgramStore.h"
 #include "rsdProgramRaster.h"
 #include "rsdProgramVertex.h"
@@ -72,6 +73,7 @@
         rsdAllocationResize,
         rsdAllocationSyncAll,
         rsdAllocationMarkDirty,
+        rsdAllocationInitSurfaceTexture,
         rsdAllocationData1D,
         rsdAllocationData2D,
         rsdAllocationData3D,
@@ -114,6 +116,13 @@
     },
 
     {
+        rsdPathInitStatic,
+        rsdPathInitDynamic,
+        rsdPathDraw,
+        rsdPathDestroy
+    },
+
+    {
         rsdSamplerInit,
         rsdSamplerDestroy
     },
@@ -259,6 +268,9 @@
     for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
         setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority);
     }
+    if (dc->mHasGraphics) {
+        rsdGLSetPriority(rsc, priority);
+    }
 }
 
 void Shutdown(Context *rsc) {
diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h
index 126c87a..168bdf3 100644
--- a/libs/rs/driver/rsdCore.h
+++ b/libs/rs/driver/rsdCore.h
@@ -41,6 +41,7 @@
 typedef struct RsdHalRec {
     uint32_t version_major;
     uint32_t version_minor;
+    bool mHasGraphics;
 
     struct Workers {
         volatile int mRunningCount;
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 368dd710..b136cc7 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -361,6 +361,7 @@
     dc->gl.vertexArrayState = new RsdVertexArrayState();
     dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
     dc->gl.currentFrameBuffer = NULL;
+    dc->mHasGraphics = true;
 
     ALOGV("%p initGLThread end", rsc);
     rsc->setWatchdogGL(NULL, 0, NULL);
@@ -421,6 +422,15 @@
     RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
 }
 
+void rsdGLSetPriority(const Context *rsc, int32_t priority) {
+    if (priority > 0) {
+        // Mark context as low priority.
+        ALOGV("low pri");
+    } else {
+        ALOGV("normal pri");
+    }
+}
+
 void rsdGLCheckError(const android::renderscript::Context *rsc,
                      const char *msg, bool isFatal) {
     GLenum err = glGetError();
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 51893c3..e015cb1 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -82,6 +82,8 @@
 void rsdGLSwap(const android::renderscript::Context *rsc);
 void rsdGLCheckError(const android::renderscript::Context *rsc,
                      const char *msg, bool isFatal = false);
+void rsdGLSetPriority(const android::renderscript::Context *rsc,
+                      int32_t priority);
 
 #endif
 
diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp
index eb62ddb..50daf3e 100644
--- a/libs/rs/driver/rsdMesh.cpp
+++ b/libs/rs/driver/rsdMesh.cpp
@@ -35,7 +35,7 @@
     }
     drv = new RsdMeshObj(rsc, m);
     m->mHal.drv = drv;
-    return drv->init();
+    return drv->init(rsc);
 }
 
 void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) {
diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
index 99d79dc..893f046 100644
--- a/libs/rs/driver/rsdMeshObj.cpp
+++ b/libs/rs/driver/rsdMeshObj.cpp
@@ -50,14 +50,9 @@
 }
 
 bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
-    // Do not create attribs for padding
-    if (elem->getFieldName(fieldIdx)[0] == '#') {
-        return false;
-    }
-
     // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
     // Filter rs types accordingly
-    RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
+    RsDataType dt = elem->mHal.state.fields[fieldIdx]->mHal.state.dataType;
     if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
         dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
         dt != RS_TYPE_SIGNED_16) {
@@ -65,7 +60,7 @@
     }
 
     // Now make sure they are not arrays
-    uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
+    uint32_t arraySize = elem->mHal.state.fieldArraySizes[fieldIdx];
     if (arraySize != 1) {
         return false;
     }
@@ -73,15 +68,15 @@
     return true;
 }
 
-bool RsdMeshObj::init() {
+bool RsdMeshObj::init(const Context *rsc) {
 
-    updateGLPrimitives();
+    updateGLPrimitives(rsc);
 
     // Count the number of gl attrs to initialize
     mAttribCount = 0;
     for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
         const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
-        for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
+        for (uint32_t ct=0; ct < elem->mHal.state.fieldsCount; ct++) {
             if (isValidGLComponent(elem, ct)) {
                 mAttribCount ++;
             }
@@ -104,21 +99,21 @@
     uint32_t userNum = 0;
     for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
         const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
-        uint32_t stride = elem->getSizeBytes();
-        for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
-            const Component &c = elem->getField(fieldI)->getComponent();
+        uint32_t stride = elem->mHal.state.elementSizeBytes;
+        for (uint32_t fieldI=0; fieldI < elem->mHal.state.fieldsCount; fieldI++) {
+            const Element *f = elem->mHal.state.fields[fieldI];
 
             if (!isValidGLComponent(elem, fieldI)) {
                 continue;
             }
 
-            mAttribs[userNum].size = c.getVectorSize();
-            mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
-            mAttribs[userNum].type = rsdTypeToGLType(c.getType());
-            mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+            mAttribs[userNum].size = f->mHal.state.vectorSize;
+            mAttribs[userNum].offset = elem->mHal.state.fieldOffsetBytes[fieldI];
+            mAttribs[userNum].type = rsdTypeToGLType(f->mHal.state.dataType);
+            mAttribs[userNum].normalized = f->mHal.state.dataType != RS_TYPE_FLOAT_32;
             mAttribs[userNum].stride = stride;
             String8 tmp(RS_SHADER_ATTR);
-            tmp.append(elem->getFieldName(fieldI));
+            tmp.append(elem->mHal.state.fieldNames[fieldI]);
             mAttribs[userNum].name.setTo(tmp.string());
 
             // Remember which allocation this attribute came from
@@ -133,7 +128,7 @@
 void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex,
                                       uint32_t start, uint32_t len) const {
     if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) {
-        ALOGE("Invalid mesh or parameters");
+        rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid mesh or parameters");
         return;
     }
 
@@ -186,7 +181,7 @@
     rsdGLCheckError(rsc, "Mesh::renderPrimitiveRange");
 }
 
-void RsdMeshObj::updateGLPrimitives() {
+void RsdMeshObj::updateGLPrimitives(const Context *rsc) {
     mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount];
     for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) {
         switch (mRSMesh->mHal.state.primitives[i]) {
@@ -196,6 +191,7 @@
             case RS_PRIMITIVE_TRIANGLE:       mGLPrimitives[i] = GL_TRIANGLES; break;
             case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break;
             case RS_PRIMITIVE_TRIANGLE_FAN:   mGLPrimitives[i] = GL_TRIANGLE_FAN; break;
+            default: rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid mesh primitive"); break;
         }
     }
 }
diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h
index 8b1271b..1370f01 100644
--- a/libs/rs/driver/rsdMeshObj.h
+++ b/libs/rs/driver/rsdMeshObj.h
@@ -37,15 +37,16 @@
             const android::renderscript::Mesh *);
     ~RsdMeshObj();
 
-    void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
+    void renderPrimitiveRange(const android::renderscript::Context *,
+                              uint32_t primIndex, uint32_t start, uint32_t len) const;
 
-    bool init();
+    bool init(const android::renderscript::Context *rsc);
 
 protected:
     const android::renderscript::Mesh *mRSMesh;
 
     uint32_t *mGLPrimitives;
-    void updateGLPrimitives();
+    void updateGLPrimitives(const android::renderscript::Context *rsc);
 
     bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx);
     // Attribues that allow us to map to GL
diff --git a/libs/rs/driver/rsdPath.cpp b/libs/rs/driver/rsdPath.cpp
new file mode 100644
index 0000000..e04bc02
--- /dev/null
+++ b/libs/rs/driver/rsdPath.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES/glext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsPath.h>
+
+#include "rsdCore.h"
+#include "rsdPath.h"
+#include "rsdAllocation.h"
+#include "rsdGL.h"
+#include "rsdVertexArray.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+class DrvPath {
+protected:
+    DrvPath();
+public:
+    virtual ~DrvPath();
+    virtual void draw(Context *) = 0;
+};
+
+class DrvPathStatic : public DrvPath {
+public:
+    typedef struct {
+        float x1, xc, x2;
+        float y1, yc, y2;
+    } segment_t;
+
+    segment_t *mSegments;
+    uint32_t mSegmentCount;
+
+    DrvPathStatic(const Allocation *vtx, const Allocation *loops);
+    virtual ~DrvPathStatic();
+
+    virtual void draw(Context *);
+};
+
+class DrvPathDynamic : public DrvPath {
+public:
+    DrvPathDynamic();
+    virtual ~DrvPathDynamic();
+};
+
+static void cleanup(const Context *rsc, const Path *m) {
+    DrvPath *dp = (DrvPath *)m->mHal.drv;
+    if (dp) {
+        delete dp;
+    }
+}
+
+bool rsdPathInitStatic(const Context *rsc, const Path *m,
+                       const Allocation *vtx, const Allocation *loops) {
+    DrvPathStatic *drv = NULL;
+    cleanup(rsc, m);
+
+    DrvPathStatic *dps = new DrvPathStatic(vtx, loops);
+    //LOGE("init path m %p,  %p", m, dps);
+    m->mHal.drv = dps;
+    return dps != NULL;
+}
+
+bool rsdPathInitDynamic(const Context *rsc, const Path *m) {
+    return false;
+}
+
+
+void rsdPathDraw(const Context *rsc, const Path *m) {
+    //LOGE("render m=%p", m);
+
+    DrvPath *drv = (DrvPath *)m->mHal.drv;
+    if(drv) {
+        //LOGE("render 2 drv=%p", drv);
+        drv->draw((Context *)rsc);
+    }
+}
+
+void rsdPathDestroy(const Context *rsc, const Path *m) {
+    cleanup(rsc, m);
+    m->mHal.drv = NULL;
+}
+
+
+
+
+DrvPath::DrvPath() {
+}
+
+DrvPath::~DrvPath() {
+}
+
+DrvPathStatic::DrvPathStatic(const Allocation *vtx, const Allocation *loops) {
+    mSegmentCount = vtx->getType()->getDimX() / 3;
+    mSegments = new segment_t[mSegmentCount];
+
+    const float *fin = (const float *)vtx->getPtr();
+    for (uint32_t ct=0; ct < mSegmentCount; ct++) {
+        segment_t *s = &mSegments[ct];
+        s->x1 = fin[0];
+        s->y1 = fin[1];
+
+        s->xc = fin[2];
+        s->yc = fin[3];
+
+        s->x2 = fin[4];
+        s->y2 = fin[5];
+        fin += 6;
+    }
+}
+
+DrvPathStatic::~DrvPathStatic() {
+}
+
+void DrvPathStatic::draw(Context *rsc) {
+    const static float color[24] = {
+        1.f, 0.f, 0.f, 1.f,  0.5f, 0.f, 0.f, 1.f,
+        1.f, 0.f, 0.f, 1.f,  0.5f, 0.f, 0.f, 1.f,
+        1.f, 1.f, 1.f, 1.f,  1.f, 1.f, 1.f, 1.f};
+    float vtx[12];
+
+    //LOGE("draw");
+    if (!rsc->setupCheck()) {
+        return;
+    }
+
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+    if (!dc->gl.shaderCache->setup(rsc)) {
+        return;
+    }
+
+    RsdVertexArray::Attrib attribs[2];
+    attribs[0].set(GL_FLOAT, 2, 8, false, (uint32_t)vtx, "ATTRIB_position");
+    attribs[1].set(GL_FLOAT, 4, 16, false, (uint32_t)color, "ATTRIB_color");
+    RsdVertexArray va(attribs, 2);
+    va.setup(rsc);
+
+    //LOGE("mSegmentCount %i", mSegmentCount);
+    for (uint32_t ct=0; ct < mSegmentCount; ct++) {
+        segment_t *s = &mSegments[ct];
+
+        vtx[0] = s->x1;
+        vtx[1] = s->y1;
+        vtx[2] = s->xc;
+        vtx[3] = s->yc;
+
+        vtx[4] = s->x2;
+        vtx[5] = s->y2;
+        vtx[6] = s->xc;
+        vtx[7] = s->yc;
+
+        vtx[8] = s->x1;
+        vtx[9] = s->y1;
+        vtx[10] = s->x2;
+        vtx[11] = s->y2;
+
+        RSD_CALL_GL(glDrawArrays, GL_LINES, 0, 6);
+    }
+
+}
+
+DrvPathDynamic::DrvPathDynamic() {
+}
+
+DrvPathDynamic::~DrvPathDynamic() {
+}
diff --git a/libs/rs/driver/rsdPath.h b/libs/rs/driver/rsdPath.h
new file mode 100644
index 0000000..fa00972
--- /dev/null
+++ b/libs/rs/driver/rsdPath.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSD_PATH_H
+#define RSD_PATH_H
+
+#include <rs_hal.h>
+
+
+bool rsdPathInitStatic(const android::renderscript::Context *rsc,
+                       const android::renderscript::Path *m,
+                       const android::renderscript::Allocation *vertex,
+                       const android::renderscript::Allocation *loops);
+bool rsdPathInitDynamic(const android::renderscript::Context *rsc,
+                        const android::renderscript::Path *m);
+void rsdPathDraw(const android::renderscript::Context *rsc,
+                 const android::renderscript::Path *m);
+void rsdPathDestroy(const android::renderscript::Context *rsc,
+                    const android::renderscript::Path *m);
+
+
+#endif
diff --git a/libs/rs/driver/rsdProgramRaster.cpp b/libs/rs/driver/rsdProgramRaster.cpp
index b493759..e5a0291 100644
--- a/libs/rs/driver/rsdProgramRaster.cpp
+++ b/libs/rs/driver/rsdProgramRaster.cpp
@@ -45,6 +45,9 @@
         case RS_CULL_NONE:
             RSD_CALL_GL(glDisable, GL_CULL_FACE);
             break;
+        default:
+            rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid cull type");
+            break;
     }
 
 }
diff --git a/libs/rs/driver/rsdProgramStore.cpp b/libs/rs/driver/rsdProgramStore.cpp
index fca9ba9..c1295e8 100644
--- a/libs/rs/driver/rsdProgramStore.cpp
+++ b/libs/rs/driver/rsdProgramStore.cpp
@@ -111,7 +111,7 @@
         drv->blendSrc = GL_SRC_ALPHA_SATURATE;
         break;
     default:
-        ALOGE("Unknown blend src mode.");
+        rsc->setError(RS_ERROR_FATAL_DRIVER, "Unknown blend src mode.");
         goto error;
     }
 
@@ -141,7 +141,7 @@
         drv->blendDst = GL_ONE_MINUS_DST_ALPHA;
         break;
     default:
-        ALOGE("Unknown blend dst mode.");
+        rsc->setError(RS_ERROR_FATAL_DRIVER, "Unknown blend dst mode.");
         goto error;
     }
 
diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp
index 14c2970..44bfb1c 100644
--- a/libs/rs/driver/rsdRuntimeStubs.cpp
+++ b/libs/rs/driver/rsdRuntimeStubs.cpp
@@ -25,6 +25,7 @@
 #include "rsdCore.h"
 
 #include "rsdRuntime.h"
+#include "rsdPath.h"
 
 #include <time.h>
 
@@ -89,6 +90,16 @@
     rsrBindTexture(rsc, sc, pf, slot, a);
 }
 
+static void SC_BindVertexConstant(ProgramVertex *pv, uint32_t slot, Allocation *a) {
+    GET_TLS();
+    rsrBindConstant(rsc, sc, pv, slot, a);
+}
+
+static void SC_BindFragmentConstant(ProgramFragment *pf, uint32_t slot, Allocation *a) {
+    GET_TLS();
+    rsrBindConstant(rsc, sc, pf, slot, a);
+}
+
 static void SC_BindSampler(ProgramFragment *pf, uint32_t slot, Sampler *s) {
     GET_TLS();
     rsrBindSampler(rsc, sc, pf, slot, s);
@@ -204,6 +215,12 @@
     rsrDrawRect(rsc, sc, x1, y1, x2, y2, z);
 }
 
+static void SC_DrawPath(Path *p) {
+    GET_TLS();
+    //rsrDrawPath(rsc, sc, p);
+    rsdPathDraw(rsc, p);
+}
+
 static void SC_DrawMesh(Mesh *m) {
     GET_TLS();
     rsrDrawMesh(rsc, sc, m);
@@ -533,6 +550,10 @@
     { "_Z13rsClearObjectP9rs_script", (void *)&SC_ClearObject, true },
     { "_Z10rsIsObject9rs_script", (void *)&SC_IsObject, true },
 
+    { "_Z11rsSetObjectP7rs_pathS_", (void *)&SC_SetObject, true },
+    { "_Z13rsClearObjectP7rs_path", (void *)&SC_ClearObject, true },
+    { "_Z10rsIsObject7rs_path", (void *)&SC_IsObject, true },
+
     { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_SetObject, true },
     { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_ClearObject, true },
     { "_Z10rsIsObject7rs_mesh", (void *)&SC_IsObject, true },
@@ -580,6 +601,8 @@
     { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_BindProgramRaster, false },
     { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_BindSampler, false },
     { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_BindTexture, false },
+    { "_Z15rsgBindConstant19rs_program_fragmentj13rs_allocation", (void *)&SC_BindFragmentConstant, false },
+    { "_Z15rsgBindConstant17rs_program_vertexj13rs_allocation", (void *)&SC_BindVertexConstant, false },
 
     { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadProjectionMatrix, false },
     { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadModelMatrix, false },
@@ -603,6 +626,8 @@
     { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_DrawMeshPrimitiveRange, false },
     { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_MeshComputeBoundingBox, false },
 
+    { "_Z11rsgDrawPath7rs_path", (void *)&SC_DrawPath, false },
+
     { "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false },
     { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false },
 
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index c70193ae..ef8516f 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -90,12 +90,12 @@
     String8 s;
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
         const Element *e = mRSProgram->mHal.state.inputElements[ct];
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
+        for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+            const Element *f = e->mHal.state.fields[field];
 
             // Cannot be complex
-            rsAssert(!f->getFieldCount());
-            switch (f->getComponent().getVectorSize()) {
+            rsAssert(!f->mHal.state.fieldsCount);
+            switch (f->mHal.state.vectorSize) {
             case 1: s.append("attribute float ATTRIB_"); break;
             case 2: s.append("attribute vec2 ATTRIB_"); break;
             case 3: s.append("attribute vec3 ATTRIB_"); break;
@@ -104,7 +104,7 @@
                 rsAssert(0);
             }
 
-            s.append(e->getFieldName(field));
+            s.append(e->mHal.state.fieldNames[field]);
             s.append(";\n");
         }
     }
@@ -114,17 +114,13 @@
 void RsdShader::appendAttributes() {
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
         const Element *e = mRSProgram->mHal.state.inputElements[ct];
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-            const char *fn = e->getFieldName(field);
-
-            if (fn[0] == '#') {
-                continue;
-            }
+        for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+            const Element *f = e->mHal.state.fields[field];
+            const char *fn = e->mHal.state.fieldNames[field];
 
             // Cannot be complex
-            rsAssert(!f->getFieldCount());
-            switch (f->getComponent().getVectorSize()) {
+            rsAssert(!f->mHal.state.fieldsCount);
+            switch (f->mHal.state.vectorSize) {
             case 1: mShader.append("attribute float ATTRIB_"); break;
             case 2: mShader.append("attribute vec2 ATTRIB_"); break;
             case 3: mShader.append("attribute vec3 ATTRIB_"); break;
@@ -143,7 +139,12 @@
     char buf[256];
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
         if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
-            snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+            Allocation *a = mRSProgram->mHal.state.textures[ct];
+            if (a && a->mHal.state.surfaceTextureID) {
+                snprintf(buf, sizeof(buf), "uniform samplerExternalOES UNI_Tex%i;\n", ct);
+            } else {
+                snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+            }
             mTextureTargets[ct] = GL_TEXTURE_2D;
         } else {
             snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
@@ -211,24 +212,20 @@
 void RsdShader::appendUserConstants() {
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
         const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-            const char *fn = e->getFieldName(field);
-
-            if (fn[0] == '#') {
-                continue;
-            }
+        for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+            const Element *f = e->mHal.state.fields[field];
+            const char *fn = e->mHal.state.fieldNames[field];
 
             // Cannot be complex
-            rsAssert(!f->getFieldCount());
-            if (f->getType() == RS_TYPE_MATRIX_4X4) {
+            rsAssert(!f->mHal.state.fieldsCount);
+            if (f->mHal.state.dataType == RS_TYPE_MATRIX_4X4) {
                 mShader.append("uniform mat4 UNI_");
-            } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
+            } else if (f->mHal.state.dataType == RS_TYPE_MATRIX_3X3) {
                 mShader.append("uniform mat3 UNI_");
-            } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
+            } else if (f->mHal.state.dataType == RS_TYPE_MATRIX_2X2) {
                 mShader.append("uniform mat2 UNI_");
             } else {
-                switch (f->getComponent().getVectorSize()) {
+                switch (f->mHal.state.vectorSize) {
                 case 1: mShader.append("uniform float UNI_"); break;
                 case 2: mShader.append("uniform vec2 UNI_"); break;
                 case 3: mShader.append("uniform vec3 UNI_"); break;
@@ -239,8 +236,8 @@
             }
 
             mShader.append(fn);
-            if (e->getFieldArraySize(field) > 1) {
-                mShader.appendFormat("[%d]", e->getFieldArraySize(field));
+            if (e->mHal.state.fieldArraySizes[field] > 1) {
+                mShader.appendFormat("[%d]", e->mHal.state.fieldArraySizes[field]);
             }
             mShader.append(";\n");
         }
@@ -248,8 +245,8 @@
 }
 
 void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
-    RsDataType dataType = field->getType();
-    uint32_t elementSize = field->getSizeBytes() / sizeof(float);
+    RsDataType dataType = field->mHal.state.dataType;
+    uint32_t elementSize = field->mHal.state.elementSizeBytes / sizeof(float);
     for (uint32_t i = 0; i < arraySize; i ++) {
         if (arraySize > 1) {
             ALOGV("Array Element [%u]", i);
@@ -270,7 +267,7 @@
             ALOGV("{%f, %f",  fd[0], fd[2]);
             ALOGV(" %f, %f}", fd[1], fd[3]);
         } else {
-            switch (field->getComponent().getVectorSize()) {
+            switch (field->mHal.state.vectorSize) {
             case 1:
                 ALOGV("Uniform 1 = %f", fd[0]);
                 break;
@@ -295,7 +292,7 @@
 
 void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd,
                          int32_t slot, uint32_t arraySize ) {
-    RsDataType dataType = field->getType();
+    RsDataType dataType = field->mHal.state.dataType;
     if (dataType == RS_TYPE_MATRIX_4X4) {
         RSD_CALL_GL(glUniformMatrix4fv, slot, arraySize, GL_FALSE, fd);
     } else if (dataType == RS_TYPE_MATRIX_3X3) {
@@ -303,7 +300,7 @@
     } else if (dataType == RS_TYPE_MATRIX_2X2) {
         RSD_CALL_GL(glUniformMatrix2fv, slot, arraySize, GL_FALSE, fd);
     } else {
-        switch (field->getComponent().getVectorSize()) {
+        switch (field->mHal.state.vectorSize) {
         case 1:
             RSD_CALL_GL(glUniform1fv, slot, arraySize, fd);
             break;
@@ -458,15 +455,11 @@
 
         const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
         const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-            const char *fieldName = e->getFieldName(field);
-            // If this field is padding, skip it
-            if (fieldName[0] == '#') {
-                continue;
-            }
+        for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+            const Element *f = e->mHal.state.fields[field];
+            const char *fieldName = e->mHal.state.fieldNames[field];
 
-            uint32_t offset = e->getFieldOffsetBytes(field);
+            uint32_t offset = e->mHal.state.fieldOffsetBytes[field];
             const float *fd = reinterpret_cast<const float *>(&data[offset]);
 
             int32_t slot = -1;
@@ -505,22 +498,13 @@
     mAttribCount = 0;
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
         const Element *elem = mRSProgram->mHal.state.inputElements[ct];
-        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
-            if (elem->getFieldName(field)[0] != '#') {
-                mAttribCount ++;
-            }
-        }
+        mAttribCount += elem->mHal.state.fieldsCount;
     }
 
     mUniformCount = 0;
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
         const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement();
-
-        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
-            if (elem->getFieldName(field)[0] != '#') {
-                mUniformCount ++;
-            }
-        }
+        mUniformCount += elem->mHal.state.fieldsCount;
     }
     mUniformCount += mRSProgram->mHal.state.texturesCount;
 
@@ -540,17 +524,17 @@
 
 void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths,
                                    uint32_t *count, const char *prefix) {
-    rsAssert(e->getFieldCount());
-    for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
-        const Element *ce = e->getField(ct);
-        if (ce->getFieldCount()) {
+    rsAssert(e->mHal.state.fieldsCount);
+    for (uint32_t ct=0; ct < e->mHal.state.fieldsCount; ct++) {
+        const Element *ce = e->mHal.state.fields[ct];
+        if (ce->mHal.state.fieldsCount) {
             initAddUserElement(ce, names, arrayLengths, count, prefix);
-        } else if (e->getFieldName(ct)[0] != '#') {
+        } else {
             String8 tmp(prefix);
-            tmp.append(e->getFieldName(ct));
+            tmp.append(e->mHal.state.fieldNames[ct]);
             names[*count].setTo(tmp.string());
             if (arrayLengths) {
-                arrayLengths[*count] = e->getFieldArraySize(ct);
+                arrayLengths[*count] = e->mHal.state.fieldArraySizes[ct];
             }
             (*count)++;
         }
diff --git a/libs/rs/driver/rsdShaderCache.h b/libs/rs/driver/rsdShaderCache.h
index 17ee3e8..d64780b 100644
--- a/libs/rs/driver/rsdShaderCache.h
+++ b/libs/rs/driver/rsdShaderCache.h
@@ -108,6 +108,7 @@
             }
             if (numFragUnis) {
                 fragUniforms = new UniformData[numFragUnis];
+                fragUniformIsSTO = new bool[numFragUnis];
             }
         }
         ~ProgramEntry() {
@@ -123,6 +124,10 @@
                 delete[] fragUniforms;
                 fragUniforms = NULL;
             }
+            if (fragUniformIsSTO) {
+                delete[] fragUniformIsSTO;
+                fragUniformIsSTO = NULL;
+            }
         }
         uint32_t vtx;
         uint32_t frag;
@@ -131,6 +136,7 @@
         AttrData *vtxAttrs;
         UniformData *vtxUniforms;
         UniformData *fragUniforms;
+        bool *fragUniformIsSTO;
     };
     android::Vector<ProgramEntry*> mEntries;
     ProgramEntry *mCurrent;
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index ffb1196..6759bc7 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -42,6 +42,7 @@
     param RsType vtype
     param RsAllocationMipmapControl mips
     param uint32_t usages
+    param uint32_t ptr
     ret RsAllocation
 }
 
@@ -63,7 +64,10 @@
     ret RsAllocation
 }
 
-
+AllocationGetSurfaceTextureID {
+    param RsAllocation alloc
+    ret int32_t
+}
 
 ContextFinish {
 	sync
@@ -389,3 +393,13 @@
 	param uint32_t *primType
 	ret RsMesh
 	}
+
+PathCreate {
+    param RsPathPrimitive pp
+    param bool isStatic
+    param RsAllocation vertex
+    param RsAllocation loops
+    param float quality
+    ret RsPath
+    }
+
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index fd85b07..02c6809 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -22,21 +22,22 @@
 using namespace android::renderscript;
 
 Allocation::Allocation(Context *rsc, const Type *type, uint32_t usages,
-                       RsAllocationMipmapControl mc)
+                       RsAllocationMipmapControl mc, void * ptr)
     : ObjectBase(rsc) {
 
     memset(&mHal, 0, sizeof(mHal));
     mHal.state.mipmapControl = RS_ALLOCATION_MIPMAP_NONE;
     mHal.state.usageFlags = usages;
     mHal.state.mipmapControl = mc;
+    mHal.state.usrPtr = ptr;
 
     setType(type);
     updateCache();
 }
 
 Allocation * Allocation::createAllocation(Context *rsc, const Type *type, uint32_t usages,
-                              RsAllocationMipmapControl mc) {
-    Allocation *a = new Allocation(rsc, type, usages, mc);
+                              RsAllocationMipmapControl mc, void * ptr) {
+    Allocation *a = new Allocation(rsc, type, usages, mc, ptr);
 
     if (!rsc->mHal.funcs.allocation.init(rsc, a, type->getElement()->getHasReferences())) {
         rsc->setError(RS_ERROR_FATAL_DRIVER, "Allocation::Allocation, alloc failure");
@@ -413,6 +414,12 @@
     ALOGE("not implemented");
 }
 
+int32_t Allocation::getSurfaceTextureID(const Context *rsc) {
+    int32_t id = rsc->mHal.funcs.allocation.initSurfaceTexture(rsc, this);
+    mHal.state.surfaceTextureID = id;
+    return id;
+}
+
 /////////////////
 //
 
@@ -571,8 +578,8 @@
 
 RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype,
                                        RsAllocationMipmapControl mips,
-                                       uint32_t usages) {
-    Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips);
+                                       uint32_t usages, uint32_t ptr) {
+    Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips, (void *)ptr);
     if (!alloc) {
         return NULL;
     }
@@ -585,7 +592,7 @@
                                             const void *data, size_t data_length, uint32_t usages) {
     Type *t = static_cast<Type *>(vtype);
 
-    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
+    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages, 0);
     Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
     if (texAlloc == NULL) {
         ALOGE("Memory allocation failure");
@@ -609,7 +616,7 @@
     // Cubemap allocation's faces should be Width by Width each.
     // Source data should have 6 * Width by Width pixels
     // Error checking is done in the java layer
-    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
+    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages, 0);
     Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
     if (texAlloc == NULL) {
         ALOGE("Memory allocation failure");
@@ -658,6 +665,11 @@
                                            (RsAllocationCubemapFace)srcFace);
 }
 
+int32_t rsi_AllocationGetSurfaceTextureID(Context *rsc, RsAllocation valloc) {
+    Allocation *alloc = static_cast<Allocation *>(valloc);
+    return alloc->getSurfaceTextureID(rsc);
+}
+
 }
 }
 
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 20201ca..6838759 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -55,6 +55,9 @@
             bool hasMipmaps;
             bool hasFaces;
             bool hasReferences;
+            int32_t surfaceTextureID;
+
+            void * usrPtr;
         };
         State state;
 
@@ -66,7 +69,8 @@
     Hal mHal;
 
     static Allocation * createAllocation(Context *rsc, const Type *, uint32_t usages,
-                                  RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE);
+                                         RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE,
+                                         void *ptr = 0);
     virtual ~Allocation();
     void updateCache();
 
@@ -123,6 +127,7 @@
         return mHal.state.mipmapControl != RS_ALLOCATION_MIPMAP_NONE;
     }
 
+    int32_t getSurfaceTextureID(const Context *rsc);
 
 protected:
     Vector<const Program *> mToDirtyList;
@@ -134,7 +139,7 @@
 
 private:
     void freeChildrenUnlocked();
-    Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc);
+    Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc, void *ptr);
 
     uint32_t getPackedSize() const;
     static void writePackedData(const Type *type, uint8_t *dst, const uint8_t *src, bool dstPadded);
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
index 21b98f6..9c2c200 100644
--- a/libs/rs/rsComponent.cpp
+++ b/libs/rs/rsComponent.cpp
@@ -62,6 +62,7 @@
         rsAssert(mNormalized == true);
         break;
     default:
+        rsAssert(mKind != RS_KIND_INVALID);
         break;
     }
 
@@ -167,6 +168,9 @@
     case RS_TYPE_BOOLEAN:
         mTypeBits = 8;
         break;
+    default:
+        rsAssert(mType != RS_TYPE_INVALID);
+        break;
     }
 
     mBitsUnpadded = mTypeBits * mVectorSize;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 04284dd..3346594 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -361,6 +361,7 @@
 #else
     setpriority(PRIO_PROCESS, mNativeThreadId, p);
 #endif
+    mHal.funcs.setPriority(this, mThreadPriority);
 }
 
 Context::Context() {
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index a844a20..05c799e 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -32,6 +32,7 @@
 #include "rsAdapter.h"
 #include "rsSampler.h"
 #include "rsFont.h"
+#include "rsPath.h"
 #include "rsProgramFragment.h"
 #include "rsProgramStore.h"
 #include "rsProgramRaster.h"
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index dff9585..fb2892c 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -27,6 +27,7 @@
     mFields = NULL;
     mFieldCount = 0;
     mHasReference = false;
+    memset(&mHal, 0, sizeof(mHal));
 }
 
 Element::~Element() {
@@ -47,6 +48,12 @@
     mFields = NULL;
     mFieldCount = 0;
     mHasReference = false;
+
+    delete [] mHal.state.fields;
+    delete [] mHal.state.fieldArraySizes;
+    delete [] mHal.state.fieldNames;
+    delete [] mHal.state.fieldNameLengths;
+    delete [] mHal.state.fieldOffsetBytes;
 }
 
 size_t Element::getSizeBits() const {
@@ -157,16 +164,36 @@
 }
 
 void Element::compute() {
+    mHal.state.dataType = mComponent.getType();
+    mHal.state.dataKind = mComponent.getKind();
+    mHal.state.vectorSize = mComponent.getVectorSize();
+
     if (mFieldCount == 0) {
         mBits = mComponent.getBits();
         mBitsUnpadded = mComponent.getBitsUnpadded();
         mHasReference = mComponent.isReference();
+
+        mHal.state.elementSizeBytes = getSizeBytes();
         return;
     }
 
+    uint32_t noPaddingFieldCount = 0;
+    for (uint32_t ct = 0; ct < mFieldCount; ct ++) {
+        if (mFields[ct].name.string()[0] != '#') {
+            noPaddingFieldCount ++;
+        }
+    }
+
+    mHal.state.fields = new const Element*[noPaddingFieldCount];
+    mHal.state.fieldArraySizes = new uint32_t[noPaddingFieldCount];
+    mHal.state.fieldNames = new const char*[noPaddingFieldCount];
+    mHal.state.fieldNameLengths = new uint32_t[noPaddingFieldCount];
+    mHal.state.fieldOffsetBytes = new uint32_t[noPaddingFieldCount];
+    mHal.state.fieldsCount = noPaddingFieldCount;
+
     size_t bits = 0;
     size_t bitsUnpadded = 0;
-    for (size_t ct=0; ct < mFieldCount; ct++) {
+    for (size_t ct = 0, ctNoPadding = 0; ct < mFieldCount; ct++) {
         mFields[ct].offsetBits = bits;
         mFields[ct].offsetBitsUnpadded = bitsUnpadded;
         bits += mFields[ct].e->getSizeBits() * mFields[ct].arraySize;
@@ -175,8 +202,21 @@
         if (mFields[ct].e->mHasReference) {
             mHasReference = true;
         }
+
+        if (mFields[ct].name.string()[0] == '#') {
+            continue;
+        }
+
+        mHal.state.fields[ctNoPadding] = mFields[ct].e.get();
+        mHal.state.fieldArraySizes[ctNoPadding] = mFields[ct].arraySize;
+        mHal.state.fieldNames[ctNoPadding] = mFields[ct].name.string();
+        mHal.state.fieldNameLengths[ctNoPadding] = mFields[ct].name.length() + 1; // to include 0
+        mHal.state.fieldOffsetBytes[ctNoPadding] = mFields[ct].offsetBits >> 3;
+
+        ctNoPadding ++;
     }
 
+    mHal.state.elementSizeBytes = getSizeBytes();
 }
 
 ObjectBaseRef<const Element> Element::createRef(Context *rsc, RsDataType dt, RsDataKind dk,
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index 04010fa..4b6b460 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -24,10 +24,38 @@
 // ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
 // An element is a group of Components that occupies one cell in a structure.
 class Element : public ObjectBase {
 public:
+    struct Hal {
+        mutable void *drv;
+
+        struct State {
+            RsDataType dataType;
+            RsDataKind dataKind;
+            uint32_t vectorSize;
+            uint32_t elementSizeBytes;
+
+            // Subelements
+            const Element **fields;
+            uint32_t *fieldArraySizes;
+            const char **fieldNames;
+            uint32_t *fieldNameLengths;
+            uint32_t *fieldOffsetBytes;
+            uint32_t fieldsCount;
+        };
+        State state;
+    };
+    Hal mHal;
+
     class Builder {
     public:
         Builder();
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 0fc73fb..166b5d3 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -23,20 +23,18 @@
 // ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
 
 // An element is a group of Components that occupies one cell in a structure.
 class Mesh : public ObjectBase {
 public:
-    Mesh(Context *);
-    Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
-    ~Mesh();
-
-    virtual void serialize(OStream *stream) const;
-    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
-    static Mesh *createFromStream(Context *rsc, IStream *stream);
-    void init();
-
     struct Hal {
         mutable void *drv;
 
@@ -57,6 +55,15 @@
     };
     Hal mHal;
 
+    Mesh(Context *);
+    Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
+    ~Mesh();
+
+    virtual void serialize(OStream *stream) const;
+    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
+    static Mesh *createFromStream(Context *rsc, IStream *stream);
+    void init();
+
     void setVertexBuffer(Allocation *vb, uint32_t index) {
         mVertexBuffers[index].set(vb);
         mHal.state.vertexBuffers[index] = vb;
diff --git a/libs/rs/rsPath.cpp b/libs/rs/rsPath.cpp
new file mode 100644
index 0000000..c4f4978
--- /dev/null
+++ b/libs/rs/rsPath.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Path::Path(Context *rsc) : ObjectBase(rsc) {
+}
+
+Path::Path(Context *rsc, RsPathPrimitive pp, bool isStatic,
+                      Allocation *vtx, Allocation *loops, float quality)
+: ObjectBase(rsc) {
+
+    memset(&mHal, 0, sizeof(mHal));
+    mHal.state.quality = quality;
+    mHal.state.primitive = pp;
+
+    //LOGE("i1");
+    rsc->mHal.funcs.path.initStatic(rsc, this, vtx, loops);
+
+    //LOGE("i2");
+}
+
+Path::Path(Context *rsc, uint32_t vertexBuffersCount, uint32_t primitivesCount)
+: ObjectBase(rsc) {
+
+}
+
+Path::~Path() {
+
+}
+
+
+void Path::rasterize(const BezierSegment_t *s, uint32_t num, Allocation *alloc) {
+
+    for (uint32_t i=0; i < num; i++) {
+
+    }
+
+}
+
+void Path::render(Context *rsc) {
+}
+
+void Path::serialize(OStream *stream) const {
+
+}
+
+RsA3DClassID Path::getClassId() const {
+    return RS_A3D_CLASS_ID_UNKNOWN;
+}
+
+namespace android {
+namespace renderscript {
+
+RsPath rsi_PathCreate(Context *rsc, RsPathPrimitive pp, bool isStatic,
+                      RsAllocation vtx, RsAllocation loops, float quality) {
+    return new Path(rsc, pp, isStatic, (Allocation *)vtx, (Allocation *)loops, quality);
+}
+
+}
+}
diff --git a/libs/rs/rsPath.h b/libs/rs/rsPath.h
new file mode 100644
index 0000000..dac795e
--- /dev/null
+++ b/libs/rs/rsPath.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_PATH_H
+#define ANDROID_RS_PATH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Path : public ObjectBase {
+public:
+    struct {
+        mutable void * drv;
+
+        struct State {
+            RsPathPrimitive primitive;
+            float quality;
+        };
+        State state;
+    } mHal;
+
+    Path(Context *);
+    Path(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
+    Path(Context *, RsPathPrimitive pp, bool isStatic, Allocation *vtx, Allocation *loop, float q);
+
+    ~Path();
+
+    void render(Context *);
+    virtual void serialize(OStream *stream) const;
+    virtual RsA3DClassID getClassId() const;
+
+private:
+
+
+    typedef struct {
+        float x[4];
+        float y[4];
+    } BezierSegment_t;
+
+    bool subdivideCheck(const BezierSegment_t *s, float u1, float u2);
+
+    void rasterize(const BezierSegment_t *s, uint32_t num, Allocation *alloc);
+
+
+};
+
+}
+}
+#endif //ANDROID_RS_PATH_H
+
+
+
diff --git a/libs/rs/rsRuntime.h b/libs/rs/rsRuntime.h
index cb962a8..3bded62 100644
--- a/libs/rs/rsRuntime.h
+++ b/libs/rs/rsRuntime.h
@@ -30,6 +30,8 @@
 //////////////////////////////////////////////////////////////////////////////
 
 void rsrBindTexture(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *);
+void rsrBindConstant(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *);
+void rsrBindConstant(Context *, Script *, ProgramVertex*, uint32_t slot, Allocation *);
 void rsrBindSampler(Context *, Script *, ProgramFragment *, uint32_t slot, Sampler *);
 void rsrBindProgramStore(Context *, Script *, ProgramStore *);
 void rsrBindProgramFragment(Context *, Script *, ProgramFragment *);
@@ -68,6 +70,7 @@
 void rsrDrawSpriteScreenspace(Context *, Script *,
                               float x, float y, float z, float w, float h);
 void rsrDrawRect(Context *, Script *, float x1, float y1, float x2, float y2, float z);
+void rsrDrawPath(Context *, Script *, Path *);
 void rsrDrawMesh(Context *, Script *, Mesh *);
 void rsrDrawMeshPrimitive(Context *, Script *, Mesh *, uint32_t primIndex);
 void rsrDrawMeshPrimitiveRange(Context *, Script *, Mesh *,
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 7964792..97469d3 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -50,6 +50,18 @@
     pf->bindTexture(rsc, slot, a);
 }
 
+void rsrBindConstant(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Allocation *a) {
+    CHECK_OBJ_OR_NULL(a);
+    CHECK_OBJ(pf);
+    pf->bindAllocation(rsc, a, slot);
+}
+
+void rsrBindConstant(Context *rsc, Script *sc, ProgramVertex *pv, uint32_t slot, Allocation *a) {
+    CHECK_OBJ_OR_NULL(a);
+    CHECK_OBJ(pv);
+    pv->bindAllocation(rsc, a, slot);
+}
+
 void rsrBindSampler(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Sampler *s) {
     CHECK_OBJ_OR_NULL(vs);
     CHECK_OBJ(vpf);
@@ -200,6 +212,14 @@
     rsrDrawQuad(rsc, sc, x1, y2, z, x2, y2, z, x2, y1, z, x1, y1, z);
 }
 
+void rsrDrawPath(Context *rsc, Script *sc, Path *sm) {
+    CHECK_OBJ(sm);
+    if (!rsc->setupCheck()) {
+        return;
+    }
+    sm->render(rsc);
+}
+
 void rsrDrawMesh(Context *rsc, Script *sc, Mesh *sm) {
     CHECK_OBJ(sm);
     if (!rsc->setupCheck()) {
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 7966470..70ab7b7 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -46,12 +46,8 @@
         delete [] mLODs;
         mLODs = NULL;
     }
-    mDimX = 0;
-    mDimY = 0;
-    mDimZ = 0;
-    mDimLOD = 0;
-    mFaces = false;
     mElement.clear();
+    memset(&mHal, 0, sizeof(mHal));
 }
 
 TypeState::TypeState() {
@@ -62,16 +58,16 @@
 }
 
 size_t Type::getOffsetForFace(uint32_t face) const {
-    rsAssert(mFaces);
+    rsAssert(mHal.state.faces);
     return 0;
 }
 
 void Type::compute() {
     uint32_t oldLODCount = mLODCount;
-    if (mDimLOD) {
-        uint32_t l2x = rsFindHighBit(mDimX) + 1;
-        uint32_t l2y = rsFindHighBit(mDimY) + 1;
-        uint32_t l2z = rsFindHighBit(mDimZ) + 1;
+    if (mHal.state.dimLOD) {
+        uint32_t l2x = rsFindHighBit(mHal.state.dimX) + 1;
+        uint32_t l2y = rsFindHighBit(mHal.state.dimY) + 1;
+        uint32_t l2z = rsFindHighBit(mHal.state.dimZ) + 1;
 
         mLODCount = rsMax(l2x, l2y);
         mLODCount = rsMax(mLODCount, l2z);
@@ -85,9 +81,9 @@
         mLODs = new LOD[mLODCount];
     }
 
-    uint32_t tx = mDimX;
-    uint32_t ty = mDimY;
-    uint32_t tz = mDimZ;
+    uint32_t tx = mHal.state.dimX;
+    uint32_t ty = mHal.state.dimY;
+    uint32_t tz = mHal.state.dimZ;
     size_t offset = 0;
     for (uint32_t lod=0; lod < mLODCount; lod++) {
         mLODs[lod].mX = tx;
@@ -103,10 +99,11 @@
     // At this point the offset is the size of a mipmap chain;
     mMipChainSizeBytes = offset;
 
-    if (mFaces) {
+    if (mHal.state.faces) {
         offset *= 6;
     }
     mTotalSizeBytes = offset;
+    mHal.state.element = mElement.get();
 }
 
 uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const {
@@ -127,7 +124,8 @@
     return offset;
 }
 
-uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const {
+uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face,
+                                uint32_t x, uint32_t y) const {
     uint32_t offset = mLODs[lod].mOffset;
     offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes();
 
@@ -141,7 +139,12 @@
 void Type::dumpLOGV(const char *prefix) const {
     char buf[1024];
     ObjectBase::dumpLOGV(prefix);
-    ALOGV("%s   Type: x=%zu y=%zu z=%zu mip=%i face=%i", prefix, mDimX, mDimY, mDimZ, mDimLOD, mFaces);
+    ALOGV("%s   Type: x=%u y=%u z=%u mip=%i face=%i", prefix,
+                                                      mHal.state.dimX,
+                                                      mHal.state.dimY,
+                                                      mHal.state.dimZ,
+                                                      mHal.state.dimLOD,
+                                                      mHal.state.faces);
     snprintf(buf, sizeof(buf), "%s element: ", prefix);
     mElement->dumpLOGV(buf);
 }
@@ -155,12 +158,12 @@
 
     mElement->serialize(stream);
 
-    stream->addU32(mDimX);
-    stream->addU32(mDimY);
-    stream->addU32(mDimZ);
+    stream->addU32(mHal.state.dimX);
+    stream->addU32(mHal.state.dimY);
+    stream->addU32(mHal.state.dimZ);
 
-    stream->addU8((uint8_t)(mDimLOD ? 1 : 0));
-    stream->addU8((uint8_t)(mFaces ? 1 : 0));
+    stream->addU8((uint8_t)(mHal.state.dimLOD ? 1 : 0));
+    stream->addU8((uint8_t)(mHal.state.faces ? 1 : 0));
 }
 
 Type *Type::createFromStream(Context *rsc, IStream *stream) {
@@ -232,11 +235,11 @@
     Type *nt = new Type(rsc);
     returnRef.set(nt);
     nt->mElement.set(e);
-    nt->mDimX = dimX;
-    nt->mDimY = dimY;
-    nt->mDimZ = dimZ;
-    nt->mDimLOD = dimLOD;
-    nt->mFaces = dimFaces;
+    nt->mHal.state.dimX = dimX;
+    nt->mHal.state.dimY = dimY;
+    nt->mHal.state.dimZ = dimZ;
+    nt->mHal.state.dimLOD = dimLOD;
+    nt->mHal.state.faces = dimFaces;
     nt->compute();
 
     ObjectBase::asyncLock();
@@ -248,14 +251,14 @@
 
 ObjectBaseRef<Type> Type::cloneAndResize1D(Context *rsc, uint32_t dimX) const {
     return getTypeRef(rsc, mElement.get(), dimX,
-                      mDimY, mDimZ, mDimLOD, mFaces);
+                      mHal.state.dimY, mHal.state.dimZ, mHal.state.dimLOD, mHal.state.faces);
 }
 
 ObjectBaseRef<Type> Type::cloneAndResize2D(Context *rsc,
                               uint32_t dimX,
                               uint32_t dimY) const {
     return getTypeRef(rsc, mElement.get(), dimX, dimY,
-                      mDimZ, mDimLOD, mFaces);
+                      mHal.state.dimZ, mHal.state.dimLOD, mHal.state.faces);
 }
 
 
@@ -276,8 +279,8 @@
 
 void rsaTypeGetNativeData(RsContext con, RsType type, uint32_t *typeData, uint32_t typeDataSize) {
     rsAssert(typeDataSize == 6);
-    // Pack the data in the follofing way mDimX; mDimY; mDimZ;
-    // mDimLOD; mDimFaces; mElement; into typeData
+    // Pack the data in the follofing way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ;
+    // mHal.state.dimLOD; mHal.state.faces; mElement; into typeData
     Type *t = static_cast<Type *>(type);
 
     (*typeData++) = t->getDimX();
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index bc0d9ff..3878156 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -22,10 +22,35 @@
 // ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
 
 class Type : public ObjectBase {
 public:
+    struct Hal {
+        mutable void *drv;
+
+        struct State {
+            const Element * element;
+
+            // Size of the structure in the various dimensions.  A missing Dimension is
+            // specified as a 0 and not a 1.
+            uint32_t dimX;
+            uint32_t dimY;
+            uint32_t dimZ;
+            bool dimLOD;
+            bool faces;
+        };
+        State state;
+    };
+    Hal mHal;
+
     Type * createTex2D(const Element *, size_t w, size_t h, bool mip);
 
     size_t getOffsetForFace(uint32_t face) const;
@@ -34,22 +59,25 @@
     size_t getElementSizeBytes() const {return mElement->getSizeBytes();}
     const Element * getElement() const {return mElement.get();}
 
-    uint32_t getDimX() const {return mDimX;}
-    uint32_t getDimY() const {return mDimY;}
-    uint32_t getDimZ() const {return mDimZ;}
-    uint32_t getDimLOD() const {return mDimLOD;}
-    bool getDimFaces() const {return mFaces;}
+    uint32_t getDimX() const {return mHal.state.dimX;}
+    uint32_t getDimY() const {return mHal.state.dimY;}
+    uint32_t getDimZ() const {return mHal.state.dimZ;}
+    uint32_t getDimLOD() const {return mHal.state.dimLOD;}
+    bool getDimFaces() const {return mHal.state.faces;}
 
     uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;}
     uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;}
     uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;}
 
-    uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
+    uint32_t getLODOffset(uint32_t lod) const {
+        rsAssert(lod < mLODCount); return mLODs[lod].mOffset;
+    }
     uint32_t getLODOffset(uint32_t lod, uint32_t x) const;
     uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const;
     uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const;
 
-    uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const;
+    uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face,
+                              uint32_t x, uint32_t y) const;
 
     uint32_t getLODCount() const {return mLODCount;}
     bool getIsNp2() const;
@@ -95,14 +123,6 @@
 
     ObjectBaseRef<const Element> mElement;
 
-    // Size of the structure in the various dimensions.  A missing Dimension is
-    // specified as a 0 and not a 1.
-    size_t mDimX;
-    size_t mDimY;
-    size_t mDimZ;
-    bool mDimLOD;
-    bool mFaces;
-
     // count of mipmap levels, 0 indicates no mipmapping
 
     size_t mMipChainSizeBytes;
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index b8d7351..1e222e1 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -29,6 +29,7 @@
 class Allocation;
 class Script;
 class ScriptC;
+class Path;
 class Program;
 class ProgramStore;
 class ProgramRaster;
@@ -114,6 +115,7 @@
                        bool zeroNew);
         void (*syncAll)(const Context *rsc, const Allocation *alloc, RsAllocationUsageType src);
         void (*markDirty)(const Context *rsc, const Allocation *alloc);
+        int32_t (*initSurfaceTexture)(const Context *rsc, const Allocation *alloc);
 
         void (*data1D)(const Context *rsc, const Allocation *alloc,
                        uint32_t xoff, uint32_t lod, uint32_t count,
@@ -189,6 +191,13 @@
     } mesh;
 
     struct {
+        bool (*initStatic)(const Context *rsc, const Path *m, const Allocation *vtx, const Allocation *loops);
+        bool (*initDynamic)(const Context *rsc, const Path *m);
+        void (*draw)(const Context *rsc, const Path *m);
+        void (*destroy)(const Context *rsc, const Path *m);
+    } path;
+
+    struct {
         bool (*init)(const Context *rsc, const Sampler *m);
         void (*destroy)(const Context *rsc, const Sampler *m);
     } sampler;
diff --git a/libs/rs/scriptc/rs_allocation.rsh b/libs/rs/scriptc/rs_allocation.rsh
index 9ec03bf..a2f69d9 100644
--- a/libs/rs/scriptc/rs_allocation.rsh
+++ b/libs/rs/scriptc/rs_allocation.rsh
@@ -168,5 +168,135 @@
 extern const void * __attribute__((overloadable))
     rsGetElementAt(rs_allocation, uint32_t x, uint32_t y, uint32_t z);
 
+/**
+ * @param a allocation to get data from
+ * @return element describing allocation layout
+ */
+extern rs_element __attribute__((overloadable))
+    rsAllocationGetElement(rs_allocation a);
+
+/**
+ * @param m mesh to get data from
+ * @return number of allocations in the mesh that contain vertex
+ *         data
+ */
+extern uint32_t __attribute__((overloadable))
+    rsMeshGetVertexAllocationCount(rs_mesh m);
+
+/**
+ * @param m mesh to get data from
+ * @return number of primitive groups in the mesh. This would
+ *         include simple primitives as well as allocations
+ *         containing index data
+ */
+extern uint32_t __attribute__((overloadable))
+    rsMeshGetPrimitiveCount(rs_mesh m);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the vertex allocation
+ * @return allocation containing vertex data
+ */
+extern rs_allocation __attribute__((overloadable))
+    rsMeshGetVertexAllocation(rs_mesh m, uint32_t index);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the index allocation
+ * @return allocation containing index data
+ */
+extern rs_allocation __attribute__((overloadable))
+    rsMeshGetIndexAllocation(rs_mesh m, uint32_t index);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the primitive
+ * @return primitive describing how the mesh is rendered
+ */
+extern rs_primitive __attribute__((overloadable))
+    rsMeshGetPrimitive(rs_mesh m, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @return number of sub-elements in this element
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementCount(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element to return
+ * @return sub-element in this element at given index
+ */
+extern rs_element __attribute__((overloadable))
+    rsElementGetSubElement(rs_element, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element to return
+ * @return length of the sub-element name including the null
+ *         terminator (size of buffer needed to write the name)
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementNameLength(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @param name array to store the name into
+ * @param nameLength length of the provided name array
+ * @return number of characters actually written, excluding the
+ *         null terminator
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementName(rs_element e, uint32_t index, char *name, uint32_t nameLength);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @return array size of sub-element in this element at given
+ *         index
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementArraySize(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @return offset in bytes of sub-element in this element at
+ *         given index
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementOffsetBytes(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @return total size of the element in bytes
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSizeBytes(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return element's data type
+ */
+extern rs_data_type __attribute__((overloadable))
+    rsElementGetDataType(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return element's data size
+ */
+extern rs_data_kind __attribute__((overloadable))
+    rsElementGetDataKind(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return length of the element vector (for float2, float3,
+ *         etc.)
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetVectorSize(rs_element e);
+
 #endif
 
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index 2581953..7fdebdc 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -22,6 +22,66 @@
  */
 #ifndef __RS_GRAPHICS_RSH__
 #define __RS_GRAPHICS_RSH__
+
+// These are API 15 once it get official
+typedef enum {
+    RS_DEPTH_FUNC_ALWAYS,
+    RS_DEPTH_FUNC_LESS,
+    RS_DEPTH_FUNC_LEQUAL,
+    RS_DEPTH_FUNC_GREATER,
+    RS_DEPTH_FUNC_GEQUAL,
+    RS_DEPTH_FUNC_EQUAL,
+    RS_DEPTH_FUNC_NOTEQUAL,
+
+    RS_DEPTH_FUNC_INVALID = 100,
+} rs_depth_func;
+
+typedef enum {
+    RS_BLEND_SRC_ZERO,                  // 0
+    RS_BLEND_SRC_ONE,                   // 1
+    RS_BLEND_SRC_DST_COLOR,             // 2
+    RS_BLEND_SRC_ONE_MINUS_DST_COLOR,   // 3
+    RS_BLEND_SRC_SRC_ALPHA,             // 4
+    RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,   // 5
+    RS_BLEND_SRC_DST_ALPHA,             // 6
+    RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,   // 7
+    RS_BLEND_SRC_SRC_ALPHA_SATURATE,    // 8
+
+    RS_BLEND_SRC_INVALID = 100,
+} rs_blend_src_func;
+
+typedef enum {
+    RS_BLEND_DST_ZERO,                  // 0
+    RS_BLEND_DST_ONE,                   // 1
+    RS_BLEND_DST_SRC_COLOR,             // 2
+    RS_BLEND_DST_ONE_MINUS_SRC_COLOR,   // 3
+    RS_BLEND_DST_SRC_ALPHA,             // 4
+    RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,   // 5
+    RS_BLEND_DST_DST_ALPHA,             // 6
+    RS_BLEND_DST_ONE_MINUS_DST_ALPHA,   // 7
+
+    RS_BLEND_DST_INVALID = 100,
+} rs_blend_dst_func;
+
+typedef enum {
+    RS_CULL_BACK,
+    RS_CULL_FRONT,
+    RS_CULL_NONE,
+
+    RS_CULL_INVALID = 100,
+} rs_cull_mode;
+
+typedef enum {
+    RS_SAMPLER_NEAREST,
+    RS_SAMPLER_LINEAR,
+    RS_SAMPLER_LINEAR_MIP_LINEAR,
+    RS_SAMPLER_WRAP,
+    RS_SAMPLER_CLAMP,
+    RS_SAMPLER_LINEAR_MIP_NEAREST,
+
+    RS_SAMPLER_INVALID = 100,
+} rs_sampler_value;
+
 #if (defined(RS_VERSION) && (RS_VERSION >= 14))
 /**
  * Set the color target used for all subsequent rendering calls
@@ -82,6 +142,88 @@
 extern void __attribute__((overloadable))
     rsgBindProgramStore(rs_program_store ps);
 
+
+/**
+ * @hide
+ * Get program store depth function
+ *
+ * @param ps
+ */
+extern rs_depth_func __attribute__((overloadable))
+    rsgProgramStoreGetDepthFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store depth mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetDepthMask(rs_program_store ps);
+/**
+ * @hide
+ * Get program store red component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskR(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store green component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskG(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blur component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskB(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store alpha component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskA(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend source function
+ *
+ * @param ps
+ */
+extern rs_blend_src_func __attribute__((overloadable))
+        rsgProgramStoreGetBlendSrcFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend destination function
+ *
+ * @param ps
+ */
+extern rs_blend_dst_func __attribute__((overloadable))
+    rsgProgramStoreGetBlendDstFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store dither state
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetDitherEnabled(rs_program_store ps);
+
+
 /**
  * Bind a new ProgramVertex to the rendering context.
  *
@@ -99,6 +241,24 @@
     rsgBindProgramRaster(rs_program_raster pr);
 
 /**
+ * @hide
+ * Get program raster point sprite state
+ *
+ * @param pr
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramRasterGetPointSpriteEnabled(rs_program_raster pr);
+
+/**
+ * @hide
+ * Get program raster cull mode
+ *
+ * @param pr
+ */
+extern rs_cull_mode __attribute__((overloadable))
+    rsgProgramRasterGetCullMode(rs_program_raster pr);
+
+/**
  * Bind a new Sampler object to a ProgramFragment.  The sampler will
  * operate on the texture bound at the matching slot.
  *
@@ -108,6 +268,51 @@
     rsgBindSampler(rs_program_fragment, uint slot, rs_sampler);
 
 /**
+ * @hide
+ * Get sampler minification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetMinification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler magnification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetMagnification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap S value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetWrapS(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap T value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetWrapT(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler anisotropy
+ *
+ * @param pr
+ */
+extern float __attribute__((overloadable))
+    rsgSamplerGetAnisotropy(rs_sampler s);
+
+/**
  * Bind a new Allocation object to a ProgramFragment.  The
  * Allocation must be a valid texture for the Program.  The sampling
  * of the texture will be controled by the Sampler bound at the
@@ -164,6 +369,28 @@
     rsgProgramFragmentConstantColor(rs_program_fragment pf, float r, float g, float b, float a);
 
 /**
+ * Bind a new Allocation object to a ProgramFragment.  The
+ * Allocation must be a valid constant input for the Program.
+ *
+ * @param ps program object
+ * @param slot index of the constant buffer on the program
+ * @param c constants to bind
+ */
+extern void __attribute__((overloadable))
+    rsgBindConstant(rs_program_fragment ps, uint slot, rs_allocation c);
+
+/**
+ * Bind a new Allocation object to a ProgramVertex.  The
+ * Allocation must be a valid constant input for the Program.
+ *
+ * @param pv program object
+ * @param slot index of the constant buffer on the program
+ * @param c constants to bind
+ */
+extern void __attribute__((overloadable))
+    rsgBindConstant(rs_program_vertex pv, uint slot, rs_allocation c);
+
+/**
  * Get the width of the current rendering surface.
  *
  * @return uint
@@ -288,6 +515,9 @@
 extern void __attribute__((overloadable))
     rsgDrawSpriteScreenspace(float x, float y, float z, float w, float h);
 
+extern void __attribute__((overloadable))
+    rsgDrawPath(rs_path p);
+
 /**
  * Draw a mesh using the current context state.  The whole mesh is
  * rendered.
diff --git a/libs/rs/scriptc/rs_object.rsh b/libs/rs/scriptc/rs_object.rsh
index a431219..1fc3f83 100644
--- a/libs/rs/scriptc/rs_object.rsh
+++ b/libs/rs/scriptc/rs_object.rsh
@@ -56,6 +56,11 @@
  * \overload
  */
 extern void __attribute__((overloadable))
+    rsSetObject(rs_path *dst, rs_path src);
+/**
+ * \overload
+ */
+extern void __attribute__((overloadable))
     rsSetObject(rs_mesh *dst, rs_mesh src);
 /**
  * \overload
@@ -114,6 +119,11 @@
  * \overload
  */
 extern void __attribute__((overloadable))
+    rsClearObject(rs_path *dst);
+/**
+ * \overload
+ */
+extern void __attribute__((overloadable))
     rsClearObject(rs_mesh *dst);
 /**
  * \overload
@@ -175,6 +185,11 @@
  * \overload
  */
 extern bool __attribute__((overloadable))
+    rsIsObject(rs_path);
+/**
+ * \overload
+ */
+extern bool __attribute__((overloadable))
     rsIsObject(rs_mesh);
 /**
  * \overload
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 84bca9c..5345a48 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -138,6 +138,12 @@
  */
 typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_mesh;
 /**
+ * \brief Opaque handle to a Renderscript Path object.
+ *
+ * See: android.renderscript.Path
+ */
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_path;
+/**
  * \brief Opaque handle to a Renderscript ProgramFragment object.
  *
  * See: android.renderscript.ProgramFragment
@@ -396,4 +402,96 @@
 
 #endif //defined(RS_VERSION) && (RS_VERSION >= 14)
 
+/**
+ * Describes the way mesh vertex data is interpreted when rendering
+ *
+ **/
+typedef enum {
+    RS_PRIMITIVE_POINT,
+    RS_PRIMITIVE_LINE,
+    RS_PRIMITIVE_LINE_STRIP,
+    RS_PRIMITIVE_TRIANGLE,
+    RS_PRIMITIVE_TRIANGLE_STRIP,
+    RS_PRIMITIVE_TRIANGLE_FAN,
+
+    RS_PRIMITIVE_INVALID = 100,
+} rs_primitive;
+
+/**
+ * \brief Enumeration for possible element data types
+ *
+ * DataType represents the basic type information for a basic element.  The
+ * naming convention follows.  For numeric types it is FLOAT,
+ * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
+ * size of the data.  BOOLEAN is a true / false (1,0)
+ * represented in an 8 bit container.  The UNSIGNED variants
+ * with multiple bit definitions are for packed graphical data
+ * formats and represent vectors with per vector member sizes
+ * which are treated as a single unit for packing and alignment
+ * purposes.
+ *
+ * MATRIX the three matrix types contain FLOAT_32 elements and are treated
+ * as 32 bits for alignment purposes.
+ *
+ * RS_* objects.  32 bit opaque handles.
+ */
+typedef enum {
+    RS_TYPE_NONE,
+    //RS_TYPE_FLOAT_16,
+    RS_TYPE_FLOAT_32 = 2,
+    RS_TYPE_FLOAT_64,
+    RS_TYPE_SIGNED_8,
+    RS_TYPE_SIGNED_16,
+    RS_TYPE_SIGNED_32,
+    RS_TYPE_SIGNED_64,
+    RS_TYPE_UNSIGNED_8,
+    RS_TYPE_UNSIGNED_16,
+    RS_TYPE_UNSIGNED_32,
+    RS_TYPE_UNSIGNED_64,
+
+    RS_TYPE_BOOLEAN,
+
+    RS_TYPE_UNSIGNED_5_6_5,
+    RS_TYPE_UNSIGNED_5_5_5_1,
+    RS_TYPE_UNSIGNED_4_4_4_4,
+
+    RS_TYPE_MATRIX_4X4,
+    RS_TYPE_MATRIX_3X3,
+    RS_TYPE_MATRIX_2X2,
+
+    RS_TYPE_ELEMENT = 1000,
+    RS_TYPE_TYPE,
+    RS_TYPE_ALLOCATION,
+    RS_TYPE_SAMPLER,
+    RS_TYPE_SCRIPT,
+    RS_TYPE_MESH,
+    RS_TYPE_PROGRAM_FRAGMENT,
+    RS_TYPE_PROGRAM_VERTEX,
+    RS_TYPE_PROGRAM_RASTER,
+    RS_TYPE_PROGRAM_STORE,
+
+    RS_TYPE_INVALID = 10000,
+} rs_data_type;
+
+/**
+ * \brief Enumeration for possible element data kind
+ *
+ * The special interpretation of the data if required.  This is primarly
+ * useful for graphical data.  USER indicates no special interpretation is
+ * expected.  PIXEL is used in conjunction with the standard data types for
+ * representing texture formats.
+ */
+typedef enum {
+    RS_KIND_USER,
+
+    RS_KIND_PIXEL_L = 7,
+    RS_KIND_PIXEL_A,
+    RS_KIND_PIXEL_LA,
+    RS_KIND_PIXEL_RGB,
+    RS_KIND_PIXEL_RGBA,
+    RS_KIND_PIXEL_DEPTH,
+
+    RS_KIND_INVALID = 100,
+} rs_data_kind;
+
 #endif
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
index a7987b3..0ffb0e5 100644
--- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
@@ -25,13 +25,14 @@
     p.y = -1.f + ((float)y / gDimY) * 2.f;
 
     float2 t = 0;
+    float2 t2 = t * t;
     int iteration = 0;
-    while((t.x*t.x + t.y*t.y < 4.f) && (iteration < gMaxIteration)) {
-        float2 t2 = t * t;
+    while((t2.x + t2.y < 4.f) && (iteration < gMaxIteration)) {
         float xtemp = t2.x - t2.y + p.x;
         t.y = 2 * t.x * t.y + p.y;
         t.x = xtemp;
         iteration++;
+        t2 = t * t;
     }
 
     if(iteration >= gMaxIteration) {
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 3615f60..7368260 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -283,6 +283,9 @@
         mRadius = MAX_RADIUS;
         mScript.set_radius(mRadius);
 
+        mScript.invoke_filter();
+        mRS.finish();
+
         long t = java.lang.System.currentTimeMillis();
 
         mScript.invoke_filter();
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl
new file mode 100644
index 0000000..656961c
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl
@@ -0,0 +1,8 @@
+varying vec2 varTex0;
+
+void main() {
+   lowp vec3 col0 = texture2D(UNI_Tex0, varTex0).rgb;
+   gl_FragColor.xyz = col0 * UNI_modulate.rgb;
+   gl_FragColor.w = UNI_modulate.a;
+}
+
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
index ba70c71..41f664a 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
@@ -35,18 +35,22 @@
     // Custom shaders
     private ProgramFragment mProgFragmentMultitex;
     private ProgramFragment mProgFragmentSingletex;
+    private ProgramFragment mProgFragmentSingletexModulate;
     private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
     int mBenchmarkDimX;
     int mBenchmarkDimY;
 
     private ScriptC_fill_test mFillScript;
     ScriptField_TestScripts_s.Item[] mTests;
+    ScriptField_FillTestFragData_s mFragData;
 
     private final String[] mNames = {
         "Fill screen 10x singletexture",
         "Fill screen 10x 3tex multitexture",
         "Fill screen 10x blended singletexture",
-        "Fill screen 10x blended 3tex multitexture"
+        "Fill screen 10x blended 3tex multitexture",
+        "Fill screen 3x modulate blended singletexture",
+        "Fill screen 1x modulate blended singletexture",
     };
 
     public FillTest() {
@@ -88,6 +92,8 @@
         addTest(index++, 0 /*testId*/, 0 /*blend*/, 10 /*quadCount*/);
         addTest(index++, 1 /*testId*/, 1 /*blend*/, 10 /*quadCount*/);
         addTest(index++, 0 /*testId*/, 1 /*blend*/, 10 /*quadCount*/);
+        addTest(index++, 2 /*testId*/, 1 /*blend*/, 3 /*quadCount*/);
+        addTest(index++, 2 /*testId*/, 1 /*blend*/, 1 /*quadCount*/);
 
         return true;
     }
@@ -112,6 +118,14 @@
         pfbCustom.setShader(mRes, R.raw.singletexf);
         pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
         mProgFragmentSingletex = pfbCustom.create();
+
+        pfbCustom = new ProgramFragment.Builder(mRS);
+        pfbCustom.setShader(mRes, R.raw.singletexfm);
+        pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
+        mFragData = new ScriptField_FillTestFragData_s(mRS, 1);
+        pfbCustom.addConstant(mFragData.getType());
+        mProgFragmentSingletexModulate = pfbCustom.create();
+        mProgFragmentSingletexModulate.bindConstants(mFragData.getAllocation(), 0);
     }
 
     private Allocation loadTextureARGB(int id) {
@@ -140,6 +154,7 @@
         mFillScript.set_gProgVertex(progVertex);
 
         mFillScript.set_gProgFragmentTexture(mProgFragmentSingletex);
+        mFillScript.set_gProgFragmentTextureModulate(mProgFragmentSingletexModulate);
         mFillScript.set_gProgFragmentMultitex(mProgFragmentMultitex);
         mFillScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS));
         mFillScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS));
@@ -150,5 +165,7 @@
         mFillScript.set_gTexOpaque(loadTextureRGB(R.drawable.data));
         mFillScript.set_gTexTransparent(loadTextureARGB(R.drawable.leaf));
         mFillScript.set_gTexChecker(loadTextureRGB(R.drawable.checker));
+
+        mFillScript.bind_gFragData(mFragData);
     }
 }
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
index 23832d3..281f830 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
@@ -21,6 +21,7 @@
 
 rs_program_vertex gProgVertex;
 rs_program_fragment gProgFragmentTexture;
+rs_program_fragment gProgFragmentTextureModulate;
 rs_program_fragment gProgFragmentMultitex;
 
 rs_program_store gProgStoreBlendNone;
@@ -41,6 +42,11 @@
 } FillTestData;
 FillTestData *gData;
 
+typedef struct FillTestFragData_s {
+    float4 modulate;
+} FillTestFragData;
+FillTestFragData *gFragData;
+
 static float gDt = 0.0f;
 
 void init() {
@@ -58,7 +64,7 @@
     rsgProgramVertexLoadProjectionMatrix(&proj);
 }
 
-static void displaySingletexFill(bool blend, int quadCount) {
+static void displaySingletexFill(bool blend, int quadCount, bool modulate) {
     bindProgramVertexOrtho();
     rs_matrix4x4 matrix;
     rsMatrixLoadIdentity(&matrix);
@@ -70,9 +76,21 @@
     } else {
         rsgBindProgramStore(gProgStoreBlendAlpha);
     }
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+    if (modulate) {
+        rsgBindProgramFragment(gProgFragmentTextureModulate);
+        rsgBindSampler(gProgFragmentTextureModulate, 0, gLinearClamp);
+        rsgBindTexture(gProgFragmentTextureModulate, 0, gTexOpaque);
+
+        gFragData->modulate.r = 0.8f;
+        gFragData->modulate.g = 0.7f;
+        gFragData->modulate.b = 0.8f;
+        gFragData->modulate.a = 0.5f;
+        rsgAllocationSyncAll(rsGetAllocation(gFragData));
+    } else {
+        rsgBindProgramFragment(gProgFragmentTexture);
+        rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+        rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+    }
 
     for (int i = 0; i < quadCount; i ++) {
         float startX = 5 * i, startY = 5 * i;
@@ -128,7 +146,10 @@
             displayMultitextureSample(gData->blend == 1 ? true : false, gData->quadCount);
             break;
         case 1:
-            displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount);
+            displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, false);
+            break;
+        case 2:
+            displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, true);
             break;
         default:
             rsDebug("Wrong test number", 0);
diff --git a/tests/RenderScriptTests/SceneGraph/Android.mk b/tests/RenderScriptTests/SceneGraph/Android.mk
new file mode 100644
index 0000000..ba4b3c5
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/Android.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := SceneGraphTest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml
new file mode 100644
index 0000000..e8d1e8e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.testapp">
+    <uses-permission
+        android:name="android.permission.INTERNET" />
+    <application android:label="SceneGraphTest">
+        <activity android:name="TestApp"
+                  android:label="SceneGraphTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="FileSelector"
+                  android:label="FileSelector"
+                  android:hardwareAccelerated="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/SceneGraph/assets/blue.jpg b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg
new file mode 100644
index 0000000..494e77a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg
new file mode 100644
index 0000000..2fcecb0
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/green.jpg b/tests/RenderScriptTests/SceneGraph/assets/green.jpg
new file mode 100644
index 0000000..a86a754
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/green.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/grey.jpg b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg
new file mode 100644
index 0000000..5870b1a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orange.jpg b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg
new file mode 100644
index 0000000..7dbe942
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d
new file mode 100644
index 0000000..07318ae
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae
new file mode 100644
index 0000000..7eef443f
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae
@@ -0,0 +1,1102 @@
+<?xml version="1.0" ?>
+<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
+    <asset>
+        <contributor>
+            <author>alexst</author>
+            <authoring_tool>OpenCOLLADA2010</authoring_tool>
+            <comments>ColladaMaya export options: bakeTransforms=0;relativePaths=0;copyTextures=0;exportTriangles=1;exportCgfxFileReferences=0; isSampling=0;curveConstrainSampling=0;removeStaticCurves=1;exportPolygonMeshes=1;exportLights=1; exportCameras=1;exportJointsAndSkin=1;exportAnimations=0;exportInvisibleNodes=0;exportDefaultCameras=0; exportTexCoords=1;exportNormals=1;exportNormalsPerVertex=1;exportVertexColors=0;exportVertexColorsPerVertex=0; exportTexTangents=0;exportTangents=0;exportReferencedMaterials=1;exportMaterialsOnly=0; exportXRefs=1;dereferenceXRefs=1;exportCameraAsLookat=0;cameraXFov=0;cameraYFov=1;doublePrecision=0</comments>
+            <source_data>file:///Volumes/Android/art/orientation_test.mb</source_data>
+        </contributor>
+        <created>2011-09-30T15:31:38</created>
+        <modified>2011-09-30T15:31:38</modified>
+        <unit meter="0.01" name="centimeter" />
+        <up_axis>Y_UP</up_axis>
+    </asset>
+    <library_cameras>
+        <camera id="cameraShape1" name="cameraShape1">
+            <optics>
+                <technique_common>
+                    <perspective>
+                        <yfov>37.8493</yfov>
+                        <aspect_ratio>1.5</aspect_ratio>
+                        <znear>1</znear>
+                        <zfar>400</zfar>
+                    </perspective>
+                </technique_common>
+            </optics>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <film_fit>0</film_fit>
+                    <film_fit_offset>0</film_fit_offset>
+                    <film_offsetX>0</film_offsetX>
+                    <film_offsetY>0</film_offsetY>
+                    <horizontal_aperture>3.599993</horizontal_aperture>
+                    <lens_squeeze>1</lens_squeeze>
+                    <originalMayaNodeId>cameraShape1</originalMayaNodeId>
+                    <vertical_aperture>2.399995</vertical_aperture>
+                </technique>
+            </extra>
+        </camera>
+        <camera id="CameraDistShape" name="CameraDistShape">
+            <optics>
+                <technique_common>
+                    <perspective>
+                        <yfov>37.8493</yfov>
+                        <aspect_ratio>1.5</aspect_ratio>
+                        <znear>1</znear>
+                        <zfar>1000</zfar>
+                    </perspective>
+                </technique_common>
+            </optics>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <film_fit>0</film_fit>
+                    <film_fit_offset>0</film_fit_offset>
+                    <film_offsetX>0</film_offsetX>
+                    <film_offsetY>0</film_offsetY>
+                    <horizontal_aperture>3.599993</horizontal_aperture>
+                    <lens_squeeze>1</lens_squeeze>
+                    <originalMayaNodeId>CameraDistShape</originalMayaNodeId>
+                    <vertical_aperture>2.399995</vertical_aperture>
+                </technique>
+            </extra>
+        </camera>
+    </library_cameras>
+    <library_materials>
+        <material id="Paint1" name="Paint1">
+            <instance_effect url="#Paint1-fx" />
+        </material>
+        <material id="lambert2" name="lambert2">
+            <instance_effect url="#lambert2-fx" />
+        </material>
+        <material id="Plastic" name="Plastic">
+            <instance_effect url="#Plastic-fx" />
+        </material>
+        <material id="Metal" name="Metal">
+            <instance_effect url="#Metal-fx" />
+        </material>
+        <material id="PlasticCenter" name="PlasticCenter">
+            <instance_effect url="#PlasticCenter-fx" />
+        </material>
+        <material id="PlasticRed" name="PlasticRed">
+            <instance_effect url="#PlasticRed-fx" />
+        </material>
+        <material id="lambert10" name="lambert10">
+            <instance_effect url="#lambert10-fx" />
+        </material>
+        <material id="lambert11" name="lambert11">
+            <instance_effect url="#lambert11-fx" />
+        </material>
+    </library_materials>
+    <library_effects>
+        <effect id="Metal-fx">
+            <profile_COMMON>
+                <newparam sid="file23-surface">
+                    <surface type="2D">
+                        <init_from>file23</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file23-sampler">
+                    <sampler2D>
+                        <source>file23-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file23-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="Paint1-fx">
+            <profile_COMMON>
+                <newparam sid="file25-surface">
+                    <surface type="2D">
+                        <init_from>file25</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file25-sampler">
+                    <sampler2D>
+                        <source>file25-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file25-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="Plastic-fx">
+            <profile_COMMON>
+                <newparam sid="file24-surface">
+                    <surface type="2D">
+                        <init_from>file24</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file24-sampler">
+                    <sampler2D>
+                        <source>file24-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file24-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="PlasticCenter-fx">
+            <profile_COMMON>
+                <newparam sid="file24-surface">
+                    <surface type="2D">
+                        <init_from>file24</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file24-sampler">
+                    <sampler2D>
+                        <source>file24-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file24-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="PlasticRed-fx">
+            <profile_COMMON>
+                <newparam sid="file23-surface">
+                    <surface type="2D">
+                        <init_from>file23</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file23-sampler">
+                    <sampler2D>
+                        <source>file23-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file23-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="lambert10-fx">
+            <profile_COMMON>
+                <newparam sid="file28-surface">
+                    <surface type="2D">
+                        <init_from>file28</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file28-sampler">
+                    <sampler2D>
+                        <source>file28-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file28-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="lambert11-fx">
+            <profile_COMMON>
+                <newparam sid="file29-surface">
+                    <surface type="2D">
+                        <init_from>file29</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file29-sampler">
+                    <sampler2D>
+                        <source>file29-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file29-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="lambert2-fx">
+            <profile_COMMON>
+                <newparam sid="file22-surface">
+                    <surface type="2D">
+                        <init_from>file22</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file22-sampler">
+                    <sampler2D>
+                        <source>file22-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file22-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+    </library_effects>
+    <library_images>
+        <image id="file29" name="file29" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/blue.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file29</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+        <image id="file25" name="file25" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/carbonfiber.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file25</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+        <image id="file28" name="file28" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/green.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file28</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+        <image id="file22" name="file22" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/grey.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file22</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+        <image id="file24" name="file24" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/orange.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file24</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+        <image id="file23" name="file23" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/red.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file23</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+    </library_images>
+    <library_visual_scenes>
+        <visual_scene id="VisualSceneNode" name="orientation_test">
+            <node id="camera1" name="camera1">
+                <translate sid="translate">24.5791 14.1321 31.4654</translate>
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <rotate sid="rotateY">0 1 0 42</rotate>
+                <rotate sid="rotateX">1 0 0 -16.2</rotate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_camera url="#cameraShape1" />
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>camera1</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="CameraAim" name="CameraAim">
+                <translate sid="translate">0.0209301 3.68542 2.06912</translate>
+                <rotate sid="rotateY">0 1 0 43.2561</rotate>
+                <rotate sid="rotateX">1 0 0 -20</rotate>
+                <scale sid="scale">1 1 1</scale>
+                <node id="CameraDist" name="CameraDist">
+                    <translate sid="translate">0 0 45</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_camera url="#CameraDistShape" />
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>CameraDist</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>CameraAim</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pSphere4" name="pSphere4">
+                <translate sid="translate">-9.69237 0 7.70498</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pSphereShape4">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert7SG" target="#Paint1">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pSphere4</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pSphere1" name="pSphere1">
+                <translate sid="translate">13.0966 0 5.76254</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pSphereShape1">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert7SG" target="#Paint1">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pSphere1</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pSphere2" name="pSphere2">
+                <translate sid="translate">21.7661 0 -13.6375</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pSphereShape2">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert7SG" target="#Paint1">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pSphere2</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pSphere3" name="pSphere3">
+                <translate sid="translate">-13.862 0 -13.6154</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pSphereShape3">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert7SG" target="#Paint1">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pSphere3</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pSphere5" name="pSphere5">
+                <translate sid="translate">31.0862 0 18.5992</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pSphereShape5">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert7SG" target="#Paint1">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pSphere5</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pCube1" name="pCube1">
+                <translate sid="translate">0 0 0</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pCubeShape1">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert4SG" target="#lambert2">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pCube1</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="group1" name="group1">
+                <translate sid="translate">0 0 0</translate>
+                <rotate sid="rotateZ">0 0 1 -162.693</rotate>
+                <rotate sid="rotateY">0 1 0 21.3345</rotate>
+                <rotate sid="rotateX">1 0 0 -100.567</rotate>
+                <scale sid="scale">1 1 1</scale>
+                <node id="pSphere6" name="pSphere6">
+                    <translate sid="translate">-13.862 0 -13.6154</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape6">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert6SG" target="#Plastic">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere6</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere7" name="pSphere7">
+                    <translate sid="translate">-9.69237 0 7.70498</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape7">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert6SG" target="#Plastic">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere7</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere8" name="pSphere8">
+                    <translate sid="translate">21.7661 0 -13.6375</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape8">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert6SG" target="#Plastic">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere8</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere9" name="pSphere9">
+                    <translate sid="translate">13.0966 0 5.76254</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape9">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert6SG" target="#Plastic">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere9</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>group1</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="group2" name="group2">
+                <translate sid="translate">0 0 0</translate>
+                <rotate sid="rotateZ">0 0 1 45.4017</rotate>
+                <rotate sid="rotateY">0 1 0 79.393</rotate>
+                <rotate sid="rotateX">1 0 0 5.10889</rotate>
+                <scale sid="scale">1 1 1</scale>
+                <node id="pSphere10" name="pSphere10">
+                    <translate sid="translate">31.0862 0 18.5992</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape10">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere10</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere11" name="pSphere11">
+                    <translate sid="translate">13.0966 0 5.76254</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape11">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere11</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere12" name="pSphere12">
+                    <translate sid="translate">7.4784 16.3496 7.36882</translate>
+                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+                    <rotate sid="rotateY">0 1 0 158.666</rotate>
+                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape12">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere12</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere13" name="pSphere13">
+                    <translate sid="translate">-9.69237 0 7.70498</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape13">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere13</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere14" name="pSphere14">
+                    <translate sid="translate">11.3635 -4.3926 2.21012</translate>
+                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+                    <rotate sid="rotateY">0 1 0 158.666</rotate>
+                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape14">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere14</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere15" name="pSphere15">
+                    <translate sid="translate">21.7661 0 -13.6375</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape15">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere15</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere16" name="pSphere16">
+                    <translate sid="translate">-9.5945 -8.92317 -5.74901</translate>
+                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+                    <rotate sid="rotateY">0 1 0 158.666</rotate>
+                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape16">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere16</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere17" name="pSphere17">
+                    <translate sid="translate">-13.862 0 -13.6154</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape17">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere17</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere18" name="pSphere18">
+                    <translate sid="translate">-24.2135 6.497 -5.58935</translate>
+                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+                    <rotate sid="rotateY">0 1 0 158.666</rotate>
+                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape18">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere18</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>group2</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pCube2" name="pCube2">
+                <translate sid="translate">0 0 0</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pCubeShape2">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert8SG" target="#PlasticCenter">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pCube2</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pCube3" name="pCube3">
+                <translate sid="translate">15 0 0</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pCubeShape3">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert9SG" target="#PlasticRed">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pCube3</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pCube4" name="pCube4">
+                <translate sid="translate">0 15 0</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pCubeShape4">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert10SG" target="#lambert10">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pCube4</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pCube5" name="pCube5">
+                <translate sid="translate">0 0 15</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pCubeShape5">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert11SG" target="#lambert11">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pCube5</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+        </visual_scene>
+    </library_visual_scenes>
+    <scene>
+        <instance_visual_scene url="#VisualSceneNode" />
+    </scene>
+</COLLADA>
diff --git a/tests/RenderScriptTests/SceneGraph/assets/paint.jpg b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg
new file mode 100644
index 0000000..0791045
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/red.jpg b/tests/RenderScriptTests/SceneGraph/assets/red.jpg
new file mode 100644
index 0000000..320a2a6
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/red.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png
new file mode 100644
index 0000000..f7353fd
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml
new file mode 100644
index 0000000..9ea30107
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/load_model"
+          android:title="@string/load_model" />
+    <item android:id="@+id/use_blur"
+          android:title="@string/use_blur" />
+</menu>
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl
new file mode 100644
index 0000000..fa468cc
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl
@@ -0,0 +1,15 @@
+varying vec2 varTex0;
+
+void main() {
+   vec2 blurCoord = varTex0;
+   blurCoord.x = varTex0.x + UNI_blurOffset0;
+   vec3 col = texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.x = varTex0.x + UNI_blurOffset1;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.x = varTex0.x + UNI_blurOffset2;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.x = varTex0.x + UNI_blurOffset3;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+
+   gl_FragColor = vec4(col * 0.25, 0.0); //texture2D(UNI_Tex0, varTex0);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl
new file mode 100644
index 0000000..a644a3e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl
@@ -0,0 +1,17 @@
+varying vec2 varTex0;
+
+void main() {
+   vec2 blurCoord = varTex0;
+   blurCoord.y = varTex0.y + UNI_blurOffset0;
+   vec3 col = texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.y = varTex0.y + UNI_blurOffset1;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.y = varTex0.y + UNI_blurOffset2;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.y = varTex0.y + UNI_blurOffset3;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+
+   col = col * 0.25;
+
+   gl_FragColor = vec4(col, 0.0); //texture2D(UNI_Tex0, varTex0);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl
new file mode 100644
index 0000000..bc824b6
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl
@@ -0,0 +1,7 @@
+varying vec2 varTex0;
+
+void main() {
+   gl_Position = ATTRIB_position;
+   varTex0 = ATTRIB_texture0;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl
new file mode 100644
index 0000000..5d8938b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl
@@ -0,0 +1,19 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+   vec3 worldNorm = (varWorldNormal);
+
+   vec3 light0Vec = V;
+   vec3 light0R = reflect(light0Vec, worldNorm);
+   float light0_Diffuse = dot(worldNorm, light0Vec);
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * light0_Diffuse * 1.2;
+   gl_FragColor = col; //vec4(0.0, 1.0, 0.0, 0.0);
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl
new file mode 100644
index 0000000..51f0612
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl
@@ -0,0 +1,23 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+   vec3 worldNorm = normalize(varWorldNormal);
+
+   vec3 light0Vec = V;
+   vec3 light0R = reflect(light0Vec, worldNorm);
+   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+   float light0_Specular = pow(light0Spec, 15.0) * 0.5;
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * (textureCube(UNI_Tex1, worldNorm).rgb * 0.5 + vec3(light0_Diffuse));
+   col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl
new file mode 100644
index 0000000..893d553
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl
@@ -0,0 +1,26 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+   vec3 worldNorm = normalize(varWorldNormal);
+
+   vec3 light0Vec = V;
+   vec3 light0R = reflect(light0Vec, worldNorm);
+   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.01, 0.99);
+   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+   float light0_Specular = pow(light0Spec, 150.0) * 0.5;
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * light0_Diffuse * 1.1;
+   col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+
+   float fresnel = mix(pow(1.0 - light0_Diffuse, 15.0), 1.0, 0.1);
+   col.xyz = mix(col.xyz, textureCube(UNI_Tex1, -light0R).rgb * 2.4, fresnel);
+   col.w = 0.8;
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl
new file mode 100644
index 0000000..ceb53bd
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl
@@ -0,0 +1,22 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+   vec3 worldNorm = normalize(varWorldNormal);
+
+   vec3 light0Vec = V;
+   vec3 light0R = reflect(light0Vec, worldNorm);
+   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+   float light0_Specular = pow(light0Spec, 10.0) * 0.5;
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * light0_Diffuse * 1.2;
+   col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl
new file mode 100644
index 0000000..b253622
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl
@@ -0,0 +1,29 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+   vec3 worldNorm = normalize(varWorldNormal);
+
+   vec3 light0Vec = normalize(UNI_lightPos_0.xyz - varWorldPos.xyz);
+   vec3 light0R = reflect(light0Vec, worldNorm);
+   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+   float light0_Specular = pow(light0Spec, 10.0) * 0.7;
+
+   vec3 light1Vec = normalize(UNI_lightPos_1.xyz - varWorldPos.xyz);
+   vec3 light1R = reflect(light1Vec, worldNorm);
+   float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0);
+   float light1Spec = clamp(dot(-light1R, V), 0.001, 1.0);
+   float light1_Specular = pow(light1Spec, 10.0) * 0.7;
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = UNI_diffuse;
+   col.xyz = col.xyz * (light0_Diffuse * UNI_lightColor_0.xyz +
+                        light1_Diffuse * UNI_lightColor_1.xyz);
+   col.xyz += (light0_Specular + light1_Specular);
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d
new file mode 100644
index 0000000..f48895c
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl
new file mode 100644
index 0000000..42b231a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl
@@ -0,0 +1,13 @@
+varying vec2 varTex0;
+
+void main() {
+   vec3 col = texture2D(UNI_Tex0, varTex0).rgb;
+
+   vec3 desat = vec3(0.299, 0.587, 0.114);
+   float lum = dot(desat, col);
+   float stepVal = step(lum, 0.8);
+   col = mix(col, vec3(0.0), stepVal)*0.5;
+
+   gl_FragColor = vec4(col, 0.0);
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl
new file mode 100644
index 0000000..1ea234f
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl
@@ -0,0 +1,17 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+   vec4 objPos = ATTRIB_position;
+   vec4 worldPos = UNI_model * objPos;
+   gl_Position = UNI_viewProj * worldPos;
+
+   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+   vec3 worldNorm = model3 * ATTRIB_normal;
+
+   varWorldPos = worldPos.xyz;
+   varWorldNormal = worldNorm;
+   varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl
new file mode 100644
index 0000000..dd709cf
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl
@@ -0,0 +1,7 @@
+varying vec2 varTex0;
+
+void main() {
+   lowp vec4 col = texture2D(UNI_Tex0, varTex0).rgba;
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/values/strings.xml b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml
new file mode 100644
index 0000000..c916d79
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <skip />
+    <string name="load_model">Load Model</string>
+    <string name="use_blur">Use Blur</string>
+</resources>
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
new file mode 100644
index 0000000..42f2be5
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.*;
+import android.renderscript.Matrix4f;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Camera extends SceneGraphBase {
+
+    Transform mTransform;
+
+    ScriptField_Camera_s.Item mData;
+    ScriptField_Camera_s mField;
+
+    public Camera() {
+        mData = new ScriptField_Camera_s.Item();
+        mData.near = 0.1f;
+        mData.far = 1000.0f;
+        mData.horizontalFOV = 60.0f;
+        mData.aspect = 0;
+    }
+
+    public void setTransform(Transform t) {
+        mTransform = t;
+        if (mField != null) {
+            mField.set_transformMatrix(0, mTransform.getRSData().getAllocation(), true);
+            mField.set_isDirty(0, 1, true);
+        }
+    }
+    public void setFOV(float fov) {
+        mData.horizontalFOV = fov;
+        if (mField != null) {
+            mField.set_horizontalFOV(0, fov, true);
+            mField.set_isDirty(0, 1, true);
+        }
+    }
+
+    public void setNear(float n) {
+        mData.near = n;
+        if (mField != null) {
+            mField.set_near(0, n, true);
+            mField.set_isDirty(0, 1, true);
+        }
+    }
+
+    public void setFar(float f) {
+        mData.far = f;
+        if (mField != null) {
+            mField.set_far(0, f, true);
+            mField.set_isDirty(0, 1, true);
+        }
+    }
+
+    public void setName(String n) {
+        super.setName(n);
+        if (mField != null) {
+            RenderScriptGL rs = SceneManager.getRS();
+            mData.name = getNameAlloc(rs);
+            mField.set_name(0, mData.name, true);
+            mField.set_isDirty(0, 1, true);
+        }
+    }
+
+    ScriptField_Camera_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        if (rs == null) {
+            return null;
+        }
+
+        if (mTransform == null) {
+            throw new RuntimeException("Cameras without transforms are invalid");
+        }
+
+        mField = new ScriptField_Camera_s(rs, 1);
+
+        mData.transformMatrix = mTransform.getRSData().getAllocation();
+        mData.transformTimestamp = 1;
+        mData.timestamp = 1;
+        mData.isDirty = 1;
+        mData.name = getNameAlloc(rs);
+        mField.set(mData, 0, true);
+
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
new file mode 100644
index 0000000..d954313
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
@@ -0,0 +1,563 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+package com.android.scenegraph;

+import com.android.scenegraph.CompoundTransform.TranslateComponent;

+import com.android.scenegraph.CompoundTransform.RotateComponent;

+import com.android.scenegraph.CompoundTransform.ScaleComponent;

+import java.io.IOException;

+import java.io.InputStream;

+import java.util.ArrayList;

+import java.util.Iterator;

+import java.util.List;

+import java.util.StringTokenizer;

+import java.util.HashMap;

+

+import javax.xml.parsers.DocumentBuilder;

+import javax.xml.parsers.DocumentBuilderFactory;

+import javax.xml.parsers.ParserConfigurationException;

+

+import org.w3c.dom.Document;

+import org.w3c.dom.Element;

+import org.w3c.dom.Node;

+import org.w3c.dom.NodeList;

+import org.xml.sax.SAXException;

+

+import android.renderscript.*;

+import android.util.Log;

+

+public class ColladaParser {

+    static final String TAG = "ColladaParser";

+    Document mDom;

+

+    HashMap<String, LightBase> mLights;

+    HashMap<String, Camera> mCameras;

+    HashMap<String, ArrayList<ShaderParam> > mEffectsParams;

+    HashMap<String, Texture2D> mImages;

+    HashMap<String, Texture2D> mSamplerImageMap;

+    HashMap<String, String> mMeshIdNameMap;

+    Scene mScene;

+

+    String mRootDir;

+

+    String toString(Float3 v) {

+        String valueStr = v.x + " " + v.y + " " + v.z;

+        return valueStr;

+    }

+

+    String toString(Float4 v) {

+        String valueStr = v.x + " " + v.y + " " + v.z + " " + v.w;

+        return valueStr;

+    }

+

+    public ColladaParser(){

+        mLights = new HashMap<String, LightBase>();

+        mCameras = new HashMap<String, Camera>();

+        mEffectsParams = new HashMap<String, ArrayList<ShaderParam> >();

+        mImages = new HashMap<String, Texture2D>();

+        mMeshIdNameMap = new HashMap<String, String>();

+    }

+

+    public void init(InputStream is, String rootDir) {

+        mLights.clear();

+        mCameras.clear();

+        mEffectsParams.clear();

+

+        mRootDir = rootDir;

+

+        long start = System.currentTimeMillis();

+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

+        try {

+            DocumentBuilder db = dbf.newDocumentBuilder();

+            mDom = db.parse(is);

+        } catch(ParserConfigurationException e) {

+            e.printStackTrace();

+        } catch(SAXException e) {

+            e.printStackTrace();

+        } catch(IOException e) {

+            e.printStackTrace();

+        }

+        long end = System.currentTimeMillis();

+        Log.v("TIMER", "    Parse time: " + (end - start));

+        exportSceneData();

+    }

+

+    Scene getScene() {

+        return mScene;

+    }

+

+    private void exportSceneData(){

+        mScene = new Scene();

+

+        Element docEle = mDom.getDocumentElement();

+        NodeList nl = docEle.getElementsByTagName("light");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element l = (Element)nl.item(i);

+                convertLight(l);

+            }

+        }

+

+        nl = docEle.getElementsByTagName("camera");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element c = (Element)nl.item(i);

+                convertCamera(c);

+            }

+        }

+

+        nl = docEle.getElementsByTagName("image");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element img = (Element)nl.item(i);

+                convertImage(img);

+            }

+        }

+

+        nl = docEle.getElementsByTagName("effect");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element e = (Element)nl.item(i);

+                convertEffects(e);

+            }

+        }

+

+        // Material is just a link to the effect

+        nl = docEle.getElementsByTagName("material");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element m = (Element)nl.item(i);

+                convertMaterials(m);

+            }

+        }

+

+        // Look through the geometry list and build up a correlation between id's and names

+        nl = docEle.getElementsByTagName("geometry");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element m = (Element)nl.item(i);

+                convertGeometries(m);

+            }

+        }

+

+

+        nl = docEle.getElementsByTagName("visual_scene");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element s = (Element)nl.item(i);

+                getScene(s);

+            }

+        }

+    }

+

+    private void getRenderable(Element shape, Transform t) {

+        String geoURL = shape.getAttribute("url").substring(1);

+        String geoName = mMeshIdNameMap.get(geoURL);

+        if (geoName != null) {

+            geoURL = geoName;

+        }

+        //RenderableGroup group = new RenderableGroup();

+        //group.setName(geoURL.substring(1));

+        //mScene.appendRenderable(group);

+        NodeList nl = shape.getElementsByTagName("instance_material");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element materialRef = (Element)nl.item(i);

+                String meshIndexName = materialRef.getAttribute("symbol");

+                String materialName = materialRef.getAttribute("target");

+

+                Renderable d = new Renderable();

+                d.setMesh(geoURL, meshIndexName);

+                d.setMaterialName(materialName.substring(1));

+                d.setName(geoURL);

+

+                //Log.v(TAG, "Created drawable geo " + geoURL + " index " + meshIndexName + " material " + materialName);

+

+                d.setTransform(t);

+                //Log.v(TAG, "Set source param " + t.getName());

+

+                // Now find all the parameters that exist on the material

+                ArrayList<ShaderParam> materialParams;

+                materialParams = mEffectsParams.get(materialName.substring(1));

+                for (int pI = 0; pI < materialParams.size(); pI ++) {

+                    d.appendSourceParams(materialParams.get(pI));

+                    //Log.v(TAG, "Set source param i: " + pI + " name " + materialParams.get(pI).getParamName());

+                }

+                mScene.appendRenderable(d);

+                //group.appendChildren(d);

+            }

+        }

+    }

+

+    private void updateLight(Element shape, Transform t) {

+        String lightURL = shape.getAttribute("url");

+        // collada uses a uri structure to link things,

+        // but we ignore it for now and do a simple search

+        LightBase light = mLights.get(lightURL.substring(1));

+        if (light != null) {

+            light.setTransform(t);

+            //Log.v(TAG, "Set Light " + light.getName() + " " + t.getName());

+        }

+    }

+

+    private void updateCamera(Element shape, Transform t) {

+        String camURL = shape.getAttribute("url");

+        // collada uses a uri structure to link things,

+        // but we ignore it for now and do a simple search

+        Camera cam = mCameras.get(camURL.substring(1));

+        if (cam != null) {

+            cam.setTransform(t);

+            //Log.v(TAG, "Set Camera " + cam.getName() + " " + t.getName());

+        }

+    }

+

+    private void getNode(Element node, Transform parent, String indent) {

+        String name = node.getAttribute("name");

+        String id = node.getAttribute("id");

+        CompoundTransform current = new CompoundTransform();

+        current.setName(name);

+        if (parent != null) {

+            parent.appendChild(current);

+        } else {

+            mScene.appendTransform(current);

+        }

+

+        mScene.addToTransformMap(current);

+

+        //Log.v(TAG, indent + "|");

+        //Log.v(TAG, indent + "[" + name + "]");

+

+        Node childNode = node.getFirstChild();

+        while (childNode != null) {

+            if (childNode.getNodeType() == Node.ELEMENT_NODE) {

+                Element field = (Element)childNode;

+                String fieldName = field.getTagName();

+                String description = field.getAttribute("sid");

+                if (fieldName.equals("translate")) {

+                    Float3 value = getFloat3(field);

+                    current.addComponent(new TranslateComponent(description, value));

+                    //Log.v(TAG, indent + " translate " + description + toString(value));

+                } else if (fieldName.equals("rotate")) {

+                    Float4 value = getFloat4(field);

+                    //Log.v(TAG, indent + " rotate " + description + toString(value));

+                    Float3 axis = new Float3(value.x, value.y, value.z);

+                    current.addComponent(new RotateComponent(description, axis, value.w));

+                } else if (fieldName.equals("scale")) {

+                    Float3 value = getFloat3(field);

+                    //Log.v(TAG, indent + " scale " + description + toString(value));

+                    current.addComponent(new ScaleComponent(description, value));

+                } else if (fieldName.equals("instance_geometry")) {

+                    getRenderable(field, current);

+                } else if (fieldName.equals("instance_light")) {

+                    updateLight(field, current);

+                } else if (fieldName.equals("instance_camera")) {

+                    updateCamera(field, current);

+                } else if (fieldName.equals("node")) {

+                    getNode(field, current, indent + "   ");

+                }

+            }

+            childNode = childNode.getNextSibling();

+        }

+    }

+

+    // This will find the actual texture node, which is sometimes hidden behind a sampler

+    // and sometimes referenced directly

+    Texture2D getTexture(String samplerName) {

+        String texName = samplerName;

+

+        // Check to see if the image file is hidden by a sampler surface link combo

+        Element sampler = mDom.getElementById(samplerName);

+        if (sampler != null) {

+            NodeList nl = sampler.getElementsByTagName("source");

+            if (nl != null && nl.getLength() == 1) {

+                Element ref = (Element)nl.item(0);

+                String surfaceName = getString(ref);

+                if (surfaceName == null) {

+                    return null;

+                }

+

+                Element surface = mDom.getElementById(surfaceName);

+                if (surface == null) {

+                    return null;

+                }

+                nl = surface.getElementsByTagName("init_from");

+                if (nl != null && nl.getLength() == 1) {

+                    ref = (Element)nl.item(0);

+                    texName = getString(ref);

+                }

+            }

+        }

+

+        //Log.v(TAG, "Extracted texture name " + texName);

+        return mImages.get(texName);

+    }

+

+    void extractParams(Element fx, ArrayList<ShaderParam> params) {

+        Node paramNode = fx.getFirstChild();

+        while (paramNode != null) {

+            if (paramNode.getNodeType() == Node.ELEMENT_NODE) {

+                String name = paramNode.getNodeName();

+                // Now find what type it is

+                Node typeNode = paramNode.getFirstChild();

+                while (typeNode != null && typeNode.getNodeType() != Node.ELEMENT_NODE) {

+                    typeNode = typeNode.getNextSibling();

+                }

+                String paramType = typeNode.getNodeName();

+                Element typeElem = (Element)typeNode;

+                ShaderParam sceneParam = null;

+                if (paramType.equals("color")) {

+                    Float4Param f4p = new Float4Param(name);

+                    Float4 value = getFloat4(typeElem);

+                    f4p.setValue(value);

+                    sceneParam = f4p;

+                    //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + toString(value));

+                } else if (paramType.equals("float")) {

+                    Float4Param f4p = new Float4Param(name);

+                    float value = getFloat(typeElem);

+                    f4p.setValue(new Float4(value, value, value, value));

+                    sceneParam = f4p;

+                    //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + value);

+                }  else if (paramType.equals("texture")) {

+                    String samplerName = typeElem.getAttribute("texture");

+                    Texture2D tex = getTexture(samplerName);

+                    TextureParam texP = new TextureParam(name);

+                    texP.setTexture(tex);

+                    sceneParam = texP;

+                    //Log.v(TAG, "Extracted texture " + tex);

+                }

+                if (sceneParam != null) {

+                    params.add(sceneParam);

+                }

+            }

+            paramNode = paramNode.getNextSibling();

+        }

+    }

+

+    private void convertMaterials(Element mat) {

+        String id = mat.getAttribute("id");

+        NodeList nl = mat.getElementsByTagName("instance_effect");

+        if (nl != null && nl.getLength() == 1) {

+            Element ref = (Element)nl.item(0);

+            String url = ref.getAttribute("url");

+            ArrayList<ShaderParam> params = mEffectsParams.get(url.substring(1));

+            mEffectsParams.put(id, params);

+        }

+    }

+

+    private void convertGeometries(Element geo) {

+        String id = geo.getAttribute("id");

+        String name = geo.getAttribute("name");

+        if (!id.equals(name)) {

+            mMeshIdNameMap.put(id, name);

+        }

+    }

+

+    private void convertEffects(Element fx) {

+        String id = fx.getAttribute("id");

+        ArrayList<ShaderParam> params = new ArrayList<ShaderParam>();

+

+        NodeList nl = fx.getElementsByTagName("newparam");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element field = (Element)nl.item(i);

+                field.setIdAttribute("sid", true);

+            }

+        }

+

+        nl = fx.getElementsByTagName("blinn");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element field = (Element)nl.item(i);

+                //Log.v(TAG, "blinn");

+                extractParams(field, params);

+            }

+        }

+        nl = fx.getElementsByTagName("lambert");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element field = (Element)nl.item(i);

+                //Log.v(TAG, "lambert");

+                extractParams(field, params);

+            }

+        }

+        nl = fx.getElementsByTagName("phong");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element field = (Element)nl.item(i);

+                //Log.v(TAG, "phong");

+                extractParams(field, params);

+            }

+        }

+        mEffectsParams.put(id, params);

+    }

+

+    private void convertLight(Element light) {

+        String name = light.getAttribute("name");

+        String id = light.getAttribute("id");

+

+        // Determine type

+        String[] knownTypes = { "point", "spot", "directional" };

+        final int POINT_LIGHT = 0;

+        final int SPOT_LIGHT = 1;

+        final int DIR_LIGHT = 2;

+        int type = -1;

+        for (int i = 0; i < knownTypes.length; i ++) {

+            NodeList nl = light.getElementsByTagName(knownTypes[i]);

+            if (nl != null && nl.getLength() != 0) {

+                type = i;

+                break;

+            }

+        }

+

+        //Log.v(TAG, "Found Light Type " + type);

+

+        LightBase sceneLight = null;

+        switch (type) {

+        case POINT_LIGHT:

+            sceneLight = new PointLight();

+            break;

+        case SPOT_LIGHT: // TODO: finish light types

+            break;

+        case DIR_LIGHT: // TODO: finish light types

+            break;

+        }

+

+        if (sceneLight == null) {

+            return;

+        }

+

+        Float3 color = getFloat3(light, "color");

+        sceneLight.setColor(color.x, color.y, color.z);

+        sceneLight.setName(name);

+        mScene.appendLight(sceneLight);

+        mLights.put(id, sceneLight);

+

+        //Log.v(TAG, "Light " + name + " color " + toString(color));

+    }

+

+    private void convertCamera(Element camera) {

+        String name = camera.getAttribute("name");

+        String id = camera.getAttribute("id");

+        float fov = 30.0f;

+        if (getString(camera, "yfov") != null) {

+            fov = getFloat(camera, "yfov");

+        } else if(getString(camera, "xfov") != null) {

+            float aspect = getFloat(camera, "aspect_ratio");

+            fov = getFloat(camera, "xfov") / aspect;

+        }

+

+        float near = getFloat(camera, "znear");

+        float far = getFloat(camera, "zfar");

+

+        Camera sceneCamera = new Camera();

+        sceneCamera.setFOV(fov);

+        sceneCamera.setNear(near);

+        sceneCamera.setFar(far);

+        sceneCamera.setName(name);

+        mScene.appendCamera(sceneCamera);

+        mCameras.put(id, sceneCamera);

+    }

+

+    private void convertImage(Element img) {

+        String name = img.getAttribute("name");

+        String id = img.getAttribute("id");

+        String file = getString(img, "init_from");

+

+        Texture2D tex = new Texture2D();

+        tex.setFileName(file);

+        tex.setFileDir(mRootDir);

+        mScene.appendTextures(tex);

+        mImages.put(id, tex);

+    }

+

+    private void getScene(Element scene) {

+        String name = scene.getAttribute("name");

+        String id = scene.getAttribute("id");

+

+        Node childNode = scene.getFirstChild();

+        while (childNode != null) {

+            if (childNode.getNodeType() == Node.ELEMENT_NODE) {

+                String indent = "";

+                getNode((Element)childNode, null, indent);

+            }

+            childNode = childNode.getNextSibling();

+        }

+    }

+

+    private String getString(Element elem, String name) {

+        String text = null;

+        NodeList nl = elem.getElementsByTagName(name);

+        if (nl != null && nl.getLength() != 0) {

+            text = ((Element)nl.item(0)).getFirstChild().getNodeValue();

+        }

+        return text;

+    }

+

+    private String getString(Element elem) {

+        String text = null;

+        text = elem.getFirstChild().getNodeValue();

+        return text;

+    }

+

+    private int getInt(Element elem, String name) {

+        return Integer.parseInt(getString(elem, name));

+    }

+

+    private float getFloat(Element elem, String name) {

+        return Float.parseFloat(getString(elem, name));

+    }

+

+    private float getFloat(Element elem) {

+        return Float.parseFloat(getString(elem));

+    }

+

+    private Float3 parseFloat3(String valueString) {

+        StringTokenizer st = new StringTokenizer(valueString);

+        float x = Float.parseFloat(st.nextToken());

+        float y = Float.parseFloat(st.nextToken());

+        float z = Float.parseFloat(st.nextToken());

+        return new Float3(x, y, z);

+    }

+

+    private Float4 parseFloat4(String valueString) {

+        StringTokenizer st = new StringTokenizer(valueString);

+        float x = Float.parseFloat(st.nextToken());

+        float y = Float.parseFloat(st.nextToken());

+        float z = Float.parseFloat(st.nextToken());

+        float w = Float.parseFloat(st.nextToken());

+        return new Float4(x, y, z, w);

+    }

+

+    private Float3 getFloat3(Element elem, String name) {

+        String valueString = getString(elem, name);

+        return parseFloat3(valueString);

+    }

+

+    private Float4 getFloat4(Element elem, String name) {

+        String valueString = getString(elem, name);

+        return parseFloat4(valueString);

+    }

+

+    private Float3 getFloat3(Element elem) {

+        String valueString = getString(elem);

+        return parseFloat3(valueString);

+    }

+

+    private Float4 getFloat4(Element elem) {

+        String valueString = getString(elem);

+        return parseFloat4(valueString);

+    }

+}

diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java
new file mode 100644
index 0000000..301075e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+import com.android.scenegraph.SceneManager.SceneLoadedCallback;
+
+
+public class ColladaScene {
+
+    private String modelName;
+    private static String TAG = "ColladaScene";
+    private final int STATE_LAST_FOCUS = 1;
+    boolean mLoadFromSD = false;
+
+    SceneLoadedCallback mCallback;
+
+    public ColladaScene(String name, SceneLoadedCallback cb) {
+        modelName = name;
+        mCallback = cb;
+    }
+
+    public void init(RenderScriptGL rs, Resources res) {
+        mRS = rs;
+        mRes = res;
+
+        mLoadFromSD = SceneManager.isSDCardPath(modelName);
+
+        new ColladaLoaderTask().execute(modelName);
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    Scene mActiveScene;
+
+    private class ColladaLoaderTask extends AsyncTask<String, Void, Boolean> {
+        ColladaParser sceneSource;
+        protected Boolean doInBackground(String... names) {
+            String rootDir = names[0].substring(0, names[0].lastIndexOf('/') + 1);
+            long start = System.currentTimeMillis();
+            sceneSource = new ColladaParser();
+            InputStream is = null;
+            try {
+                if (!mLoadFromSD) {
+                    is = mRes.getAssets().open(names[0]);
+                } else {
+                    File f = new File(names[0]);
+                    is = new BufferedInputStream(new FileInputStream(f));
+                }
+            } catch (IOException e) {
+                Log.e(TAG, "Could not open collada file");
+                return new Boolean(false);
+            }
+            long end = System.currentTimeMillis();
+            Log.v("TIMER", "Stream load time: " + (end - start));
+
+            start = System.currentTimeMillis();
+            sceneSource.init(is, rootDir);
+            end = System.currentTimeMillis();
+            Log.v("TIMER", "Collada parse time: " + (end - start));
+            return new Boolean(true);
+        }
+
+        protected void onPostExecute(Boolean result) {
+            mActiveScene = sceneSource.getScene();
+            if (mCallback != null) {
+                mCallback.mLoadedScene = mActiveScene;
+                mCallback.run();
+            }
+
+            String shortName = modelName.substring(0, modelName.lastIndexOf('.'));
+            new A3DLoaderTask().execute(shortName + ".a3d");
+        }
+    }
+
+    private class A3DLoaderTask extends AsyncTask<String, Void, Boolean> {
+        protected Boolean doInBackground(String... names) {
+            long start = System.currentTimeMillis();
+            FileA3D model;
+            if (!mLoadFromSD) {
+                model = FileA3D.createFromAsset(mRS, mRes.getAssets(), names[0]);
+            } else {
+                model = FileA3D.createFromFile(mRS, names[0]);
+            }
+            int numModels = model.getIndexEntryCount();
+            for (int i = 0; i < numModels; i ++) {
+                FileA3D.IndexEntry entry = model.getIndexEntry(i);
+                if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
+                    mActiveScene.meshLoaded(entry.getMesh());
+                }
+            }
+            long end = System.currentTimeMillis();
+            Log.v("TIMER", "A3D load time: " + (end - start));
+            return new Boolean(true);
+        }
+
+        protected void onPostExecute(Boolean result) {
+        }
+    }
+
+}
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
new file mode 100644
index 0000000..d995dd0
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.*;
+import android.renderscript.Float3;
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class CompoundTransform extends Transform {
+
+    public static abstract class Component {
+        String mName;
+        CompoundTransform mParent;
+        int mParentIndex;
+        protected ScriptField_TransformComponent_s.Item mData;
+
+        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;
+            }
+            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() {
+            return mName;
+        }
+    }
+
+    public static class TranslateComponent extends Component {
+        public TranslateComponent(String name, Float3 translate) {
+            super(ScriptC_export.const_Transform_TRANSLATE, name);
+            setValue(translate);
+        }
+        public Float3 getValue() {
+            return new Float3(mData.value.x, mData.value.y, mData.value.z);
+        }
+        public void setValue(Float3 val) {
+            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) {
+            super(ScriptC_export.const_Transform_ROTATE, name);
+            setAxis(axis);
+            setAngle(angle);
+        }
+        public Float3 getAxis() {
+            return new Float3(mData.value.x, mData.value.y, mData.value.z);
+        }
+        public float getAngle() {
+            return mData.value.w;
+        }
+        public void setAxis(Float3 val) {
+            mData.value.x = val.x;
+            mData.value.y = val.y;
+            mData.value.z = val.z;
+            update();
+        }
+        public void setAngle(float val) {
+            mData.value.w = val;
+            update();
+        }
+    }
+
+    public static class ScaleComponent extends Component {
+        public ScaleComponent(String name, Float3 scale) {
+            super(ScriptC_export.const_Transform_SCALE, name);
+            setValue(scale);
+        }
+        public Float3 getValue() {
+            return new Float3(mData.value.x, mData.value.y, mData.value.z);
+        }
+        public void setValue(Float3 val) {
+            mData.value.x = val.x;
+            mData.value.y = val.y;
+            mData.value.z = val.z;
+            update();
+        }
+    }
+
+    ScriptField_TransformComponent_s mComponentField;
+    public ArrayList<Component> mTransformComponents;
+
+    public CompoundTransform() {
+        mTransformComponents = new ArrayList<Component>();
+    }
+
+    public void addComponent(Component c) {
+        if (c.mParent != null) {
+            throw new IllegalArgumentException("Transform components may not be shared");
+        }
+        c.mParent = this;
+        c.mParentIndex = mTransformComponents.size();
+        mTransformComponents.add(c);
+        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);
+        updateRSComponent(c);
+    }
+
+    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;
+        }
+        initLocalData();
+
+        mField.set_components(0, mTransformData.components, false);
+        mField.set_isDirty(0, 1, true);
+    }
+
+    void initLocalData() {
+        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
new file mode 100644
index 0000000..1502458
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.Scene;
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.Element;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Float4Param extends ShaderParam {
+    private static String TAG = "Float4Param";
+
+    LightBase mLight;
+
+    public Float4Param(String name) {
+        super(name);
+    }
+
+    public Float4Param(String name, float x) {
+        super(name);
+        set(x, 0, 0, 0);
+    }
+
+    public Float4Param(String name, float x, float y) {
+        super(name);
+        set(x, y, 0, 0);
+    }
+
+    public Float4Param(String name, float x, float y, float z) {
+        super(name);
+        set(x, y, z, 0);
+    }
+
+    public Float4Param(String name, float x, float y, float z, float w) {
+        super(name);
+        set(x, y, z, w);
+    }
+
+    void set(float x, float y, float z, float w) {
+        mData.float_value.x = x;
+        mData.float_value.y = y;
+        mData.float_value.z = z;
+        mData.float_value.w = w;
+        if (mField != null) {
+            mField.set_float_value(0, mData.float_value, true);
+        }
+        incTimestamp();
+    }
+
+    public void setValue(Float4 v) {
+        set(v.x, v.y, v.z, v.w);
+    }
+
+    public Float4 getValue() {
+        return mData.float_value;
+    }
+
+    public void setLight(LightBase l) {
+        mLight = l;
+        if (mField != null) {
+            mData.light = mLight.getRSData().getAllocation();
+            mField.set_light(0, mData.light, true);
+        }
+        incTimestamp();
+    }
+
+    boolean findLight(String property) {
+        String indexStr = mParamName.substring(property.length() + 1);
+        if (indexStr == null) {
+            Log.e(TAG, "Invalid light index.");
+            return false;
+        }
+        int index = Integer.parseInt(indexStr);
+        if (index == -1) {
+            return false;
+        }
+        Scene parentScene = SceneManager.getInstance().getActiveScene();
+        ArrayList<LightBase> allLights = parentScene.getLights();
+        if (index >= allLights.size()) {
+            return false;
+        }
+        mLight = allLights.get(index);
+        if (mLight == null) {
+            return false;
+        }
+        return true;
+    }
+
+    int getTypeFromName() {
+        int paramType = ScriptC_export.const_ShaderParam_FLOAT4_DATA;
+        if (mParamName.equalsIgnoreCase(cameraPos)) {
+            paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_POS;
+        } else if(mParamName.equalsIgnoreCase(cameraDir)) {
+            paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_DIR;
+        } else if(mParamName.startsWith(lightColor) && findLight(lightColor)) {
+            paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_COLOR;
+        } else if(mParamName.startsWith(lightPos) && findLight(lightPos)) {
+            paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_POS;
+        } else if(mParamName.startsWith(lightDir) && findLight(lightDir)) {
+            paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_DIR;
+        }
+        return paramType;
+    }
+
+    void initLocalData() {
+        mData.type = getTypeFromName();
+        if (mCamera != null) {
+            mData.camera = mCamera.getRSData().getAllocation();
+        }
+        if (mLight != null) {
+            mData.light = mLight.getRSData().getAllocation();
+        }
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
new file mode 100644
index 0000000..c8cc3ac
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramFragment.Builder;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class FragmentShader extends Shader {
+    ProgramFragment mProgram;
+    ScriptField_FragmentShader_s mField;
+
+    public static class Builder {
+
+        FragmentShader mShader;
+        ProgramFragment.Builder mBuilder;
+
+        public Builder(RenderScriptGL rs) {
+            mShader = new FragmentShader();
+            mBuilder = new ProgramFragment.Builder(rs);
+        }
+
+        public Builder setShader(Resources resources, int resourceID) {
+            mBuilder.setShader(resources, resourceID);
+            return this;
+        }
+
+        public Builder setObjectConst(Type type) {
+            mShader.mPerObjConstants = type;
+            return this;
+        }
+
+        public Builder setShaderConst(Type type) {
+            mShader.mPerShaderConstants = type;
+            return this;
+        }
+
+        public Builder addShaderTexture(Program.TextureType texType, String name) {
+            mShader.mShaderTextureNames.add(name);
+            mShader.mShaderTextureTypes.add(texType);
+            return this;
+        }
+
+        public Builder addTexture(Program.TextureType texType, String name) {
+            mShader.mTextureNames.add(name);
+            mShader.mTextureTypes.add(texType);
+            return this;
+        }
+
+        public FragmentShader create() {
+            if (mShader.mPerShaderConstants != null) {
+                mBuilder.addConstant(mShader.mPerShaderConstants);
+            }
+            if (mShader.mPerObjConstants != null) {
+                mBuilder.addConstant(mShader.mPerObjConstants);
+            }
+            for (int i = 0; i < mShader.mTextureTypes.size(); i ++) {
+                mBuilder.addTexture(mShader.mTextureTypes.get(i));
+            }
+            for (int i = 0; i < mShader.mShaderTextureTypes.size(); i ++) {
+                mBuilder.addTexture(mShader.mShaderTextureTypes.get(i));
+            }
+
+            mShader.mProgram = mBuilder.create();
+            return mShader;
+        }
+    }
+
+    public ProgramFragment getProgram() {
+        return mProgram;
+    }
+
+    ScriptField_ShaderParam_s getTextureParams() {
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        if (rs == null || res == null) {
+            return null;
+        }
+
+        ArrayList<ScriptField_ShaderParam_s.Item> paramList;
+        paramList = new ArrayList<ScriptField_ShaderParam_s.Item>();
+
+        int shaderTextureStart = mTextureTypes.size();
+        for (int i = 0; i < mShaderTextureNames.size(); i ++) {
+            ShaderParam sp = mSourceParams.get(mShaderTextureNames.get(i));
+            if (sp != null && sp instanceof TextureParam) {
+                TextureParam p = (TextureParam)sp;
+                ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item();
+                paramRS.bufferOffset = shaderTextureStart + i;
+                paramRS.transformTimestamp = 0;
+                paramRS.dataTimestamp = 0;
+                paramRS.data = p.getRSData().getAllocation();
+                paramList.add(paramRS);
+            }
+        }
+
+        ScriptField_ShaderParam_s rsParams = null;
+        int paramCount = paramList.size();
+        if (paramCount != 0) {
+            rsParams = new ScriptField_ShaderParam_s(rs, paramCount);
+            for (int i = 0; i < paramCount; i++) {
+                rsParams.set(paramList.get(i), i, false);
+            }
+            rsParams.copyAll();
+        }
+        return rsParams;
+    }
+
+    ScriptField_FragmentShader_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        if (rs == null || res == null) {
+            return null;
+        }
+
+        ScriptField_FragmentShader_s.Item item = new ScriptField_FragmentShader_s.Item();
+        item.program = mProgram;
+
+        ScriptField_ShaderParam_s texParams = getTextureParams();
+        if (texParams != null) {
+            item.shaderTextureParams = texParams.getAllocation();
+        }
+
+        linkConstants(rs);
+        if (mPerShaderConstants != null) {
+            item.shaderConst = mConstantBuffer;
+            item.shaderConstParams = mConstantBufferParams.getAllocation();
+            mProgram.bindConstants(item.shaderConst, 0);
+        }
+
+        item.objectConstIndex = -1;
+        if (mPerObjConstants != null) {
+            item.objectConstIndex = mPerShaderConstants != null ? 1 : 0;
+        }
+
+        mField = new ScriptField_FragmentShader_s(rs, 1);
+        mField.set(item, 0, true);
+        return mField;
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java
new file mode 100644
index 0000000..8f5e2e7
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Float3;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class LightBase extends SceneGraphBase {
+    static final int RS_LIGHT_POINT = 0;
+    static final int RS_LIGHT_DIRECTIONAL = 1;
+
+    ScriptField_Light_s mField;
+    ScriptField_Light_s.Item mFieldData;
+    Transform mTransform;
+    Float4 mColor;
+    float mIntensity;
+    public LightBase() {
+        mColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f);
+        mIntensity = 1.0f;
+    }
+
+    public void setTransform(Transform t) {
+        mTransform = t;
+        updateRSData();
+    }
+
+    public void setColor(float r, float g, float b) {
+        mColor.x = r;
+        mColor.y = g;
+        mColor.z = b;
+        updateRSData();
+    }
+
+    public void setColor(Float3 c) {
+        setColor(c.x, c.y, c.z);
+    }
+
+    public void setIntensity(float i) {
+        mIntensity = i;
+        updateRSData();
+    }
+
+    public void setName(String n) {
+        super.setName(n);
+        updateRSData();
+    }
+
+    protected void updateRSData() {
+        if (mField == null) {
+            return;
+        }
+        RenderScriptGL rs = SceneManager.getRS();
+        mFieldData.transformMatrix = mTransform.getRSData().getAllocation();
+        mFieldData.name = getNameAlloc(rs);
+        mFieldData.color = mColor;
+        mFieldData.intensity = mIntensity;
+
+        initLocalData();
+
+        mField.set(mFieldData, 0, true);
+    }
+
+    abstract void initLocalData();
+
+    ScriptField_Light_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        if (rs == null) {
+            return null;
+        }
+        if (mField == null) {
+            mField = new ScriptField_Light_s(rs, 1);
+            mFieldData = new ScriptField_Light_s.Item();
+        }
+
+        updateRSData();
+
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
new file mode 100644
index 0000000..6d70bc9
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class MatrixTransform extends Transform {
+
+    Matrix4f mLocalMatrix;
+    public MatrixTransform() {
+        mLocalMatrix = new Matrix4f();
+    }
+
+    public void setMatrix(Matrix4f matrix) {
+        mLocalMatrix = matrix;
+        updateRSData();
+    }
+
+    public Matrix4f getMatrix() {
+        return new Matrix4f(mLocalMatrix.getArray());
+    }
+
+    void initLocalData() {
+        mTransformData.localMat = mLocalMatrix;
+    }
+
+    void updateRSData() {
+        if (mField == null) {
+            return;
+        }
+        mField.set_localMat(0, mLocalMatrix, false);
+        mField.set_isDirty(0, 1, true);
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java
new file mode 100644
index 0000000..574bafc
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class PointLight extends LightBase {
+    public PointLight() {
+    }
+
+     void initLocalData() {
+        mFieldData.type = RS_LIGHT_POINT;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java
new file mode 100644
index 0000000..02fd69d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.util.Log;
+
+import android.renderscript.*;
+import android.content.res.Resources;
+
+/**
+ * @hide
+ */
+public class RenderPass extends SceneGraphBase {
+
+    TextureRenderTarget mColorTarget;
+    Float4 mClearColor;
+    boolean mShouldClearColor;
+
+    TextureRenderTarget mDepthTarget;
+    float mClearDepth;
+    boolean mShouldClearDepth;
+
+    ArrayList<RenderableBase> mObjectsToDraw;
+
+    Camera mCamera;
+
+    ScriptField_RenderPass_s.Item mRsField;
+
+    public RenderPass() {
+        mObjectsToDraw = new ArrayList<RenderableBase>();
+        mClearColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f);
+        mShouldClearColor = true;
+        mClearDepth = 1.0f;
+        mShouldClearDepth = true;
+    }
+
+    public void appendRenderable(Renderable d) {
+        mObjectsToDraw.add(d);
+    }
+
+    public void setCamera(Camera c) {
+        mCamera = c;
+    }
+
+    public void setColorTarget(TextureRenderTarget colorTarget) {
+        mColorTarget = colorTarget;
+    }
+    public void setClearColor(Float4 clearColor) {
+        mClearColor = clearColor;
+    }
+    public void setShouldClearColor(boolean shouldClearColor) {
+        mShouldClearColor = shouldClearColor;
+    }
+
+    public void setDepthTarget(TextureRenderTarget depthTarget) {
+        mDepthTarget = depthTarget;
+    }
+    public void setClearDepth(float clearDepth) {
+        mClearDepth = clearDepth;
+    }
+    public void setShouldClearDepth(boolean shouldClearDepth) {
+        mShouldClearDepth = shouldClearDepth;
+    }
+
+    public ArrayList<RenderableBase> getRenderables() {
+        return mObjectsToDraw;
+    }
+
+    ScriptField_RenderPass_s.Item getRsField(RenderScriptGL rs, Resources res) {
+        if (mRsField != null) {
+            return mRsField;
+        }
+
+        mRsField = new ScriptField_RenderPass_s.Item();
+        if (mColorTarget != null) {
+            mRsField.color_target = mColorTarget.getRsData(true).get_texture(0);
+        }
+        if (mColorTarget != null) {
+            mRsField.depth_target = mDepthTarget.getRsData(true).get_texture(0);
+        }
+        mRsField.camera = mCamera != null ? mCamera.getRSData().getAllocation() : null;
+
+        if (mObjectsToDraw.size() != 0) {
+            Allocation drawableData = Allocation.createSized(rs,
+                                                              Element.ALLOCATION(rs),
+                                                              mObjectsToDraw.size());
+            Allocation[] drawableAllocs = new Allocation[mObjectsToDraw.size()];
+            for (int i = 0; i < mObjectsToDraw.size(); i ++) {
+                Renderable dI = (Renderable)mObjectsToDraw.get(i);
+                drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
+            }
+            drawableData.copyFrom(drawableAllocs);
+            mRsField.objects = drawableData;
+        }
+
+        mRsField.clear_color = mClearColor;
+        mRsField.clear_depth = mClearDepth;
+        mRsField.should_clear_color = mShouldClearColor;
+        mRsField.should_clear_depth = mShouldClearDepth;
+        return mRsField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java
new file mode 100644
index 0000000..c08a722
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import android.content.res.Resources;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramRaster;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RSRuntimeException;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderState extends SceneGraphBase {
+    VertexShader mVertex;
+    FragmentShader mFragment;
+    ProgramStore mStore;
+    ProgramRaster mRaster;
+
+    ScriptField_RenderState_s mField;
+
+    public RenderState(VertexShader pv,
+                       FragmentShader pf,
+                       ProgramStore ps,
+                       ProgramRaster pr) {
+        mVertex = pv;
+        mFragment = pf;
+        mStore = ps;
+        mRaster = pr;
+    }
+
+    public RenderState(RenderState r) {
+        mVertex = r.mVertex;
+        mFragment = r.mFragment;
+        mStore = r.mStore;
+        mRaster = r.mRaster;
+    }
+
+    public void setProgramVertex(VertexShader pv) {
+        mVertex = pv;
+        updateRSData();
+    }
+
+    public void setProgramFragment(FragmentShader pf) {
+        mFragment = pf;
+        updateRSData();
+    }
+
+    public void setProgramStore(ProgramStore ps) {
+        mStore = ps;
+        updateRSData();
+    }
+
+    public void setProgramRaster(ProgramRaster pr) {
+        mRaster = pr;
+        updateRSData();
+    }
+
+    void updateRSData() {
+        if (mField == null) {
+            return;
+        }
+        ScriptField_RenderState_s.Item item = new ScriptField_RenderState_s.Item();
+        item.pv = mVertex.getRSData().getAllocation();
+        item.pf = mFragment.getRSData().getAllocation();
+        item.ps = mStore;
+        item.pr = mRaster;
+
+        mField.set(item, 0, true);
+    }
+
+    public ScriptField_RenderState_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        if (rs == null) {
+            return null;
+        }
+
+        mField = new ScriptField_RenderState_s(rs, 1);
+        updateRSData();
+
+        return mField;
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
new file mode 100644
index 0000000..9f7ab41
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.android.scenegraph.Float4Param;
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.ShaderParam;
+import com.android.scenegraph.TransformParam;
+
+import android.content.res.Resources;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Element.DataType;
+import android.renderscript.Matrix4f;
+import android.renderscript.Mesh;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Renderable extends RenderableBase {
+    HashMap<String, ShaderParam> mSourceParams;
+
+    RenderState mRenderState;
+    Transform mTransform;
+
+    String mMeshName;
+    String mMeshIndexName;
+
+    public String mMaterialName;
+
+    ScriptField_Renderable_s mField;
+    ScriptField_Renderable_s.Item mData;
+
+    public Renderable() {
+        mSourceParams = new HashMap<String, ShaderParam>();
+        mData = new ScriptField_Renderable_s.Item();
+    }
+
+    public void setCullType(int cull) {
+        mData.cullType = cull;
+    }
+
+    public void setRenderState(RenderState renderState) {
+        mRenderState = renderState;
+        if (mField != null) {
+            RenderScriptGL rs = SceneManager.getRS();
+            updateFieldItem(rs);
+            mField.set(mData, 0, true);
+        }
+    }
+
+    public void setMesh(Mesh mesh) {
+        mData.mesh = mesh;
+        if (mField != null) {
+            mField.set_mesh(0, mData.mesh, true);
+        }
+    }
+
+    public void setMesh(String mesh, String indexName) {
+        mMeshName = mesh;
+        mMeshIndexName = indexName;
+    }
+
+    public void setMaterialName(String name) {
+        mMaterialName = name;
+    }
+
+    public void setTransform(Transform t) {
+        mTransform = t;
+        if (mField != null) {
+            RenderScriptGL rs = SceneManager.getRS();
+            updateFieldItem(rs);
+            mField.set(mData, 0, true);
+        }
+    }
+
+    public void appendSourceParams(ShaderParam p) {
+        mSourceParams.put(p.getParamName(), p);
+        // Possibly lift this restriction later
+        if (mField != null) {
+            throw new RuntimeException("Can't add source params to objects that are rendering");
+        }
+    }
+
+    public void resolveMeshData(Mesh mesh) {
+        mData.mesh = mesh;
+        if (mData.mesh == null) {
+            Log.v("DRAWABLE: ", "*** NO MESH *** " + mMeshName);
+            return;
+        }
+        int subIndexCount = mData.mesh.getPrimitiveCount();
+        if (subIndexCount == 1 || mMeshIndexName == null) {
+            mData.meshIndex = 0;
+        } else {
+            for (int i = 0; i < subIndexCount; i ++) {
+                if (mData.mesh.getIndexSetAllocation(i).getName().equals(mMeshIndexName)) {
+                    mData.meshIndex = i;
+                    break;
+                }
+            }
+        }
+        if (mField != null) {
+            mField.set(mData, 0, true);
+        }
+    }
+
+    void updateTextures(RenderScriptGL rs) {
+        Iterator<ShaderParam> allParamsIter = mSourceParams.values().iterator();
+        int paramIndex = 0;
+        while (allParamsIter.hasNext()) {
+            ShaderParam sp = allParamsIter.next();
+            if (sp instanceof TextureParam) {
+                TextureParam p = (TextureParam)sp;
+                TextureBase tex = p.getTexture();
+                if (tex != null) {
+                    mData.pf_textures[paramIndex++] = tex.getRsData(false).getAllocation();
+                }
+            }
+        }
+        ProgramFragment pf = mRenderState.mFragment.mProgram;
+        mData.pf_num_textures = pf != null ? Math.min(pf.getTextureCount(), paramIndex) : 0;
+        if (mField != null) {
+            mField.set_pf_textures(0, mData.pf_textures, true);
+            mField.set_pf_num_textures(0, mData.pf_num_textures, true);
+        }
+    }
+
+    public void setVisible(boolean vis) {
+        mData.cullType = vis ? 0 : 2;
+        if (mField != null) {
+            mField.set_cullType(0, mData.cullType, true);
+        }
+    }
+
+    ScriptField_Renderable_s getRsField(RenderScriptGL rs, Resources res) {
+        if (mField != null) {
+            return mField;
+        }
+        updateFieldItem(rs);
+        updateTextures(rs);
+
+        mField = new ScriptField_Renderable_s(rs, 1);
+        mField.set(mData, 0, true);
+
+        return mField;
+    }
+
+    void updateVertexConstants(RenderScriptGL rs) {
+        Allocation pvParams = null, vertexConstants = null;
+        VertexShader pv = mRenderState.mVertex;
+        if (pv != null && pv.getObjectConstants() != null) {
+            vertexConstants = Allocation.createTyped(rs, pv.getObjectConstants());
+            Element vertexConst = vertexConstants.getType().getElement();
+            pvParams = ShaderParam.fillInParams(vertexConst, mSourceParams,
+                                                mTransform).getAllocation();
+        }
+        mData.pv_const = vertexConstants;
+        mData.pv_constParams = pvParams;
+    }
+
+    void updateFragmentConstants(RenderScriptGL rs) {
+        Allocation pfParams = null, fragmentConstants = null;
+        FragmentShader pf = mRenderState.mFragment;
+        if (pf != null && pf.getObjectConstants() != null) {
+            fragmentConstants = Allocation.createTyped(rs, pf.getObjectConstants());
+            Element fragmentConst = fragmentConstants.getType().getElement();
+            pfParams = ShaderParam.fillInParams(fragmentConst, mSourceParams,
+                                                mTransform).getAllocation();
+        }
+        mData.pf_const = fragmentConstants;
+        mData.pf_constParams = pfParams;
+    }
+
+    void updateFieldItem(RenderScriptGL rs) {
+        updateVertexConstants(rs);
+        updateFragmentConstants(rs);
+
+        if (mTransform != null) {
+            mData.transformMatrix = mTransform.getRSData().getAllocation();
+        }
+        mData.name = getNameAlloc(rs);
+        mData.render_state = mRenderState.getRSData().getAllocation();
+        mData.bVolInitialized = 0;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
new file mode 100644
index 0000000..74535dd
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderableBase extends SceneGraphBase {
+    public RenderableBase() {
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java
new file mode 100644
index 0000000..590bbab
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderableGroup extends RenderableBase {
+
+    ArrayList<RenderableBase> mChildren;
+
+    public RenderableGroup() {
+        mChildren = new ArrayList<RenderableBase>();
+    }
+
+    public void appendChildren(RenderableBase d) {
+        mChildren.add(d);
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
new file mode 100644
index 0000000..8c09860
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Mesh;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Scene extends SceneGraphBase {
+    private static String TIMER_TAG = "TIMER";
+
+    CompoundTransform mRootTransforms;
+    HashMap<String, Transform> mTransformMap;
+    ArrayList<RenderPass> mRenderPasses;
+    ArrayList<LightBase> mLights;
+    ArrayList<Camera> mCameras;
+    ArrayList<FragmentShader> mFragmentShaders;
+    ArrayList<VertexShader> mVertexShaders;
+    ArrayList<RenderableBase> mRenderables;
+    HashMap<String, RenderableBase> mRenderableMap;
+    ArrayList<Texture2D> mTextures;
+
+    HashMap<String, ArrayList<Renderable> > mRenderableMeshMap;
+
+    // RS Specific stuff
+    ScriptField_SgTransform mTransformRSData;
+
+    RenderScriptGL mRS;
+    Resources mRes;
+
+    ScriptField_RenderPass_s mRenderPassAlloc;
+
+    public Scene() {
+        mRenderPasses = new ArrayList<RenderPass>();
+        mLights = new ArrayList<LightBase>();
+        mCameras = new ArrayList<Camera>();
+        mFragmentShaders = new ArrayList<FragmentShader>();
+        mVertexShaders = new ArrayList<VertexShader>();
+        mRenderables = new ArrayList<RenderableBase>();
+        mRenderableMap = new HashMap<String, RenderableBase>();
+        mRenderableMeshMap = new HashMap<String, ArrayList<Renderable> >();
+        mTextures = new ArrayList<Texture2D>();
+        mRootTransforms = new CompoundTransform();
+        mRootTransforms.setName("_scene_root_");
+        mTransformMap = new HashMap<String, Transform>();
+    }
+
+    public void appendTransform(Transform t) {
+        mRootTransforms.appendChild(t);
+    }
+
+    // temporary
+    public void addToTransformMap(Transform t) {
+        mTransformMap.put(t.getName(), t);
+    }
+
+    public Transform getTransformByName(String name) {
+        return mTransformMap.get(name);
+    }
+
+    public void appendRenderPass(RenderPass p) {
+        mRenderPasses.add(p);
+    }
+
+    public void clearRenderPasses() {
+        mRenderPasses.clear();
+    }
+
+    public void appendLight(LightBase l) {
+        mLights.add(l);
+    }
+
+    public void appendCamera(Camera c) {
+        mCameras.add(c);
+    }
+
+    public void appendShader(FragmentShader f) {
+        mFragmentShaders.add(f);
+    }
+
+    public void appendShader(VertexShader v) {
+        mVertexShaders.add(v);
+    }
+
+    public ArrayList<Camera> getCameras() {
+        return mCameras;
+    }
+
+    public ArrayList<LightBase> getLights() {
+        return mLights;
+    }
+
+    public void appendRenderable(RenderableBase d) {
+        mRenderables.add(d);
+        mRenderableMap.put(d.getName(), d);
+    }
+
+    public ArrayList<RenderableBase> getRenderables() {
+        return mRenderables;
+    }
+
+    public RenderableBase getRenderableByName(String name) {
+        return mRenderableMap.get(name);
+    }
+
+    public void appendTextures(Texture2D tex) {
+        mTextures.add(tex);
+    }
+
+    public void assignRenderStateToMaterial(RenderState renderState, String regex) {
+        Pattern pattern = Pattern.compile(regex);
+        int numRenderables = mRenderables.size();
+        for (int i = 0; i < numRenderables; i ++) {
+            Renderable shape = (Renderable)mRenderables.get(i);
+            Matcher m = pattern.matcher(shape.mMaterialName);
+            if (m.find()) {
+                shape.setRenderState(renderState);
+            }
+        }
+    }
+
+    public void assignRenderState(RenderState renderState) {
+        int numRenderables = mRenderables.size();
+        for (int i = 0; i < numRenderables; i ++) {
+            Renderable shape = (Renderable)mRenderables.get(i);
+            shape.setRenderState(renderState);
+        }
+    }
+
+    public void meshLoaded(Mesh m) {
+        ArrayList<Renderable> entries = mRenderableMeshMap.get(m.getName());
+        int numEntries = entries.size();
+        for (int i = 0; i < numEntries; i++) {
+            Renderable d = entries.get(i);
+            d.resolveMeshData(m);
+        }
+    }
+
+    void addToMeshMap(Renderable d) {
+        ArrayList<Renderable> entries = mRenderableMeshMap.get(d.mMeshName);
+        if (entries == null) {
+            entries = new ArrayList<Renderable>();
+            mRenderableMeshMap.put(d.mMeshName, entries);
+        }
+        entries.add(d);
+    }
+
+    public void destroyRS() {
+        SceneManager sceneManager = SceneManager.getInstance();
+        mTransformRSData = null;
+        sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
+        sceneManager.mRenderLoop.set_gRenderableObjects(null);
+        mRenderPassAlloc = null;
+        sceneManager.mRenderLoop.set_gRenderPasses(null);
+        sceneManager.mRenderLoop.bind_gFrontToBack(null);
+        sceneManager.mRenderLoop.bind_gBackToFront(null);
+        sceneManager.mRenderLoop.set_gCameras(null);
+
+        mTransformMap = null;
+        mRenderPasses = null;
+        mLights = null;
+        mCameras = null;
+        mRenderables = null;
+        mRenderableMap = null;
+        mTextures = null;
+        mRenderableMeshMap = null;
+        mRootTransforms = null;
+    }
+
+    public void initRenderPassRS(RenderScriptGL rs, SceneManager sceneManager) {
+        if (mRenderPasses.size() != 0) {
+            mRenderPassAlloc = new ScriptField_RenderPass_s(mRS, mRenderPasses.size());
+            for (int i = 0; i < mRenderPasses.size(); i ++) {
+                mRenderPassAlloc.set(mRenderPasses.get(i).getRsField(mRS, mRes), i, false);
+            }
+            mRenderPassAlloc.copyAll();
+            sceneManager.mRenderLoop.set_gRenderPasses(mRenderPassAlloc.getAllocation());
+        }
+    }
+
+    private void addDrawables(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
+        Allocation drawableData = Allocation.createSized(rs,
+                                                         Element.ALLOCATION(rs),
+                                                         mRenderables.size());
+        Allocation[] drawableAllocs = new Allocation[mRenderables.size()];
+        for (int i = 0; i < mRenderables.size(); i ++) {
+            Renderable dI = (Renderable)mRenderables.get(i);
+            addToMeshMap(dI);
+            drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
+        }
+        drawableData.copyFrom(drawableAllocs);
+        sceneManager.mRenderLoop.set_gRenderableObjects(drawableData);
+
+        initRenderPassRS(rs, sceneManager);
+    }
+
+    private void addShaders(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
+        Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs),
+                                                       mVertexShaders.size());
+        Allocation[] shaderAllocs = new Allocation[mVertexShaders.size()];
+        for (int i = 0; i < mVertexShaders.size(); i ++) {
+            VertexShader sI = mVertexShaders.get(i);
+            shaderAllocs[i] = sI.getRSData().getAllocation();
+        }
+        shaderData.copyFrom(shaderAllocs);
+        sceneManager.mRenderLoop.set_gVertexShaders(shaderData);
+
+        shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs), mFragmentShaders.size());
+        shaderAllocs = new Allocation[mFragmentShaders.size()];
+        for (int i = 0; i < mFragmentShaders.size(); i ++) {
+            FragmentShader sI = mFragmentShaders.get(i);
+            shaderAllocs[i] = sI.getRSData().getAllocation();
+        }
+        shaderData.copyFrom(shaderAllocs);
+        sceneManager.mRenderLoop.set_gFragmentShaders(shaderData);
+    }
+
+    public void initRS() {
+        SceneManager sceneManager = SceneManager.getInstance();
+        mRS = SceneManager.getRS();
+        mRes = SceneManager.getRes();
+        long start = System.currentTimeMillis();
+        mTransformRSData = mRootTransforms.getRSData();
+        long end = System.currentTimeMillis();
+        Log.v(TIMER_TAG, "Transform init time: " + (end - start));
+
+        start = System.currentTimeMillis();
+
+        sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
+        end = System.currentTimeMillis();
+        Log.v(TIMER_TAG, "Script init time: " + (end - start));
+
+        start = System.currentTimeMillis();
+        addDrawables(mRS, mRes, sceneManager);
+        end = System.currentTimeMillis();
+        Log.v(TIMER_TAG, "Renderable init time: " + (end - start));
+
+        addShaders(mRS, mRes, sceneManager);
+
+        Allocation opaqueBuffer = null;
+        if (mRenderables.size() > 0) {
+            opaqueBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
+        }
+        Allocation transparentBuffer = null;
+        if (mRenderables.size() > 0) {
+            transparentBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
+        }
+
+        sceneManager.mRenderLoop.bind_gFrontToBack(opaqueBuffer);
+        sceneManager.mRenderLoop.bind_gBackToFront(transparentBuffer);
+
+        if (mCameras.size() > 0) {
+            Allocation cameraData;
+            cameraData = Allocation.createSized(mRS, Element.ALLOCATION(mRS), mCameras.size());
+            Allocation[] cameraAllocs = new Allocation[mCameras.size()];
+            for (int i = 0; i < mCameras.size(); i ++) {
+                cameraAllocs[i] = mCameras.get(i).getRSData().getAllocation();
+            }
+            cameraData.copyFrom(cameraAllocs);
+            sceneManager.mRenderLoop.set_gCameras(cameraData);
+        }
+
+        if (mLights.size() > 0) {
+            Allocation lightData = Allocation.createSized(mRS,
+                                                          Element.ALLOCATION(mRS),
+                                                          mLights.size());
+            Allocation[] lightAllocs = new Allocation[mLights.size()];
+            for (int i = 0; i < mLights.size(); i ++) {
+                lightAllocs[i] = mLights.get(i).getRSData().getAllocation();
+            }
+            lightData.copyFrom(lightAllocs);
+            sceneManager.mRenderLoop.set_gLights(lightData);
+        }
+    }
+}
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java
new file mode 100644
index 0000000..412ffbf
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RSRuntimeException;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class SceneGraphBase {
+    String mName;
+    Allocation mNameAlloc;
+    public void setName(String n) {
+        mName = n;
+        mNameAlloc = null;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    Allocation getNameAlloc(RenderScriptGL rs) {
+        if (mNameAlloc == null)  {
+            mNameAlloc = SceneManager.getStringAsAllocation(rs, getName());
+        }
+        return mNameAlloc;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
new file mode 100644
index 0000000..f77f483
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.android.scenegraph.Camera;
+import com.android.scenegraph.MatrixTransform;
+import com.android.scenegraph.Scene;
+import com.android.testapp.R;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Mesh;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Type.Builder;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+/**
+ * @hide
+ */
+public class SceneManager extends SceneGraphBase {
+
+    HashMap<String, Allocation> mAllocationMap;
+
+    ScriptC_render mRenderLoop;
+    ScriptC mCameraScript;
+    ScriptC mLightScript;
+    ScriptC mObjectParamsScript;
+    ScriptC mFragmentParamsScript;
+    ScriptC mVertexParamsScript;
+    ScriptC mCullScript;
+    ScriptC_transform mTransformScript;
+    ScriptC_export mExportScript;
+
+    RenderScriptGL mRS;
+    Resources mRes;
+    Mesh mQuad;
+    int mWidth;
+    int mHeight;
+
+    Scene mActiveScene;
+    private static SceneManager sSceneManager;
+
+    private Allocation sDefault2D;
+    private Allocation sDefaultCube;
+
+    private static Allocation getDefault(boolean isCube) {
+        final int dimension = 4;
+        final int bytesPerPixel = 4;
+        int arraySize = dimension * dimension * bytesPerPixel;
+
+        RenderScriptGL rs = sSceneManager.mRS;
+        Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));
+        b.setX(dimension).setY(dimension);
+        if (isCube) {
+            b.setFaces(true);
+            arraySize *= 6;
+        }
+        Type bitmapType = b.create();
+
+        Allocation.MipmapControl mip = Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE;
+        int usage =  Allocation.USAGE_GRAPHICS_TEXTURE;
+        Allocation defaultImage = Allocation.createTyped(rs, bitmapType, mip, usage);
+
+        byte imageData[] = new byte[arraySize];
+        defaultImage.copyFrom(imageData);
+        return defaultImage;
+    }
+
+    static Allocation getDefaultTex2D() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        if (sSceneManager.sDefault2D == null) {
+            sSceneManager.sDefault2D = getDefault(false);
+        }
+        return sSceneManager.sDefault2D;
+    }
+
+    static Allocation getDefaultTexCube() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        if (sSceneManager.sDefaultCube == null) {
+            sSceneManager.sDefaultCube = getDefault(true);
+        }
+        return sSceneManager.sDefaultCube;
+    }
+
+    public static boolean isSDCardPath(String path) {
+        int sdCardIndex = path.indexOf("sdcard/");
+        // We are looking for /sdcard/ or sdcard/
+        if (sdCardIndex == 0 || sdCardIndex == 1) {
+            return true;
+        }
+        sdCardIndex = path.indexOf("mnt/sdcard/");
+        if (sdCardIndex == 0 || sdCardIndex == 1) {
+            return true;
+        }
+        return false;
+    }
+
+    static Bitmap loadBitmap(String name, Resources res) {
+        InputStream is = null;
+        boolean loadFromSD = isSDCardPath(name);
+        try {
+            if (!loadFromSD) {
+                is = res.getAssets().open(name);
+            } else {
+                File f = new File(name);
+                is = new BufferedInputStream(new FileInputStream(f));
+            }
+        } catch (IOException e) {
+            Log.e("ImageLoaderTask", " Message: " + e.getMessage());
+            return null;
+        }
+
+        Bitmap b = BitmapFactory.decodeStream(is);
+        try {
+            is.close();
+        } catch (IOException e) {
+            Log.e("ImageLoaderTask", " Message: " + e.getMessage());
+        }
+        return b;
+    }
+
+    public static Allocation loadCubemap(String name, RenderScriptGL rs, Resources res) {
+        Bitmap b = loadBitmap(name, res);
+        if (b == null) {
+            return null;
+        }
+        return Allocation.createCubemapFromBitmap(rs, b,
+                                                  MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+                                                  Allocation.USAGE_GRAPHICS_TEXTURE);
+    }
+
+    public static Allocation loadTexture2D(String name, RenderScriptGL rs, Resources res) {
+        Bitmap b = loadBitmap(name, res);
+        if (b == null) {
+            return null;
+        }
+        return Allocation.createFromBitmap(rs, b,
+                                           Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+                                           Allocation.USAGE_GRAPHICS_TEXTURE);
+    }
+
+    public static ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
+        ProgramStore.Builder builder = new ProgramStore.Builder(rs);
+        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+        builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
+        builder.setDitherEnabled(false);
+        builder.setDepthMaskEnabled(false);
+        return builder.create();
+    }
+
+    static Allocation getStringAsAllocation(RenderScript rs, String str) {
+        if (str == null) {
+            return null;
+        }
+        if (str.length() == 0) {
+            return null;
+        }
+        byte[] allocArray = null;
+        byte[] nullChar = new byte[1];
+        nullChar[0] = 0;
+        try {
+            allocArray = str.getBytes("UTF-8");
+            Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
+                                                      allocArray.length + 1,
+                                                      Allocation.USAGE_SCRIPT);
+            alloc.copy1DRangeFrom(0, allocArray.length, allocArray);
+            alloc.copy1DRangeFrom(allocArray.length, 1, nullChar);
+            return alloc;
+        }
+        catch (Exception e) {
+            throw new RSRuntimeException("Could not convert string to utf-8.");
+        }
+    }
+
+    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;
+        public void run() {
+        }
+    }
+
+    public Scene getActiveScene() {
+        return mActiveScene;
+    }
+
+    public void setActiveScene(Scene s) {
+        mActiveScene = s;
+
+        // Do some sanity checking
+        if (mActiveScene.getCameras().size() == 0) {
+            Matrix4f camPos = new Matrix4f();
+            camPos.translate(0, 0, 10);
+            MatrixTransform cameraTransform = new MatrixTransform();
+            cameraTransform.setName("_DefaultCameraTransform");
+            cameraTransform.setMatrix(camPos);
+            mActiveScene.appendTransform(cameraTransform);
+            Camera cam = new Camera();
+            cam.setName("_DefaultCamera");
+            cam.setTransform(cameraTransform);
+            mActiveScene.appendCamera(cam);
+        }
+    }
+
+    static RenderScriptGL getRS() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        return sSceneManager.mRS;
+    }
+
+    static Resources getRes() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        return sSceneManager.mRes;
+    }
+
+    public static SceneManager getInstance() {
+        if (sSceneManager == null) {
+            sSceneManager = new SceneManager();
+        }
+        return sSceneManager;
+    }
+
+    protected SceneManager() {
+    }
+
+    public void loadModel(String name, SceneLoadedCallback cb) {
+        ColladaScene scene = new ColladaScene(name, cb);
+        scene.init(mRS, mRes);
+    }
+
+    public Mesh getScreenAlignedQuad() {
+        if (mQuad != null) {
+            return mQuad;
+        }
+
+        Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
+                                           3, Mesh.TriangleMeshBuilder.TEXTURE_0);
+
+        tmb.setTexture(0.0f, 1.0f);
+        tmb.addVertex(-1.0f, 1.0f, 1.0f);
+
+        tmb.setTexture(0.0f, 0.0f);
+        tmb.addVertex(-1.0f, -1.0f, 1.0f);
+
+        tmb.setTexture(1.0f, 0.0f);
+        tmb.addVertex(1.0f, -1.0f, 1.0f);
+
+        tmb.setTexture(1.0f, 1.0f);
+        tmb.addVertex(1.0f, 1.0f, 1.0f);
+
+        tmb.addTriangle(0, 1, 2);
+        tmb.addTriangle(2, 3, 0);
+
+        mQuad = tmb.create(true);
+        return mQuad;
+    }
+
+    public Renderable getRenderableQuad(String name, RenderState state) {
+        Renderable quad = new Renderable();
+        quad.setTransform(new MatrixTransform());
+        quad.setMesh(getScreenAlignedQuad());
+        quad.setName(name);
+        quad.setRenderState(state);
+        quad.setCullType(1);
+        return quad;
+    }
+
+    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);
+
+        mCameraScript = new ScriptC_camera(rs, res, R.raw.camera);
+        mLightScript = new ScriptC_light(rs, res, R.raw.light);
+        mObjectParamsScript = new ScriptC_object_params(rs, res, R.raw.object_params);
+        mFragmentParamsScript = new ScriptC_object_params(rs, res, R.raw.fragment_params);
+        mVertexParamsScript = new ScriptC_object_params(rs, res, R.raw.vertex_params);
+        mCullScript = new ScriptC_cull(rs, res, R.raw.cull);
+
+        mRenderLoop = new ScriptC_render(rs, res, R.raw.render);
+        mRenderLoop.set_gTransformScript(mTransformScript);
+        mRenderLoop.set_gCameraScript(mCameraScript);
+        mRenderLoop.set_gLightScript(mLightScript);
+        mRenderLoop.set_gObjectParamsScript(mObjectParamsScript);
+        mRenderLoop.set_gFragmentParamsScript(mFragmentParamsScript);
+        mRenderLoop.set_gVertexParamsScript(mVertexParamsScript);
+        mRenderLoop.set_gCullScript(mCullScript);
+
+        mRenderLoop.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
+    }
+
+    public ScriptC getRenderLoop() {
+        return mRenderLoop;
+    }
+}
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java
new file mode 100644
index 0000000..4975114
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.android.scenegraph.SceneGraphBase;
+import com.android.scenegraph.ShaderParam;
+
+import android.renderscript.*;
+import android.renderscript.ProgramFragment.Builder;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class Shader extends SceneGraphBase {
+    protected Type mPerObjConstants;
+    protected Type mPerShaderConstants;
+
+    protected HashMap<String, ShaderParam> mSourceParams;
+    protected ArrayList<String> mShaderTextureNames;
+    protected ArrayList<Program.TextureType > mShaderTextureTypes;
+    protected ArrayList<String> mTextureNames;
+    protected ArrayList<Program.TextureType > mTextureTypes;
+
+    protected Allocation mConstantBuffer;
+    protected ScriptField_ShaderParam_s mConstantBufferParams;
+
+    public Shader() {
+        mSourceParams = new HashMap<String, ShaderParam>();
+        mShaderTextureNames = new ArrayList<String>();
+        mShaderTextureTypes = new ArrayList<Program.TextureType>();
+        mTextureNames = new ArrayList<String>();
+        mTextureTypes = new ArrayList<Program.TextureType>();
+    }
+
+    public void appendSourceParams(ShaderParam p) {
+        mSourceParams.put(p.getParamName(), p);
+    }
+
+    public Type getObjectConstants() {
+        return mPerObjConstants;
+    }
+
+    public Type getShaderConstants() {
+        return mPerObjConstants;
+    }
+
+    void linkConstants(RenderScriptGL rs) {
+        if (mPerShaderConstants == null) {
+            return;
+        }
+
+        Element constElem = mPerShaderConstants.getElement();
+        mConstantBufferParams  = ShaderParam.fillInParams(constElem, mSourceParams, null);
+
+        mConstantBuffer = Allocation.createTyped(rs, mPerShaderConstants);
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
new file mode 100644
index 0000000..8dea535
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.Transform;
+
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class ShaderParam extends SceneGraphBase {
+
+    static final String cameraPos        = "cameraPos";
+    static final String cameraDir        = "cameraDir";
+
+    static final String lightColor       = "lightColor";
+    static final String lightPos         = "lightPos";
+    static final String lightDir         = "lightDir";
+
+    static final String view             = "view";
+    static final String proj             = "proj";
+    static final String viewProj         = "viewProj";
+    static final String model            = "model";
+    static final String modelView        = "modelView";
+    static final String modelViewProj    = "modelViewProj";
+
+    static final long sMaxTimeStamp = 0xffffffffL;
+
+    ScriptField_ShaderParamData_s.Item mData;
+    ScriptField_ShaderParamData_s mField;
+
+    String mParamName;
+    Camera mCamera;
+
+    static ScriptField_ShaderParam_s fillInParams(Element constantElem,
+                                                  HashMap<String, ShaderParam> sourceParams,
+                                                  Transform transform) {
+        RenderScriptGL rs = SceneManager.getRS();
+        ArrayList<ScriptField_ShaderParam_s.Item> paramList;
+        paramList = new ArrayList<ScriptField_ShaderParam_s.Item>();
+
+        int subElemCount = constantElem.getSubElementCount();
+        for (int i = 0; i < subElemCount; i ++) {
+            String inputName = constantElem.getSubElementName(i);
+            int offset = constantElem.getSubElementOffsetBytes(i);
+
+            ShaderParam matchingParam = sourceParams.get(inputName);
+            Element subElem = constantElem.getSubElement(i);
+            // Make one if it's not there
+            if (matchingParam == null) {
+                if (subElem.getDataType() == Element.DataType.FLOAT_32) {
+                    matchingParam = new Float4Param(inputName);
+                } else if (subElem.getDataType() == Element.DataType.MATRIX_4X4) {
+                    TransformParam trParam = new TransformParam(inputName);
+                    trParam.setTransform(transform);
+                    matchingParam = trParam;
+                }
+            }
+            ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item();
+            paramRS.bufferOffset = offset;
+            paramRS.transformTimestamp = 0;
+            paramRS.dataTimestamp = 0;
+            paramRS.data = matchingParam.getRSData().getAllocation();
+            if (subElem.getDataType() == Element.DataType.FLOAT_32) {
+                paramRS.float_vecSize = subElem.getVectorSize();
+            }
+
+            paramList.add(paramRS);
+        }
+
+        ScriptField_ShaderParam_s rsParams = null;
+        int paramCount = paramList.size();
+        if (paramCount != 0) {
+            rsParams = new ScriptField_ShaderParam_s(rs, paramCount);
+            for (int i = 0; i < paramCount; i++) {
+                rsParams.set(paramList.get(i), i, false);
+            }
+            rsParams.copyAll();
+        }
+        return rsParams;
+    }
+
+    public ShaderParam(String name) {
+        mParamName = name;
+        mData = new ScriptField_ShaderParamData_s.Item();
+    }
+
+    public String getParamName() {
+        return mParamName;
+    }
+
+    public void setCamera(Camera c) {
+        mCamera = c;
+        if (mField != null) {
+            mData.camera = mCamera.getRSData().getAllocation();
+            mField.set_camera(0, mData.camera, true);
+        }
+    }
+
+    protected void incTimestamp() {
+        if (mField != null) {
+            mData.timestamp ++;
+            mData.timestamp %= sMaxTimeStamp;
+            mField.set_timestamp(0, mData.timestamp, true);
+        }
+    }
+
+    abstract void initLocalData();
+
+    public ScriptField_ShaderParamData_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        mField = new ScriptField_ShaderParamData_s(rs, 1);
+
+        if (mParamName != null) {
+            mData.paramName = SceneManager.getCachedAlloc(mParamName);
+            if (mData.paramName == null) {
+                mData.paramName = SceneManager.getStringAsAllocation(rs, mParamName);
+                SceneManager.cacheAlloc(mParamName, mData.paramName);
+            }
+        }
+        initLocalData();
+        mData.timestamp = 1;
+
+        mField.set(mData, 0, true);
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java
new file mode 100644
index 0000000..8fae9d9
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Texture2D extends TextureBase {
+    String mFileName;
+    String mFileDir;
+
+    public Texture2D() {
+        super(ScriptC_export.const_TextureType_TEXTURE_2D);
+    }
+
+    public Texture2D(Allocation tex) {
+        super(ScriptC_export.const_TextureType_TEXTURE_2D);
+        setTexture(tex);
+    }
+
+    public void setFileDir(String dir) {
+        mFileDir = dir;
+    }
+
+    public void setFileName(String file) {
+        mFileName = file;
+    }
+
+    public String getFileName() {
+        return mFileName;
+    }
+
+    public void setTexture(Allocation tex) {
+        mData.texture = tex != null ? tex : SceneManager.getDefaultTex2D();
+        if (mField != null) {
+            mField.set_texture(0, mData.texture, true);
+        }
+    }
+
+    void load() {
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1);
+        setTexture(SceneManager.loadTexture2D(mFileDir + shortName, rs, res));
+    }
+
+    ScriptField_Texture_s getRsData(boolean loadNow) {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        if (rs == null || res == null) {
+            return null;
+        }
+
+        mField = new ScriptField_Texture_s(rs, 1);
+
+        if (loadNow) {
+            load();
+        } else {
+            mData.texture = SceneManager.getDefaultTex2D();
+            new SingleImageLoaderTask().execute(this);
+        }
+
+        mField.set(mData, 0, true);
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java
new file mode 100644
index 0000000..ba49d4e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+import android.os.AsyncTask;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class TextureBase extends SceneGraphBase {
+
+    class SingleImageLoaderTask extends AsyncTask<TextureBase, Void, Boolean> {
+        protected Boolean doInBackground(TextureBase... objects) {
+            TextureBase tex = objects[0];
+            tex.load();
+            return new Boolean(true);
+        }
+        protected void onPostExecute(Boolean result) {
+        }
+    }
+
+    ScriptField_Texture_s.Item mData;
+    ScriptField_Texture_s mField;
+    TextureBase(int type) {
+        mData = new ScriptField_Texture_s.Item();
+        mData.type = type;
+    }
+
+    protected Allocation mRsTexture;
+    abstract ScriptField_Texture_s getRsData(boolean loadNow);
+    abstract void load();
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java
new file mode 100644
index 0000000..12c81c2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureCube extends TextureBase {
+    String mFileName;
+    String mFileDir;
+
+    public TextureCube() {
+        super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+    }
+
+    public TextureCube(Allocation tex) {
+        super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+        setTexture(tex);
+    }
+
+    public TextureCube(String dir, String file) {
+        super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+        setFileDir(dir);
+        setFileName(file);
+    }
+
+    public void setFileDir(String dir) {
+        mFileDir = dir;
+    }
+
+    public void setFileName(String file) {
+        mFileName = file;
+    }
+
+    public String getFileName() {
+        return mFileName;
+    }
+
+    public void setTexture(Allocation tex) {
+        mData.texture = tex != null ? tex : SceneManager.getDefaultTexCube();
+        if (mField != null) {
+            mField.set_texture(0, mData.texture, true);
+        }
+    }
+
+    void load() {
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1);
+        setTexture(SceneManager.loadCubemap(mFileDir + shortName, rs, res));
+    }
+
+    ScriptField_Texture_s getRsData(boolean loadNow) {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        if (rs == null || res == null) {
+            return null;
+        }
+
+        mField = new ScriptField_Texture_s(rs, 1);
+
+        if (loadNow) {
+            load();
+        } else {
+            mData.texture = SceneManager.getDefaultTexCube();
+            new SingleImageLoaderTask().execute(this);
+        }
+
+        mField.set(mData, 0, true);
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
new file mode 100644
index 0000000..e656ed2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.graphics.Camera;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Element;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureParam extends ShaderParam {
+
+    TextureBase mTexture;
+
+    public TextureParam(String name) {
+        super(name);
+    }
+
+    public TextureParam(String name, TextureBase t) {
+        super(name);
+        setTexture(t);
+    }
+
+    public void setTexture(TextureBase t) {
+        mTexture = t;
+    }
+
+    public TextureBase getTexture() {
+        return mTexture;
+    }
+
+    void initLocalData() {
+        mData.type = ScriptC_export.const_ShaderParam_TEXTURE;
+        if (mTexture != null) {
+            mData.texture = mTexture.getRsData(false).getAllocation();
+        }
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java
new file mode 100644
index 0000000..6aa29a5
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureRenderTarget extends TextureBase {
+    public TextureRenderTarget() {
+        super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET);
+    }
+
+    public TextureRenderTarget(Allocation tex) {
+        super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET);
+        setTexture(tex);
+    }
+
+    public void setTexture(Allocation tex) {
+        mData.texture = tex;
+        if (mField != null) {
+            mField.set_texture(0, mData.texture, true);
+        }
+    }
+
+    void load() {
+    }
+
+    ScriptField_Texture_s getRsData(boolean loadNow) {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        if (rs == null) {
+            return null;
+        }
+
+        mField = new ScriptField_Texture_s(rs, 1);
+        mField.set(mData, 0, true);
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
new file mode 100644
index 0000000..8180bd0
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.*;
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class Transform extends SceneGraphBase {
+    Transform mParent;
+    ArrayList<Transform> mChildren;
+
+    ScriptField_SgTransform mField;
+    ScriptField_SgTransform.Item mTransformData;
+
+    public Transform() {
+        mChildren = new ArrayList<Transform>();
+        mParent = null;
+    }
+
+    public void appendChild(Transform t) {
+        mChildren.add(t);
+        t.mParent = this;
+        updateRSChildData(true);
+    }
+
+    abstract void initLocalData();
+
+    void updateRSChildData(boolean copyData) {
+        if (mField == null) {
+            return;
+        }
+        RenderScriptGL rs = SceneManager.getRS();
+        if (mChildren.size() != 0) {
+            Allocation childRSData = Allocation.createSized(rs, Element.ALLOCATION(rs),
+                                                            mChildren.size());
+            mTransformData.children = childRSData;
+
+            Allocation[] childrenAllocs = new Allocation[mChildren.size()];
+            for (int i = 0; i < mChildren.size(); i ++) {
+                Transform child = mChildren.get(i);
+                childrenAllocs[i] = child.getRSData().getAllocation();
+            }
+            childRSData.copyFrom(childrenAllocs);
+        }
+        if (copyData) {
+            mField.set(mTransformData, 0, true);
+        }
+    }
+
+    ScriptField_SgTransform getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        if (rs == null) {
+            return null;
+        }
+        mField = new ScriptField_SgTransform(rs, 1);
+
+        mTransformData = new ScriptField_SgTransform.Item();
+        mTransformData.name = getNameAlloc(rs);
+        mTransformData.isDirty = 1;
+        mTransformData.timestamp = 1;
+
+        initLocalData();
+        updateRSChildData(false);
+
+        mField.set(mTransformData, 0, true);
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
new file mode 100644
index 0000000..d120d5d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Element;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TransformParam extends ShaderParam {
+
+    Transform mTransform;
+    LightBase mLight;
+
+    public TransformParam(String name) {
+        super(name);
+    }
+
+    public void setTransform(Transform t) {
+        mTransform = t;
+        if (mField != null && mTransform != null) {
+            mData.transform = mTransform.getRSData().getAllocation();
+        }
+        incTimestamp();
+    }
+
+    int getTypeFromName() {
+        int paramType = ScriptC_export.const_ShaderParam_TRANSFORM_DATA;
+        if (mParamName.equalsIgnoreCase(view)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW;
+        } else if(mParamName.equalsIgnoreCase(proj)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_PROJ;
+        } else if(mParamName.equalsIgnoreCase(viewProj)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW_PROJ;
+        } else if(mParamName.equalsIgnoreCase(model)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL;
+        } else if(mParamName.equalsIgnoreCase(modelView)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW;
+        } else if(mParamName.equalsIgnoreCase(modelViewProj)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW_PROJ;
+        }
+        return paramType;
+    }
+
+    void initLocalData() {
+        mData.type = getTypeFromName();
+        if (mTransform != null) {
+            mData.transform = mTransform.getRSData().getAllocation();
+        }
+        if (mCamera != null) {
+            mData.camera = mCamera.getRSData().getAllocation();
+        }
+        if (mLight != null) {
+            mData.light = mLight.getRSData().getAllocation();
+        }
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
new file mode 100644
index 0000000..f7d0e6d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class VertexShader extends Shader {
+    ProgramVertex mProgram;
+    ScriptField_VertexShader_s mField;
+
+    public static class Builder {
+        VertexShader mShader;
+        ProgramVertex.Builder mBuilder;
+
+        public Builder(RenderScriptGL rs) {
+            mShader = new VertexShader();
+            mBuilder = new ProgramVertex.Builder(rs);
+        }
+
+        public Builder setShader(Resources resources, int resourceID) {
+            mBuilder.setShader(resources, resourceID);
+            return this;
+        }
+
+        public Builder setObjectConst(Type type) {
+            mShader.mPerObjConstants = type;
+            return this;
+        }
+
+        public Builder setShaderConst(Type type) {
+            mShader.mPerShaderConstants = type;
+            return this;
+        }
+
+        public Builder addInput(Element e) {
+            mBuilder.addInput(e);
+            return this;
+        }
+
+        public VertexShader create() {
+            if (mShader.mPerShaderConstants != null) {
+                mBuilder.addConstant(mShader.mPerShaderConstants);
+            }
+            if (mShader.mPerObjConstants != null) {
+                mBuilder.addConstant(mShader.mPerObjConstants);
+            }
+            mShader.mProgram = mBuilder.create();
+            return mShader;
+        }
+    }
+
+    public ProgramVertex getProgram() {
+        return mProgram;
+    }
+
+    ScriptField_VertexShader_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        if (rs == null || res == null) {
+            return null;
+        }
+
+        ScriptField_VertexShader_s.Item item = new ScriptField_VertexShader_s.Item();
+        item.program = mProgram;
+
+        linkConstants(rs);
+        if (mPerShaderConstants != null) {
+            item.shaderConst = mConstantBuffer;
+            item.shaderConstParams = mConstantBufferParams.getAllocation();
+            mProgram.bindConstants(item.shaderConst, 0);
+        }
+
+        item.objectConstIndex = -1;
+        if (mPerObjConstants != null) {
+            item.objectConstIndex = mPerShaderConstants != null ? 1 : 0;
+        }
+
+        mField = new ScriptField_VertexShader_s(rs, 1);
+        mField.set(item, 0, true);
+        return mField;
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
new file mode 100644
index 0000000..dc0a885
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
@@ -0,0 +1,66 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+//#define DEBUG_CAMERA
+#include "scenegraph_objects.rsh"
+
+void root(const rs_allocation *v_in, rs_allocation *v_out, const float *usrData) {
+
+    SgCamera *cam = (SgCamera *)rsGetElementAt(*v_in, 0);
+    float aspect = *usrData;
+    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);
+
+        rsMatrixInverse(&camPosMatrix);
+        rsMatrixLoad(&cam->view, &camPosMatrix);
+
+        rsMatrixLoad(&cam->viewProj, &cam->proj);
+        rsMatrixMultiply(&cam->viewProj, &cam->view);
+
+        rsExtractFrustumPlanes(&cam->viewProj,
+                               &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+                               &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+                               &cam->frustumPlanes[3], &cam->frustumPlanes[4]);
+    }
+
+    if (cam->isDirty) {
+        cam->timestamp ++;
+    }
+
+    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/cull.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs
new file mode 100644
index 0000000..024e026
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs
@@ -0,0 +1,86 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+static void getTransformedSphere(SgRenderable *obj) {
+    obj->worldBoundingSphere = obj->boundingSphere;
+    obj->worldBoundingSphere.w = 1.0f;
+    const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
+    obj->worldBoundingSphere = rsMatrixMultiply(&objTransform->globalMat, obj->worldBoundingSphere);
+
+    const float4 unitVec = {0.57735f, 0.57735f, 0.57735f, 0.0f};
+    float4 scaledVec = rsMatrixMultiply(&objTransform->globalMat, unitVec);
+    scaledVec.w = 0.0f;
+    obj->worldBoundingSphere.w = obj->boundingSphere.w * length(scaledVec);
+}
+
+static bool frustumCulled(SgRenderable *obj, SgCamera *cam) {
+    if (!obj->bVolInitialized) {
+        float minX, minY, minZ, maxX, maxY, maxZ;
+        rsgMeshComputeBoundingBox(obj->mesh,
+                                  &minX, &minY, &minZ,
+                                  &maxX, &maxY, &maxZ);
+        //rsDebug("min", minX, minY, minZ);
+        //rsDebug("max", maxX, maxY, maxZ);
+        float4 sphere;
+        sphere.x = (maxX + minX) * 0.5f;
+        sphere.y = (maxY + minY) * 0.5f;
+        sphere.z = (maxZ + minZ) * 0.5f;
+        float3 radius;
+        radius.x = (maxX - sphere.x);
+        radius.y = (maxY - sphere.y);
+        radius.z = (maxZ - sphere.z);
+
+        sphere.w = length(radius);
+        obj->boundingSphere = sphere;
+        obj->bVolInitialized = 1;
+        //rsDebug("Sphere", sphere);
+    }
+
+    getTransformedSphere(obj);
+
+    return !rsIsSphereInFrustum(&obj->worldBoundingSphere,
+                                &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+                                &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+                                &cam->frustumPlanes[4], &cam->frustumPlanes[5]);
+}
+
+
+void root(rs_allocation *v_out, const void *usrData) {
+
+    SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
+    const SgCamera *camera = (const SgCamera*)usrData;
+
+    drawable->isVisible = 0;
+    // Not loaded yet
+    if (!rsIsObject(drawable->mesh) || drawable->cullType == CULL_ALWAYS) {
+        return;
+    }
+
+    // check to see if we are culling this object and if it's
+    // outside the frustum
+    if (drawable->cullType == CULL_FRUSTUM && frustumCulled(drawable, (SgCamera*)camera)) {
+#ifdef DEBUG_RENDERABLES
+        rsDebug("Culled", drawable);
+        printName(drawable->name);
+#endif // DEBUG_RENDERABLES
+        return;
+    }
+    drawable->isVisible = 1;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
new file mode 100644
index 0000000..b438a43
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
@@ -0,0 +1,61 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+// 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;
+
+const int Transform_TRANSLATE = TRANSFORM_TRANSLATE;
+const int Transform_ROTATE = TRANSFORM_ROTATE;
+const int Transform_SCALE = TRANSFORM_SCALE;
+
+const int TextureType_TEXTURE_2D = TEXTURE_2D;
+const int TextureType_TEXTURE_CUBE = TEXTURE_CUBE;
+const int TextureType_TEXTURE_RENDER_TARGET = TEXTURE_RENDER_TARGET;
+
+SgTransform *exportPtr;
+SgTransformComponent *componentPtr;
+SgRenderState *sExport;
+SgRenderable *drExport;
+SgRenderPass *pExport;
+SgCamera *exportPtrCam;
+SgLight *exportPtrLight;
+SgShaderParam *spExport;
+SgShaderParamData *spDataExport;
+SgVertexShader *pvExport;
+SgFragmentShader *pfExport;
+SgTexture *texExport;
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs
new file mode 100644
index 0000000..7202285
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs
@@ -0,0 +1,30 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+    SgFragmentShader *shader = (SgFragmentShader *)rsGetElementAt(*v_out, 0);
+    const SgCamera *camera = (const SgCamera*)usrData;
+    processAllParams(shader->shaderConst, shader->shaderConstParams, camera);
+    processTextureParams(shader);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs
new file mode 100644
index 0000000..e11979f
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs
@@ -0,0 +1,33 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+//#define DEBUG_LIGHT
+#include "scenegraph_objects.rsh"
+
+void root(const rs_allocation *v_in, rs_allocation *v_out) {
+
+    SgLight *light = (SgLight *)rsGetElementAt(*v_in, 0);
+    const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
+
+    float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
+    light->position = rsMatrixMultiply(&lTransform->globalMat, zero);
+
+#ifdef DEBUG_LIGHT
+    printLightInfo(light);
+#endif //DEBUG_LIGHT
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs
new file mode 100644
index 0000000..0d524a6
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs
@@ -0,0 +1,36 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+
+    SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
+    // Visibility flag was set earlier in the cull stage
+    if (!drawable->isVisible) {
+        return;
+    }
+
+    const SgCamera *camera = (const SgCamera*)usrData;
+    processAllParams(drawable->pf_const, drawable->pf_constParams, camera);
+    processAllParams(drawable->pv_const, drawable->pv_constParams, camera);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
new file mode 100644
index 0000000..575794b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
@@ -0,0 +1,193 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+static void debugParam(SgShaderParam *p, SgShaderParamData *pData) {
+    rsDebug("____________ Param ____________", p);
+    printName(pData->paramName);
+    rsDebug("bufferOffset", p->bufferOffset);
+    rsDebug("type ", pData->type);
+    rsDebug("data timestamp ", pData->timestamp);
+    rsDebug("param timestamp", p->dataTimestamp);
+
+    const SgTransform *pTransform = NULL;
+    if (rsIsObject(pData->transform)) {
+        pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0);
+
+        rsDebug("transform", pTransform);
+        printName(pTransform->name);
+        rsDebug("timestamp", pTransform->timestamp);
+        rsDebug("param timestamp", p->transformTimestamp);
+    }
+
+    const SgLight *pLight = NULL;
+    if (rsIsObject(pData->light)) {
+        pLight = (const SgLight *)rsGetElementAt(pData->light, 0);
+        printLightInfo(pLight);
+    }
+}
+
+
+static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) {
+#ifdef DEBUG_PARAMS
+    rsDebug("Writing value ", *input);
+    rsDebug("Writing vec size ", vecSize);
+#endif // DEBUG_PARAMS
+
+    switch (vecSize) {
+    case 1:
+        *ptr = input->x;
+        break;
+    case 2:
+        *((float2*)ptr) = (*input).xy;
+        break;
+    case 3:
+        *((float3*)ptr) = (*input).xyz;
+        break;
+    case 4:
+        *((float4*)ptr) = *input;
+        break;
+    }
+}
+
+static bool processParam(SgShaderParam *p, SgShaderParamData *pData,
+                         uint8_t *constantBuffer,
+                         const SgCamera *currentCam,
+                         SgFragmentShader *shader) {
+    bool isDataOnly = (pData->type > SHADER_PARAM_DATA_ONLY);
+    const SgTransform *pTransform = NULL;
+    if (rsIsObject(pData->transform)) {
+        pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0);
+    }
+
+    if (isDataOnly) {
+        // If we are a transform param and our transform is unchanged, nothing to do
+        if (pTransform) {
+            if (p->transformTimestamp == pTransform->timestamp) {
+                return false;
+            }
+            p->transformTimestamp = pTransform->timestamp;
+        } else {
+            if (p->dataTimestamp == pData->timestamp) {
+                return false;
+            }
+            p->dataTimestamp = pData->timestamp;
+        }
+    }
+
+    const SgLight *pLight = NULL;
+    if (rsIsObject(pData->light)) {
+        pLight = (const SgLight *)rsGetElementAt(pData->light, 0);
+    }
+
+    uint8_t *dataPtr = NULL;
+    const SgTexture *tex = NULL;
+    if (pData->type == SHADER_PARAM_TEXTURE) {
+        tex = rsGetElementAt(pData->texture, 0);
+    } else {
+        dataPtr = constantBuffer + p->bufferOffset;
+    }
+
+    switch (pData->type) {
+    case SHADER_PARAM_TEXTURE:
+        rsgBindTexture(shader->program, p->bufferOffset, tex->texture);
+        break;
+    case SHADER_PARAM_FLOAT4_DATA:
+        writeFloatData((float*)dataPtr, &pData->float_value, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_CAMERA_POS:
+        writeFloatData((float*)dataPtr, &currentCam->position, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_CAMERA_DIR: break;
+    case SHADER_PARAM_FLOAT4_LIGHT_COLOR:
+        writeFloatData((float*)dataPtr, &pLight->color, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_LIGHT_POS:
+        writeFloatData((float*)dataPtr, &pLight->position, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_LIGHT_DIR: break;
+
+    case SHADER_PARAM_TRANSFORM_DATA:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_VIEW:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
+        break;
+    case SHADER_PARAM_TRANSFORM_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->proj);
+        break;
+    case SHADER_PARAM_TRANSFORM_VIEW_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL_VIEW:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
+        rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+                             (rs_matrix4x4*)dataPtr,
+                             &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
+        rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+                             (rs_matrix4x4*)dataPtr,
+                             &pTransform->globalMat);
+        break;
+    }
+    return true;
+}
+
+static void processAllParams(rs_allocation shaderConst,
+                             rs_allocation allParams,
+                             const SgCamera *camera) {
+    if (rsIsObject(shaderConst)) {
+        uint8_t *constantBuffer = (uint8_t*)rsGetElementAt(shaderConst, 0);
+
+        int numParams = 0;
+        if (rsIsObject(allParams)) {
+            numParams = rsAllocationGetDimX(allParams);
+        }
+        bool updated = false;
+        for (int i = 0; i < numParams; i ++) {
+            SgShaderParam *current = (SgShaderParam*)rsGetElementAt(allParams, i);
+            SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0);
+#ifdef DEBUG_PARAMS
+            debugParam(current, currentData);
+#endif // DEBUG_PARAMS
+            updated = processParam(current, currentData, constantBuffer, camera, NULL) || updated;
+        }
+    }
+}
+
+static void processTextureParams(SgFragmentShader *shader) {
+    int numParams = 0;
+    if (rsIsObject(shader->shaderTextureParams)) {
+        numParams = rsAllocationGetDimX(shader->shaderTextureParams);
+    }
+    for (int i = 0; i < numParams; i ++) {
+        SgShaderParam *current = (SgShaderParam*)rsGetElementAt(shader->shaderTextureParams, i);
+        SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0);
+#ifdef DEBUG_PARAMS
+        debugParam(current, currentData);
+#endif // DEBUG_PARAMS
+        processParam(current, currentData, NULL, NULL, shader);
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
new file mode 100644
index 0000000..d8d48b3
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
@@ -0,0 +1,240 @@
+// Copyright (C) 2011-2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "rs_graphics.rsh"
+#include "scenegraph_objects.rsh"
+
+rs_script gTransformScript;
+rs_script gCameraScript;
+rs_script gLightScript;
+rs_script gObjectParamsScript;
+rs_script gFragmentParamsScript;
+rs_script gVertexParamsScript;
+rs_script gCullScript;
+
+SgTransform *gRootNode;
+rs_allocation gCameras;
+rs_allocation gLights;
+rs_allocation gFragmentShaders;
+rs_allocation gVertexShaders;
+rs_allocation gRenderableObjects;
+
+rs_allocation gRenderPasses;
+
+// Temporary shaders
+rs_program_store gPFSBackground;
+
+uint32_t *gFrontToBack;
+static uint32_t gFrontToBackCount = 0;
+uint32_t *gBackToFront;
+static uint32_t gBackToFrontCount = 0;
+
+static SgCamera *gActiveCamera = NULL;
+
+static rs_allocation nullAlloc;
+
+// #define DEBUG_RENDERABLES
+static void draw(SgRenderable *obj) {
+#ifdef DEBUG_RENDERABLES
+    const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
+    rsDebug("**** Drawing object with transform", obj);
+    printName(objTransform->name);
+    rsDebug("Model matrix: ", &objTransform->globalMat);
+    printName(obj->name);
+#endif //DEBUG_RENDERABLES
+
+    const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
+    const SgVertexShader *pv = (const SgVertexShader *)rsGetElementAt(renderState->pv, 0);
+    const SgFragmentShader *pf = (const SgFragmentShader *)rsGetElementAt(renderState->pf, 0);
+
+    if (pv->objectConstIndex != -1) {
+        rsgBindConstant(pv->program, pv->objectConstIndex, obj->pv_const);
+    }
+    if (pf->objectConstIndex != -1) {
+        rsgBindConstant(pf->program, pf->objectConstIndex, obj->pf_const);
+    }
+
+    if (rsIsObject(renderState->ps)) {
+        rsgBindProgramStore(renderState->ps);
+    } else {
+        rsgBindProgramStore(gPFSBackground);
+    }
+
+    if (rsIsObject(renderState->pr)) {
+        rsgBindProgramRaster(renderState->pr);
+    } else {
+        rs_program_raster pr;
+        rsgBindProgramRaster(pr);
+    }
+
+    rsgBindProgramVertex(pv->program);
+    rsgBindProgramFragment(pf->program);
+
+    for (uint32_t i = 0; i < obj->pf_num_textures; i ++) {
+        const SgTexture *tex = rsGetElementAt(obj->pf_textures[i], 0);
+        rsgBindTexture(pf->program, i, tex->texture);
+    }
+
+    rsgDrawMesh(obj->mesh, obj->meshIndex);
+}
+
+static void sortToBucket(SgRenderable *obj) {
+    const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
+    if (rsIsObject(renderState->ps)) {
+        bool isOpaque = false;
+        if (isOpaque) {
+            gFrontToBack[gFrontToBackCount++] = (uint32_t)obj;
+        } else {
+            gBackToFront[gBackToFrontCount++] = (uint32_t)obj;
+        }
+    } else {
+        gFrontToBack[gFrontToBackCount++] = (uint32_t)obj;
+    }
+}
+
+static void updateActiveCamera(rs_allocation cam) {
+    gActiveCamera = (SgCamera *)rsGetElementAt(cam, 0);
+}
+
+static void prepareCameras() {
+    // now compute all the camera matrices
+    if (rsIsObject(gCameras)) {
+        float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+        rsForEach(gCameraScript, gCameras, nullAlloc, &aspect, sizeof(aspect));
+    }
+}
+
+static void prepareLights() {
+    if (rsIsObject(gLights)) {
+        rsForEach(gLightScript, gLights, nullAlloc);
+    }
+}
+
+static void drawSorted() {
+    for (int i = 0; i < gFrontToBackCount; i ++) {
+        SgRenderable *current = (SgRenderable*)gFrontToBack[i];
+        draw(current);
+    }
+
+    for (int i = 0; i < gBackToFrontCount; i ++) {
+        SgRenderable *current = (SgRenderable*)gBackToFront[i];
+        draw(current);
+    }
+}
+
+static void drawAllObjects(rs_allocation allObj) {
+    if (!rsIsObject(allObj)) {
+        return;
+    }
+
+    rsForEach(gVertexParamsScript, nullAlloc, gVertexShaders,
+              gActiveCamera, sizeof(gActiveCamera));
+    rsForEach(gFragmentParamsScript, nullAlloc, gFragmentShaders,
+              gActiveCamera, sizeof(gActiveCamera));
+
+    // Run the params and cull script
+    rsForEach(gCullScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
+    rsForEach(gObjectParamsScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
+
+    int numRenderables = rsAllocationGetDimX(allObj);
+    for (int i = 0; i < numRenderables; i ++) {
+        rs_allocation *drawAlloc = (rs_allocation*)rsGetElementAt(allObj, i);
+        SgRenderable *current = (SgRenderable*)rsGetElementAt(*drawAlloc, 0);
+        if (current->isVisible) {
+            sortToBucket(current);
+        }
+    }
+    drawSorted();
+}
+
+int root(void) {
+#ifdef DEBUG_RENDERABLES
+    rsDebug("=============================================================================", 0);
+#endif // DEBUG_RENDERABLES
+
+    // first step is to update the transform hierachy
+    if (gRootNode && rsIsObject(gRootNode->children)) {
+        rsForEach(gTransformScript, gRootNode->children, nullAlloc, 0, 0);
+    }
+
+    prepareCameras();
+    prepareLights();
+
+    if (rsIsObject(gRenderPasses)) {
+        rsgClearDepth(1.0f);
+        int numPasses = rsAllocationGetDimX(gRenderPasses);
+        for (uint i = 0; i < numPasses; i ++) {
+            gFrontToBackCount = 0;
+            gBackToFrontCount = 0;
+            SgRenderPass *pass = (SgRenderPass*)rsGetElementAt(gRenderPasses, i);
+            if (rsIsObject(pass->color_target)) {
+                rsgBindColorTarget(pass->color_target, 0);
+            }
+            if (rsIsObject(pass->depth_target)) {
+                rsgBindDepthTarget(pass->depth_target);
+            }
+            if (!rsIsObject(pass->color_target) &&
+                !rsIsObject(pass->depth_target)) {
+                rsgClearAllRenderTargets();
+            }
+            updateActiveCamera(pass->camera);
+            if (pass->should_clear_color) {
+                rsgClearColor(pass->clear_color.x, pass->clear_color.y,
+                              pass->clear_color.z, pass->clear_color.w);
+            }
+            if (pass->should_clear_depth) {
+                rsgClearDepth(pass->clear_depth);
+            }
+            drawAllObjects(pass->objects);
+        }
+    } else {
+        gFrontToBackCount = 0;
+        gBackToFrontCount = 0;
+        rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+        rsgClearDepth(1.0f);
+
+        if (rsIsObject(gCameras)) {
+            rs_allocation *camAlloc = (rs_allocation*)rsGetElementAt(gCameras, 0);
+            updateActiveCamera(*camAlloc);
+        }
+        drawAllObjects(gRenderableObjects);
+    }
+    return 10;
+}
+
+// Search through sorted and culled objects
+void pick(int screenX, int screenY) {
+    float3 pnt, vec;
+    getCameraRay(gActiveCamera, screenX, screenY, &pnt, &vec);
+
+    for (int i = 0; i < gFrontToBackCount; i ++) {
+        SgRenderable *current = (SgRenderable*)gFrontToBack[i];
+        bool isPicked = intersect(current, pnt, vec);
+        if (isPicked) {
+            current->cullType = CULL_ALWAYS;
+        }
+    }
+
+    for (int i = 0; i < gBackToFrontCount; i ++) {
+        SgRenderable *current = (SgRenderable*)gBackToFront[i];
+        bool isPicked = intersect(current, pnt, vec);
+        if (isPicked) {
+            current->cullType = CULL_ALWAYS;
+        }
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
new file mode 100644
index 0000000..bdca3ab
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
@@ -0,0 +1,323 @@
+// Copyright (C) 2011-2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#ifndef _TRANSFORM_DEF_
+#define _TRANSFORM_DEF_
+
+#include "rs_graphics.rsh"
+
+#define TRANSFORM_NONE      0
+#define TRANSFORM_TRANSLATE 1
+#define TRANSFORM_ROTATE    2
+#define TRANSFORM_SCALE     3
+
+#define CULL_FRUSTUM 0
+#define CULL_ALWAYS  2
+
+#define LIGHT_POINT       0
+#define LIGHT_DIRECTIONAL 1
+
+// 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
+
+// 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
+
+// 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
+#define TEXTURE_RENDER_TARGET 3
+
+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;
+
+    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 {
+    rs_program_vertex program;
+    // Buffer with vertex constant data
+    rs_allocation shaderConst;
+    // ShaderParam's that populate data
+    rs_allocation shaderConstParams;
+    // location of the per object constants on the buffer
+    int objectConstIndex;
+} SgVertexShader;
+
+typedef struct FragmentShader_s {
+    rs_program_fragment program;
+    // Buffer with vertex constant data
+    rs_allocation shaderConst;
+    // ShaderParam's that populate data
+    rs_allocation shaderConstParams;
+    // ShaderParam's that set textures
+    rs_allocation shaderTextureParams;
+    // location of the per object constants on the buffer
+    int objectConstIndex;
+} SgFragmentShader;
+
+typedef struct RenderState_s {
+    rs_allocation pv; // VertexShader struct
+    rs_allocation pf; // FragmentShader struct
+    rs_program_store ps;
+    rs_program_raster pr;
+} SgRenderState;
+
+typedef struct Renderable_s {
+    rs_allocation render_state;
+    // Buffer with vertex constant data
+    rs_allocation pv_const;
+    // ShaderParam's that populate data
+    rs_allocation pv_constParams;
+    // Buffer with fragment constant data
+    rs_allocation pf_const;
+    // ShaderParam's that populate data
+    rs_allocation pf_constParams;
+    rs_allocation pf_textures[8];
+    int pf_num_textures;
+    rs_mesh mesh;
+    int meshIndex;
+    rs_allocation transformMatrix;
+    rs_allocation name;
+    float4 boundingSphere;
+    float4 worldBoundingSphere;
+    int bVolInitialized;
+    int cullType; // specifies whether to frustum cull
+    int isVisible;
+} SgRenderable;
+
+typedef struct RenderPass_s {
+    rs_allocation color_target;
+    rs_allocation depth_target;
+    rs_allocation camera;
+    rs_allocation objects;
+
+    float4 clear_color;
+    float clear_depth;
+    bool should_clear_color;
+    bool should_clear_depth;
+} SgRenderPass;
+
+typedef struct Camera_s {
+    rs_matrix4x4 proj;
+    rs_matrix4x4 view;
+    rs_matrix4x4 viewProj;
+    float4 position;
+    float near;
+    float far;
+    float horizontalFOV;
+    float aspect;
+    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 Light_s {
+    float4 position;
+    float4 color;
+    float intensity;
+    int type;
+    rs_allocation name;
+    rs_allocation transformMatrix;
+} SgLight;
+
+// This represents the shader parameter data needed to set a float or transform data
+typedef struct ShaderParamData_s {
+    int type;
+    float4 float_value;
+    uint32_t timestamp;
+    rs_allocation paramName;
+    rs_allocation camera;
+    rs_allocation light;
+    rs_allocation transform;
+    rs_allocation texture;
+} SgShaderParamData;
+
+// This represents a shader parameter that knows how to update itself for a given
+// renderable or shader and contains a timestamp for the last time this buffer was updated
+typedef struct ShaderParam_s {
+    // Used to check whether transform params need to be updated
+    uint32_t transformTimestamp;
+    // Used to check whether data params need to be updated
+    // These are used when somebody set the matrix of float value directly in java
+    uint32_t dataTimestamp;
+    // Specifies where in the constant buffer data gets written to
+    int bufferOffset;
+    // An instance of SgShaderParamData that could be shared by multiple objects
+    rs_allocation data;
+    // How many components of the vector we need to write
+    int float_vecSize;
+} SgShaderParam;
+
+// This represents a texture object
+typedef struct Texture_s {
+    uint32_t type;
+    rs_allocation texture;
+} SgTexture;
+
+static void printName(rs_allocation name) {
+    if (!rsIsObject(name)) {
+        rsDebug("no name", 0);
+        return;
+    }
+
+    rsDebug((const char*)rsGetElementAt(name, 0), 0);
+}
+
+static void printCameraInfo(const SgCamera *cam) {
+    rsDebug("***** Camera information. ptr:", cam);
+    printName(cam->name);
+    const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
+    rsDebug("Transform name:", camTransform);
+    printName(camTransform->name);
+
+    rsDebug("Aspect: ", cam->aspect);
+    rsDebug("Near: ", cam->near);
+    rsDebug("Far: ", cam->far);
+    rsDebug("Fov: ", cam->horizontalFOV);
+    rsDebug("Position: ", cam->position);
+    rsDebug("Proj: ", &cam->proj);
+    rsDebug("View: ", &cam->view);
+}
+
+static void printLightInfo(const SgLight *light) {
+    rsDebug("***** Light information. ptr:", light);
+    printName(light->name);
+    const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
+    rsDebug("Transform name:", lTransform);
+    printName(lTransform->name);
+
+    rsDebug("Position: ", light->position);
+    rsDebug("Color : ", light->color);
+    rsDebug("Intensity: ", light->intensity);
+    rsDebug("Type: ", light->type);
+}
+
+static void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) {
+    rsDebug("=================================", screenX);
+    rsDebug("Point X", screenX);
+    rsDebug("Point Y", screenY);
+
+    rs_matrix4x4 mvpInv;
+    rsMatrixLoad(&mvpInv, &cam->viewProj);
+    rsMatrixInverse(&mvpInv);
+
+    float width = (float)rsgGetWidth();
+    float height = (float)rsgGetHeight();
+
+    float4 pos = {(float)screenX, height - (float)screenY, 0.0f, 1.0f};
+
+    pos.x /= width;
+    pos.y /= height;
+
+    rsDebug("Pre Norm X", pos.x);
+    rsDebug("Pre Norm Y", pos.y);
+
+    pos.xy = pos.xy * 2.0f - 1.0f;
+
+    rsDebug("Norm X", pos.x);
+    rsDebug("Norm Y", pos.y);
+
+    pos = rsMatrixMultiply(&mvpInv, pos);
+    float oneOverW = 1.0f / pos.w;
+    pos.xyz *= oneOverW;
+
+    rsDebug("World X", pos.x);
+    rsDebug("World Y", pos.y);
+    rsDebug("World Z", pos.z);
+
+    rsDebug("Cam X", cam->position.x);
+    rsDebug("Cam Y", cam->position.y);
+    rsDebug("Cam Z", cam->position.z);
+
+    *vec = normalize(pos.xyz - cam->position.xyz);
+    rsDebug("Vec X", vec->x);
+    rsDebug("Vec Y", vec->y);
+    rsDebug("Vec Z", vec->z);
+    *pnt = cam->position.xyz;
+}
+
+static bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) {
+    // Solving for t^2 + Bt + C = 0
+    float3 originMinusCenter = pnt - obj->worldBoundingSphere.xyz;
+    float B = dot(originMinusCenter, vec) * 2.0f;
+    float C = dot(originMinusCenter, originMinusCenter) -
+              obj->worldBoundingSphere.w * obj->worldBoundingSphere.w;
+
+    float discriminant = B * B - 4.0f * C;
+    if (discriminant < 0.0f) {
+        return false;
+    }
+    discriminant = sqrt(discriminant);
+
+    float t0 = (-B - discriminant) * 0.5f;
+    float t1 = (-B + discriminant) * 0.5f;
+
+    if (t0 > t1) {
+        float temp = t0;
+        t0 = t1;
+        t1 = temp;
+    }
+
+    // The sphere is behind us
+    if (t1 < 0.0f) {
+        return false;
+    }
+    return true;
+}
+
+
+#endif // _TRANSFORM_DEF_
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
new file mode 100644
index 0000000..941b5a8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
@@ -0,0 +1,127 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.modelviewer)
+
+#include "scenegraph_objects.rsh"
+
+rs_script gTransformScript;
+
+typedef struct {
+    int changed;
+    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;
+
+    switch (type) {
+    case TRANSFORM_TRANSLATE:
+        rsMatrixLoadTranslate(&temp, data.x, data.y, data.z);
+        break;
+    case TRANSFORM_ROTATE:
+        rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z);
+        break;
+    case TRANSFORM_SCALE:
+        rsMatrixLoadScale(&temp, data.x, data.y, data.z);
+        break;
+    }
+    rsMatrixMultiply(mat, &temp);
+}
+
+void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) {
+
+    SgTransform *data = (SgTransform *)rsGetElementAt(*v_in, 0);
+    const ParentData *parent = (const ParentData *)usrData;
+
+#ifdef DEBUG_TRANSFORMS
+    debugTransform(data, parent);
+#endif //DEBUG_TRANSFORMS
+
+    rs_matrix4x4 *localMat = &data->localMat;
+    rs_matrix4x4 *globalMat = &data->globalMat;
+
+    // Refresh matrices if dirty
+    if (data->isDirty && rsIsObject(data->components)) {
+        bool resetLocal = false;
+        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;
+            }
+            const SgTransformComponent *comp = NULL;
+            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
+            appendTransformation(comp->type, comp->value, localMat);
+        }
+    }
+
+    if (parent) {
+        data->isDirty = (parent->changed || data->isDirty) ? 1 : 0;
+        if (data->isDirty) {
+            rsMatrixLoad(globalMat, parent->mat);
+            rsMatrixMultiply(globalMat, localMat);
+        }
+    } else if (data->isDirty) {
+        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));
+    }
+
+    data->isDirty = 0;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs
new file mode 100644
index 0000000..88955a8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs
@@ -0,0 +1,29 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+    SgVertexShader *shader = (SgVertexShader *)rsGetElementAt(*v_out, 0);
+    const SgCamera *camera = (const SgCamera*)usrData;
+    processAllParams(shader->shaderConst, shader->shaderConstParams, camera);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java
new file mode 100644
index 0000000..420e133
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+/**
+ * A list view where the last item the user clicked is placed in
+ * the "activated" state, causing its background to highlight.
+ */
+public class FileSelector extends ListActivity {
+
+    File[] mCurrentSubList;
+    File mCurrentFile;
+
+    class DAEFilter implements FileFilter {
+        public boolean accept(File file) {
+            if (file.isDirectory()) {
+                return true;
+            }
+            return file.getName().endsWith(".dae");
+        }
+    }
+
+    private void populateList(File file) {
+
+        mCurrentFile = file;
+        setTitle(mCurrentFile.getAbsolutePath() + "/*.dae");
+        List<String> names = new ArrayList<String>();
+        names.add("..");
+
+        mCurrentSubList = mCurrentFile.listFiles(new DAEFilter());
+
+        if (mCurrentSubList != null) {
+            for (int i = 0; i < mCurrentSubList.length; i ++) {
+                String fileName = mCurrentSubList[i].getName();
+                if (mCurrentSubList[i].isDirectory()) {
+                    fileName = "/" + fileName;
+                }
+                names.add(fileName);
+            }
+        }
+
+        // Use the built-in layout for showing a list item with a single
+        // line of text whose background is changes when activated.
+        setListAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_activated_1, names));
+        getListView().setTextFilterEnabled(true);
+
+        // Tell the list view to show one checked/activated item at a time.
+        getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        populateList(new File("/sdcard/"));
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        if (position == 0) {
+            File parent = mCurrentFile.getParentFile();
+            if (parent == null) {
+                return;
+            }
+            populateList(parent);
+            return;
+        }
+
+        // the first thing in list is parent directory
+        File selectedFile = mCurrentSubList[position - 1];
+        if (selectedFile.isDirectory()) {
+            populateList(selectedFile);
+            return;
+        }
+
+        Intent resultIntent = new Intent();
+        resultIntent.setData(Uri.fromFile(selectedFile));
+        setResult(RESULT_OK, resultIntent);
+        finish();
+    }
+
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java
new file mode 100644
index 0000000..28f916c
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java
@@ -0,0 +1,192 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+package com.android.testapp;

+

+import java.util.ArrayList;

+

+import com.android.scenegraph.*;

+

+import android.content.res.Resources;

+import android.graphics.Bitmap;

+import android.graphics.BitmapFactory;

+import android.os.AsyncTask;

+import android.renderscript.*;

+import android.renderscript.Allocation.MipmapControl;

+import android.renderscript.Element.Builder;

+import android.renderscript.Font.Style;

+import android.renderscript.Program.TextureType;

+import android.renderscript.ProgramStore.DepthFunc;

+import android.util.Log;

+

+class FullscreenBlur {

+

+    static TextureRenderTarget sRenderTargetBlur0Color;

+    static TextureRenderTarget sRenderTargetBlur0Depth;

+    static TextureRenderTarget sRenderTargetBlur1Color;

+    static TextureRenderTarget sRenderTargetBlur1Depth;

+    static TextureRenderTarget sRenderTargetBlur2Color;

+    static TextureRenderTarget sRenderTargetBlur2Depth;

+

+    static FragmentShader mPF_BlurH;

+    static FragmentShader mPF_BlurV;

+    static FragmentShader mPF_SelectColor;

+    static FragmentShader mPF_Texture;

+    static VertexShader mPV_Paint;

+    static VertexShader mPV_Blur;

+

+    static int targetWidth;

+    static int targetHeight;

+

+    // This is only used when full screen blur is enabled

+    // Basically, it's the offscreen render targets

+    static void createRenderTargets(RenderScriptGL rs, int w, int h) {

+        targetWidth = w/8;

+        targetHeight = h/8;

+        Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));

+        Type renderType = b.setX(targetWidth).setY(targetHeight).create();

+        int usage = Allocation.USAGE_GRAPHICS_TEXTURE | Allocation.USAGE_GRAPHICS_RENDER_TARGET;

+        sRenderTargetBlur0Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+        sRenderTargetBlur1Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+        sRenderTargetBlur2Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+

+        b = new Type.Builder(rs, Element.createPixel(rs, Element.DataType.UNSIGNED_16,

+                                                     Element.DataKind.PIXEL_DEPTH));

+        renderType = b.setX(targetWidth).setY(targetHeight).create();

+        usage = Allocation.USAGE_GRAPHICS_RENDER_TARGET;

+        sRenderTargetBlur0Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+        sRenderTargetBlur1Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+        sRenderTargetBlur2Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+    }

+

+    static void addOffsets(Renderable quad, float advance) {

+        quad.appendSourceParams(new Float4Param("blurOffset0", - advance * 2.5f));

+        quad.appendSourceParams(new Float4Param("blurOffset1", - advance * 0.5f));

+        quad.appendSourceParams(new Float4Param("blurOffset2", advance * 1.5f));

+        quad.appendSourceParams(new Float4Param("blurOffset3", advance * 3.5f));

+    }

+

+    static RenderPass addPass(Scene scene, Camera cam, TextureRenderTarget color, TextureRenderTarget depth) {

+        RenderPass pass = new RenderPass();

+        pass.setColorTarget(color);

+        pass.setDepthTarget(depth);

+        pass.setShouldClearColor(false);

+        pass.setShouldClearDepth(false);

+        pass.setCamera(cam);

+        scene.appendRenderPass(pass);

+        return pass;

+    }

+

+    static void addBlurPasses(Scene scene, RenderScriptGL rs, Camera cam) {

+        SceneManager sceneManager = SceneManager.getInstance();

+        ArrayList<RenderableBase> allDraw = scene.getRenderables();

+        int numDraw = allDraw.size();

+

+        ProgramRaster cullNone = ProgramRaster.CULL_NONE(rs);

+        ProgramStore blendAdd = SceneManager.BLEND_ADD_DEPTH_NONE(rs);

+        ProgramStore blendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(rs);

+

+        RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture, blendAdd, cullNone);

+        RenderState selectCol = new RenderState(mPV_Blur, mPF_SelectColor, blendNone, cullNone);

+        RenderState hBlur = new RenderState(mPV_Blur, mPF_BlurH, blendNone, cullNone);

+        RenderState vBlur = new RenderState(mPV_Blur, mPF_BlurV, blendNone, cullNone);

+

+        // Renders the scene off screen

+        RenderPass blurSourcePass = addPass(scene, cam,

+                                            sRenderTargetBlur0Color,

+                                            sRenderTargetBlur0Depth);

+        blurSourcePass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));

+        blurSourcePass.setShouldClearColor(true);

+        blurSourcePass.setClearDepth(1.0f);

+        blurSourcePass.setShouldClearDepth(true);

+        for (int i = 0; i < numDraw; i ++) {

+            blurSourcePass.appendRenderable((Renderable)allDraw.get(i));

+        }

+

+        // Pass for selecting bright colors

+        RenderPass selectColorPass = addPass(scene, cam,

+                                             sRenderTargetBlur2Color,

+                                             sRenderTargetBlur2Depth);

+        Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadS", selectCol);

+        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur0Color));

+        selectColorPass.appendRenderable(quad);

+

+        // Horizontal blur

+        RenderPass horizontalBlurPass = addPass(scene, cam,

+                                                sRenderTargetBlur1Color,

+                                                sRenderTargetBlur1Depth);

+        quad = sceneManager.getRenderableQuad("ScreenAlignedQuadH", hBlur);

+        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));

+        addOffsets(quad, 1.0f / (float)targetWidth);

+        horizontalBlurPass.appendRenderable(quad);

+

+        // Vertical Blur

+        RenderPass verticalBlurPass = addPass(scene, cam,

+                                              sRenderTargetBlur2Color,

+                                              sRenderTargetBlur2Depth);

+        quad = sceneManager.getRenderableQuad("ScreenAlignedQuadV", vBlur);

+        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur1Color));

+        addOffsets(quad, 1.0f / (float)targetHeight);

+        verticalBlurPass.appendRenderable(quad);

+    }

+

+    // Additively renders the blurred colors on top of the scene

+    static void addCompositePass(Scene scene, RenderScriptGL rs, Camera cam) {

+        SceneManager sceneManager = SceneManager.getInstance();

+        RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture,

+                                              SceneManager.BLEND_ADD_DEPTH_NONE(rs),

+                                              ProgramRaster.CULL_NONE(rs));

+

+        RenderPass compositePass = addPass(scene, cam, null, null);

+        Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadComposite", drawTex);

+        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));

+        compositePass.appendRenderable(quad);

+    }

+

+    static private FragmentShader getShader(Resources res, RenderScriptGL rs,

+                                            int resID, Type constants) {

+        FragmentShader.Builder fb = new FragmentShader.Builder(rs);

+        fb.setShader(res, resID);

+        fb.addTexture(TextureType.TEXTURE_2D, "color");

+        if (constants != null) {

+            fb.setObjectConst(constants);

+        }

+        FragmentShader prog = fb.create();

+        prog.getProgram().bindSampler(Sampler.CLAMP_LINEAR(rs), 0);

+        return prog;

+    }

+

+    static void initShaders(Resources res, RenderScriptGL rs) {

+        ScriptField_BlurOffsets blurConst = new ScriptField_BlurOffsets(rs, 1);

+        VertexShader.Builder vb = new VertexShader.Builder(rs);

+        vb.addInput(ScriptField_VertexShaderInputs.createElement(rs));

+        vb.setShader(res, R.raw.blur_vertex);

+        mPV_Blur = vb.create();

+

+        mPF_Texture = getShader(res, rs, R.raw.texture, null);

+        mPF_Texture.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(rs), 0);

+        mPF_BlurH = getShader(res, rs, R.raw.blur_h, blurConst.getAllocation().getType());

+        mPF_BlurV = getShader(res, rs, R.raw.blur_v, blurConst.getAllocation().getType());

+        mPF_SelectColor = getShader(res, rs, R.raw.select_color, null);

+    }

+

+}

+

+

+

+

+

diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java
new file mode 100644
index 0000000..385a7ab
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+import android.view.MenuInflater;
+import android.view.Window;
+import android.net.Uri;
+
+import java.lang.Runtime;
+
+public class TestApp extends Activity {
+
+    private TestAppView mView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // Create our Preview view and set it as the content of our
+        // Activity
+        mView = new TestAppView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onPause();
+        mView.pause();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.loader_menu, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle item selection
+        switch (item.getItemId()) {
+        case R.id.load_model:
+            loadModel();
+            return true;
+        case R.id.use_blur:
+            mView.mRender.toggleBlur();
+            return true;
+        default:
+            return super.onOptionsItemSelected(item);
+        }
+    }
+
+    private static final int FIND_DAE_MODEL = 10;
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (resultCode == RESULT_OK) {
+            if (requestCode == FIND_DAE_MODEL) {
+                Uri selectedImageUri = data.getData();
+                Log.e("Selected Path: ", selectedImageUri.getPath());
+                mView.mRender.loadModel(selectedImageUri.getPath());
+            }
+        }
+    }
+
+    public void loadModel() {
+        Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_PICK);
+        intent.setClassName("com.android.testapp",
+                            "com.android.testapp.FileSelector");
+        startActivityForResult(intent, FIND_DAE_MODEL);
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java
new file mode 100644
index 0000000..5bd8f0b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+// This is where the scenegraph and the rendered objects are initialized and used
+public class TestAppLoadingScreen {
+
+    private static String TAG = "TestAppLoadingScreen";
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private ScriptC_test_app mScript;
+
+    public TestAppLoadingScreen(RenderScriptGL rs, Resources res) {
+        mRS = rs;
+        mRes = res;
+        // Shows the loading screen with some text
+        renderLoading();
+        // Adds a little 3D bugdroid model to the laoding screen asynchronously.
+        new LoadingScreenLoaderTask().execute();
+    }
+
+    public void showLoadingScreen(boolean show) {
+        if (show) {
+            mRS.bindRootScript(mScript);
+        } else {
+            mRS.bindRootScript(SceneManager.getInstance().getRenderLoop());
+        }
+    }
+
+    // The loading screen has some elements that shouldn't be loaded on the UI thread
+    private class LoadingScreenLoaderTask extends AsyncTask<String, Void, Boolean> {
+        Allocation robotTex;
+        Mesh robotMesh;
+        protected Boolean doInBackground(String... names) {
+            long start = System.currentTimeMillis();
+            robotTex = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
+                                                           MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+                                                           Allocation.USAGE_GRAPHICS_TEXTURE);
+
+            FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
+            FileA3D.IndexEntry entry = model.getIndexEntry(0);
+            if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
+                robotMesh = entry.getMesh();
+            }
+
+            mScript.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
+
+            ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
+            b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+                         ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+            ProgramFragment pfDefault = b.create();
+            pfDefault.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
+            mScript.set_gPFBackground(pfDefault);
+
+            ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
+            ProgramVertexFixedFunction pvDefault = pvb.create();
+            ProgramVertexFixedFunction.Constants va = new ProgramVertexFixedFunction.Constants(mRS);
+            ((ProgramVertexFixedFunction)pvDefault).bindConstants(va);
+            mScript.set_gPVBackground(pvDefault);
+
+            long end = System.currentTimeMillis();
+            Log.v("TIMER", "Loading load time: " + (end - start));
+            return new Boolean(true);
+        }
+
+        protected void onPostExecute(Boolean result) {
+            mScript.set_gRobotTex(robotTex);
+            mScript.set_gRobotMesh(robotMesh);
+        }
+    }
+
+    // Creates a simple script to show a loding screen until everything is initialized
+    // Could also be used to do some custom renderscript work before handing things over
+    // to the scenegraph
+    void renderLoading() {
+        mScript = new ScriptC_test_app(mRS, mRes, R.raw.test_app);
+        mRS.bindRootScript(mScript);
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
new file mode 100644
index 0000000..7bf7812
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2011-2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import com.android.scenegraph.*;
+import com.android.scenegraph.SceneManager.SceneLoadedCallback;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Program.TextureType;
+import android.util.Log;
+
+// This is where the scenegraph and the rendered objects are initialized and used
+public class TestAppRS {
+
+    private static String modelName = "orientation_test.dae";
+    private static String TAG = "TestAppRS";
+    private static String mFilePath = "";
+
+    int mWidth;
+    int mHeight;
+
+    boolean mUseBlur;
+
+    TestAppLoadingScreen mLoadingScreen;
+
+    // Used to asynchronously load scene elements like meshes and transform hierarchies
+    SceneLoadedCallback mLoadedCallback = new SceneLoadedCallback() {
+        public void run() {
+            prepareToRender(mLoadedScene);
+        }
+    };
+
+    // Top level class that initializes all the elements needed to use the scene graph
+    SceneManager mSceneManager;
+
+    // Used to move the camera around in the 3D world
+    TouchHandler mTouchHandler;
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+
+    // Shaders
+    private FragmentShader mPaintF;
+    private FragmentShader mLightsF;
+    private FragmentShader mAluminumF;
+    private FragmentShader mPlasticF;
+    private FragmentShader mDiffuseF;
+    private FragmentShader mTextureF;
+    private VertexShader mGenericV;
+
+    Scene mActiveScene;
+
+    // This is a part of the test app, it's used to tests multiple render passes and is toggled
+    // on and off in the menu, off by default
+    void toggleBlur() {
+        mUseBlur = !mUseBlur;
+
+        mActiveScene.clearRenderPasses();
+        initRenderPasses();
+        mActiveScene.initRenderPassRS(mRS, mSceneManager);
+
+        // This is just a hardcoded object in the scene that gets turned on and off for the demo
+        // to make things look a bit better. This could be deleted in the cleanup
+        Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
+        if (plane != null) {
+            plane.setVisible(!mUseBlur);
+        }
+    }
+
+    public void init(RenderScriptGL rs, Resources res, int width, int height) {
+        mUseBlur = false;
+        mRS = rs;
+        mRes = res;
+        mWidth = width;
+        mHeight = height;
+
+        mTouchHandler = new TouchHandler();
+
+        mSceneManager = SceneManager.getInstance();
+        // Initializes all the RS specific scenegraph elements
+        mSceneManager.initRS(mRS, mRes, mWidth, mHeight);
+
+        mLoadingScreen = new TestAppLoadingScreen(mRS, mRes);
+
+        // Initi renderscript stuff specific to the app. This will need to be abstracted out later.
+        FullscreenBlur.createRenderTargets(mRS, mWidth, mHeight);
+        initPaintShaders();
+
+        // Load a scene to render
+        mSceneManager.loadModel(mFilePath + modelName, mLoadedCallback);
+    }
+
+    // When a new model file is selected from the UI, this function gets called to init everything
+    void loadModel(String path) {
+        mLoadingScreen.showLoadingScreen(true);
+        mActiveScene.destroyRS();
+        mSceneManager.loadModel(path, mLoadedCallback);
+    }
+
+    public void onActionDown(float x, float y) {
+        mTouchHandler.onActionDown(x, y);
+    }
+
+    public void onActionScale(float scale) {
+        mTouchHandler.onActionScale(scale);
+    }
+
+    public void onActionMove(float x, float y) {
+        mTouchHandler.onActionMove(x, y);
+    }
+
+    FragmentShader createFromResource(int id, boolean addCubemap, Type constType) {
+        FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
+        fb.setShaderConst(constType);
+        fb.setShader(mRes, id);
+        fb.addTexture(TextureType.TEXTURE_2D, "diffuse");
+        if (addCubemap) {
+            fb.addShaderTexture(TextureType.TEXTURE_CUBE, "reflection");
+        }
+        FragmentShader pf = fb.create();
+        pf.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0);
+        if (addCubemap) {
+            pf.getProgram().bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(mRS), 1);
+        }
+        return pf;
+    }
+
+    private void initPaintShaders() {
+        ScriptField_ModelParams objConst = new ScriptField_ModelParams(mRS, 1);
+        ScriptField_ViewProjParams shaderConst = new ScriptField_ViewProjParams(mRS, 1);
+
+        VertexShader.Builder vb = new VertexShader.Builder(mRS);
+        vb.addInput(ScriptField_VertexShaderInputs.createElement(mRS));
+        vb.setShader(mRes, R.raw.shader2v);
+        vb.setObjectConst(objConst.getAllocation().getType());
+        vb.setShaderConst(shaderConst.getAllocation().getType());
+        mGenericV = vb.create();
+
+        ScriptField_CameraParams fsConst = new ScriptField_CameraParams(mRS, 1);
+        ScriptField_LightParams fsConst2 = new ScriptField_LightParams(mRS, 1);
+
+        mPaintF = createFromResource(R.raw.paintf, true, fsConst.getAllocation().getType());
+        // Assign a reflection map
+        TextureCube envCube = new TextureCube("sdcard/scenegraph/", "cube_env.png");
+        mPaintF.appendSourceParams(new TextureParam("reflection", envCube));
+
+        mAluminumF = createFromResource(R.raw.metal, true, fsConst.getAllocation().getType());
+        TextureCube diffCube = new TextureCube("sdcard/scenegraph/", "cube_spec.png");
+        mAluminumF.appendSourceParams(new TextureParam("reflection", diffCube));
+
+        mPlasticF = createFromResource(R.raw.plastic, false, fsConst.getAllocation().getType());
+        mDiffuseF = createFromResource(R.raw.diffuse, false, fsConst.getAllocation().getType());
+        mTextureF = createFromResource(R.raw.texture, false, fsConst.getAllocation().getType());
+
+        FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
+        fb.setObjectConst(fsConst2.getAllocation().getType());
+        fb.setShader(mRes, R.raw.plastic_lights);
+        mLightsF = fb.create();
+
+        FullscreenBlur.initShaders(mRes, mRS);
+    }
+
+    void initRenderPasses() {
+        ArrayList<RenderableBase> allDraw = mActiveScene.getRenderables();
+        int numDraw = allDraw.size();
+
+        if (mUseBlur) {
+            FullscreenBlur.addBlurPasses(mActiveScene, mRS, mTouchHandler.getCamera());
+        }
+
+        RenderPass mainPass = new RenderPass();
+        mainPass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
+        mainPass.setShouldClearColor(true);
+        mainPass.setClearDepth(1.0f);
+        mainPass.setShouldClearDepth(true);
+        mainPass.setCamera(mTouchHandler.getCamera());
+        for (int i = 0; i < numDraw; i ++) {
+            mainPass.appendRenderable((Renderable)allDraw.get(i));
+        }
+        mActiveScene.appendRenderPass(mainPass);
+
+        if (mUseBlur) {
+            FullscreenBlur.addCompositePass(mActiveScene, mRS, mTouchHandler.getCamera());
+        }
+    }
+
+    private void addShadersToScene() {
+        mActiveScene.appendShader(mPaintF);
+        mActiveScene.appendShader(mLightsF);
+        mActiveScene.appendShader(mAluminumF);
+        mActiveScene.appendShader(mPlasticF);
+        mActiveScene.appendShader(mDiffuseF);
+        mActiveScene.appendShader(mTextureF);
+        mActiveScene.appendShader(mGenericV);
+    }
+
+    public void prepareToRender(Scene s) {
+        mSceneManager.setActiveScene(s);
+        mActiveScene = s;
+        mTouchHandler.init(mActiveScene);
+        addShadersToScene();
+        RenderState plastic = new RenderState(mGenericV, mPlasticF, null, null);
+        RenderState diffuse = new RenderState(mGenericV, mDiffuseF, null, null);
+        RenderState paint = new RenderState(mGenericV, mPaintF, null, null);
+        RenderState aluminum = new RenderState(mGenericV, mAluminumF, null, null);
+        RenderState lights = new RenderState(mGenericV, mLightsF, null, null);
+        RenderState glassTransp = new RenderState(mGenericV, mPaintF,
+                                                  ProgramStore.BLEND_ALPHA_DEPTH_TEST(mRS), null);
+
+        initRenderPasses();
+
+        mActiveScene.assignRenderState(plastic);
+
+        mActiveScene.assignRenderStateToMaterial(diffuse, "lambert2$");
+
+        mActiveScene.assignRenderStateToMaterial(paint, "^Paint");
+        mActiveScene.assignRenderStateToMaterial(paint, "^Carbon");
+        mActiveScene.assignRenderStateToMaterial(paint, "^Glass");
+        mActiveScene.assignRenderStateToMaterial(paint, "^MainGlass");
+
+        mActiveScene.assignRenderStateToMaterial(aluminum, "^Metal");
+        mActiveScene.assignRenderStateToMaterial(aluminum, "^Brake");
+
+        mActiveScene.assignRenderStateToMaterial(glassTransp, "^GlassLight");
+
+        mActiveScene.assignRenderStateToMaterial(lights, "^LightBlinn");
+
+        Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
+        if (plane != null) {
+            RenderState texState = new RenderState(mGenericV, mTextureF, null, null);
+            plane.setRenderState(texState);
+            plane.setVisible(!mUseBlur);
+        }
+
+        long start = System.currentTimeMillis();
+        mActiveScene.initRS();
+        long end = System.currentTimeMillis();
+        Log.v("TIMER", "Scene init time: " + (end - start));
+
+        mLoadingScreen.showLoadingScreen(false);
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java
new file mode 100644
index 0000000..687f35b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+
+public class TestAppView extends RSSurfaceView {
+
+    public TestAppView(Context context) {
+        super(context);
+        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
+    }
+
+    private RenderScriptGL mRS;
+    TestAppRS mRender;
+
+    private ScaleGestureDetector mScaleDetector;
+    private static final int INVALID_POINTER_ID = -1;
+    private int mActivePointerId = INVALID_POINTER_ID;
+
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            sc.setDepth(16, 24);
+            mRS = createRenderScriptGL(sc);
+            mRS.setSurface(holder, w, h);
+            mRender = new TestAppRS();
+            mRender.init(mRS, getResources(), w, h);
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if (mRS != null) {
+            mRender = null;
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event)
+    {
+        // break point at here
+        // this method doesn't work when 'extends View' include 'extends ScrollView'.
+        return super.onKeyDown(keyCode, event);
+    }
+
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        mScaleDetector.onTouchEvent(ev);
+
+        boolean ret = false;
+        float x = ev.getX();
+        float y = ev.getY();
+
+        final int action = ev.getAction();
+
+        switch (action & MotionEvent.ACTION_MASK) {
+        case MotionEvent.ACTION_DOWN: {
+            mRender.onActionDown(x, y);
+            mActivePointerId = ev.getPointerId(0);
+            ret = true;
+            break;
+        }
+        case MotionEvent.ACTION_MOVE: {
+            if (!mScaleDetector.isInProgress()) {
+                mRender.onActionMove(x, y);
+            }
+            mRender.onActionDown(x, y);
+            ret = true;
+            break;
+        }
+
+        case MotionEvent.ACTION_UP: {
+            mActivePointerId = INVALID_POINTER_ID;
+            break;
+        }
+
+        case MotionEvent.ACTION_CANCEL: {
+            mActivePointerId = INVALID_POINTER_ID;
+            break;
+        }
+
+        case MotionEvent.ACTION_POINTER_UP: {
+            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
+                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+            final int pointerId = ev.getPointerId(pointerIndex);
+            if (pointerId == mActivePointerId) {
+                // This was our active pointer going up. Choose a new
+                // active pointer and adjust accordingly.
+                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+                x = ev.getX(newPointerIndex);
+                y = ev.getY(newPointerIndex);
+                mRender.onActionDown(x, y);
+                mActivePointerId = ev.getPointerId(newPointerIndex);
+            }
+            break;
+        }
+        }
+
+        return ret;
+    }
+
+    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
+        @Override
+        public boolean onScale(ScaleGestureDetector detector) {
+            mRender.onActionScale(detector.getScaleFactor());
+            return true;
+        }
+    }
+}
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java
new file mode 100644
index 0000000..d8e48e8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import android.util.Log;
+import android.renderscript.Float3;
+import com.android.scenegraph.*;
+import com.android.scenegraph.CompoundTransform.RotateComponent;
+import com.android.scenegraph.CompoundTransform.TranslateComponent;
+
+public class TouchHandler {
+    private static String TAG = "TouchHandler";
+
+    float mLastX;
+    float mLastY;
+
+    float mRotateXValue;
+    float mRotateYValue;
+    Float3 mDistValue;
+    Float3 mPosValue;
+
+    CompoundTransform mCameraRig;
+    RotateComponent mRotateX;
+    RotateComponent mRotateY;
+    TranslateComponent mDist;
+    TranslateComponent mPosition;
+    Camera mCamera;
+
+    public void init(Scene scene) {
+        // Some initial values for camera position
+        mRotateXValue = -20;
+        mRotateYValue = 45;
+        mDistValue = new Float3(0, 0, 45);
+        mPosValue = new Float3(0, 4, 0);
+
+        mRotateX = new RotateComponent("RotateX", new Float3(1, 0, 0), mRotateXValue);
+        mRotateY = new RotateComponent("RotateY", new Float3(0, 1, 0), mRotateYValue);
+        mDist = new TranslateComponent("Distance", mDistValue);
+        mPosition = new TranslateComponent("Distance", mPosValue);
+
+        // Make a camera transform we can manipulate
+        mCameraRig = new CompoundTransform();
+        mCameraRig.setName("CameraRig");
+        mCameraRig.addComponent(mPosition);
+        mCameraRig.addComponent(mRotateY);
+        mCameraRig.addComponent(mRotateX);
+        mCameraRig.addComponent(mDist);
+        scene.appendTransform(mCameraRig);
+        mCamera = new Camera();
+        mCamera.setTransform(mCameraRig);
+        scene.appendCamera(mCamera);
+    }
+
+    public Camera getCamera() {
+        return mCamera;
+    }
+
+    public void onActionDown(float x, float y) {
+        mLastX = x;
+        mLastY = y;
+    }
+
+    public void onActionScale(float scale) {
+        if (mDist == null) {
+            return;
+        }
+        mDistValue.z *= 1.0f / scale;
+        mDistValue.z = Math.max(10.0f, Math.min(mDistValue.z, 150.0f));
+        mDist.setValue(mDistValue);
+    }
+
+    public void onActionMove(float x, float y) {
+        if (mRotateX == null) {
+            return;
+        }
+
+        float dx = mLastX - x;
+        float dy = mLastY - y;
+
+        if (Math.abs(dy) <= 2.0f) {
+            dy = 0.0f;
+        }
+        if (Math.abs(dx) <= 2.0f) {
+            dx = 0.0f;
+        }
+
+        mRotateYValue += dx * 0.25f;
+        mRotateYValue %= 360.0f;
+
+        mRotateXValue  += dy * 0.25f;
+        mRotateXValue  = Math.max(mRotateXValue , -80.0f);
+        mRotateXValue  = Math.min(mRotateXValue , 0.0f);
+
+        mRotateX.setAngle(mRotateXValue);
+        mRotateY.setAngle(mRotateYValue);
+
+        mLastX = x;
+        mLastY = y;
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
new file mode 100644
index 0000000..997a1a7
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
@@ -0,0 +1,86 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.testapp)
+
+#include "rs_graphics.rsh"
+#include "test_app.rsh"
+
+// Making sure these get reflected
+FBlurOffsets *blurExport;
+VShaderInputs *iExport;
+FShaderParams *fConst;
+FShaderLightParams *fConts2;
+VSParams *vConst2;
+VObjectParams *vConst3;
+
+rs_program_vertex gPVBackground;
+rs_program_fragment gPFBackground;
+
+rs_allocation gRobotTex;
+rs_mesh gRobotMesh;
+
+rs_program_store gPFSBackground;
+
+float gRotate;
+
+void init() {
+    gRotate = 0.0f;
+}
+
+static int pos = 50;
+static float gRotateY = 120.0f;
+static float3 gLookAt = 0;
+static float gZoom = 50.0f;
+static void displayLoading() {
+    if (rsIsObject(gRobotTex) && rsIsObject(gRobotMesh)) {
+        rsgBindProgramVertex(gPVBackground);
+        rs_matrix4x4 proj;
+        float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+        rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
+        rsgProgramVertexLoadProjectionMatrix(&proj);
+
+        rsgBindProgramFragment(gPFBackground);
+        rsgBindProgramStore(gPFSBackground);
+        rsgBindTexture(gPFBackground, 0, gRobotTex);
+
+        rs_matrix4x4 matrix;
+        rsMatrixLoadIdentity(&matrix);
+        // Position our models on the screen
+        gRotateY += rsGetDt()*100;
+        rsMatrixTranslate(&matrix, 0, 0, -gZoom);
+        rsMatrixRotate(&matrix, 20.0f, 1.0f, 0.0f, 0.0f);
+        rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
+        rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f);
+        rsgProgramVertexLoadModelMatrix(&matrix);
+        rsgDrawMesh(gRobotMesh);
+    }
+
+    uint width = rsgGetWidth();
+    uint height = rsgGetHeight();
+    int left = 0, right = 0, top = 0, bottom = 0;
+    const char* text = "Initializing...";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    int centeredPos = width / 2 - (right - left) / 2;
+    rsgDrawText(text, centeredPos, height / 2 + height / 10);
+}
+
+int root(void) {
+    rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgClearDepth(1.0f);
+    displayLoading();
+    return 30;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh
new file mode 100644
index 0000000..5fbcbb2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh
@@ -0,0 +1,52 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.testapp)
+
+// Helpers
+typedef struct ViewProjParams {
+    rs_matrix4x4 viewProj;
+} VSParams;
+
+typedef struct ModelParams {
+    rs_matrix4x4 model;
+} VObjectParams;
+
+typedef struct CameraParams {
+    float4 cameraPos;
+} FShaderParams;
+
+typedef struct LightParams {
+    float4 lightPos_0;
+    float4 lightColor_0;
+    float4 lightPos_1;
+    float4 lightColor_1;
+    float4 cameraPos;
+    float4 diffuse;
+} FShaderLightParams;
+
+typedef struct BlurOffsets {
+    float blurOffset0;
+    float blurOffset1;
+    float blurOffset2;
+    float blurOffset3;
+} FBlurOffsets;
+
+typedef struct VertexShaderInputs {
+    float4 position;
+    float3 normal;
+    float2 texture0;
+} VShaderInputs;
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index 2293678..81f773ca 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -64,6 +64,11 @@
 
         unitTests = new ArrayList<UnitTest>();
 
+        unitTests.add(new UT_mesh(this, mRes, mCtx));
+        unitTests.add(new UT_element(this, mRes, mCtx));
+        unitTests.add(new UT_sampler(this, mRes, mCtx));
+        unitTests.add(new UT_program_store(this, mRes, mCtx));
+        unitTests.add(new UT_program_raster(this, mRes, mCtx));
         unitTests.add(new UT_primitives(this, mRes, mCtx));
         unitTests.add(new UT_constant(this, mRes, mCtx));
         unitTests.add(new UT_vector(this, mRes, mCtx));
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
new file mode 100644
index 0000000..3e2a2ca
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Element.*;
+import android.renderscript.Element.DataKind.*;
+import android.renderscript.Element.DataType.*;
+
+public class UT_element extends UnitTest {
+    private Resources mRes;
+
+    Element simpleElem;
+    Element complexElem;
+
+    final String subElemNames[] = {
+        "subElem0",
+        "subElem1",
+        "subElem2",
+        "arrayElem0",
+        "arrayElem1",
+        "subElem3",
+        "subElem4",
+        "subElem5",
+        "subElem6",
+        "subElem_7",
+    };
+
+    final int subElemArraySizes[] = {
+        1,
+        1,
+        1,
+        2,
+        5,
+        1,
+        1,
+        1,
+        1,
+        1,
+    };
+
+    final int subElemOffsets[] = {
+        0,
+        4,
+        8,
+        12,
+        20,
+        40,
+        44,
+        48,
+        64,
+        80,
+    };
+
+    protected UT_element(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Element", ctx);
+        mRes = res;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_element s) {
+        simpleElem = Element.F32_3(RS);
+        complexElem = ScriptField_ComplexStruct.createElement(RS);
+        s.set_simpleElem(simpleElem);
+        s.set_complexElem(complexElem);
+
+        ScriptField_ComplexStruct data = new ScriptField_ComplexStruct(RS, 1);
+        s.bind_complexStruct(data);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_element s = new ScriptC_element(pRS, mRes, R.raw.element);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_element_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    private void testJavaSide(RenderScript RS) {
+
+        int subElemCount = simpleElem.getSubElementCount();
+        _RS_ASSERT("subElemCount == 0", subElemCount == 0);
+        _RS_ASSERT("simpleElem.getDataKind() == USER",
+                   simpleElem.getDataKind() == DataKind.USER);
+        _RS_ASSERT("simpleElem.getDataType() == FLOAT_32",
+                   simpleElem.getDataType() == DataType.FLOAT_32);
+
+        subElemCount = complexElem.getSubElementCount();
+        _RS_ASSERT("subElemCount == 10", subElemCount == 10);
+        _RS_ASSERT("complexElem.getDataKind() == USER",
+                   complexElem.getDataKind() == DataKind.USER);
+        _RS_ASSERT("complexElemsimpleElem.getDataType() == NONE",
+                   complexElem.getDataType() == DataType.NONE);
+        _RS_ASSERT("complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof",
+                   complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof);
+
+        for (int i = 0; i < subElemCount; i ++) {
+            _RS_ASSERT("complexElem.getSubElement(i) != null",
+                       complexElem.getSubElement(i) != null);
+            _RS_ASSERT("complexElem.getSubElementName(i).equals(subElemNames[i])",
+                       complexElem.getSubElementName(i).equals(subElemNames[i]));
+            _RS_ASSERT("complexElem.getSubElementArraySize(i) == subElemArraySizes[i]",
+                       complexElem.getSubElementArraySize(i) == subElemArraySizes[i]);
+            _RS_ASSERT("complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]",
+                       complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]);
+        }
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testScriptSide(pRS);
+        testJavaSide(pRS);
+        passTest();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
new file mode 100644
index 0000000..0c93702
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Mesh.*;
+
+public class UT_mesh extends UnitTest {
+    private Resources mRes;
+
+    Mesh mesh;
+
+    protected UT_mesh(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Mesh", ctx);
+        mRes = res;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_mesh s) {
+        Allocation vAlloc0 = Allocation.createSized(RS, Element.F32(RS), 10);
+        Allocation vAlloc1 = Allocation.createSized(RS, Element.F32_2(RS), 10);
+
+        Allocation iAlloc0 = Allocation.createSized(RS, Element.I16(RS), 10);
+        Allocation iAlloc2 = Allocation.createSized(RS, Element.I16(RS), 10);
+
+        Mesh.AllocationBuilder mBuilder = new Mesh.AllocationBuilder(RS);
+        mBuilder.addVertexAllocation(vAlloc0);
+        mBuilder.addVertexAllocation(vAlloc1);
+
+        mBuilder.addIndexSetAllocation(iAlloc0, Primitive.POINT);
+        mBuilder.addIndexSetType(Primitive.LINE);
+        mBuilder.addIndexSetAllocation(iAlloc2, Primitive.TRIANGLE);
+
+        s.set_mesh(mBuilder.create());
+        s.set_vertexAlloc0(vAlloc0);
+        s.set_vertexAlloc1(vAlloc1);
+        s.set_indexAlloc0(iAlloc0);
+        s.set_indexAlloc2(iAlloc2);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_mesh s = new ScriptC_mesh(pRS, mRes, R.raw.mesh);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_mesh_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    private void testJavaSide(RenderScript RS) {
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testScriptSide(pRS);
+        testJavaSide(pRS);
+        passTest();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
new file mode 100644
index 0000000..1de4d71
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramRaster;
+import android.renderscript.ProgramRaster.CullMode;
+
+public class UT_program_raster extends UnitTest {
+    private Resources mRes;
+
+    ProgramRaster pointSpriteEnabled;
+    ProgramRaster cullMode;
+
+    protected UT_program_raster(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "ProgramRaster", ctx);
+        mRes = res;
+    }
+
+    private ProgramRaster.Builder getDefaultBuilder(RenderScript RS) {
+        ProgramRaster.Builder b = new ProgramRaster.Builder(RS);
+        b.setCullMode(CullMode.BACK);
+        b.setPointSpriteEnabled(false);
+        return b;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_program_raster s) {
+        ProgramRaster.Builder b = getDefaultBuilder(RS);
+        pointSpriteEnabled = b.setPointSpriteEnabled(true).create();
+        b = getDefaultBuilder(RS);
+        cullMode = b.setCullMode(CullMode.FRONT).create();
+
+        s.set_pointSpriteEnabled(pointSpriteEnabled);
+        s.set_cullMode(cullMode);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_program_raster s = new ScriptC_program_raster(pRS, mRes, R.raw.program_raster);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_program_raster_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    private void testJavaSide(RenderScript RS) {
+        _RS_ASSERT("pointSpriteEnabled.getPointSpriteEnabled() == true",
+                    pointSpriteEnabled.getPointSpriteEnabled() == true);
+        _RS_ASSERT("pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK",
+                    pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK);
+
+        _RS_ASSERT("cullMode.getPointSpriteEnabled() == false",
+                    cullMode.getPointSpriteEnabled() == false);
+        _RS_ASSERT("cullMode.getCullMode() == ProgramRaster.CullMode.FRONT",
+                    cullMode.getCullMode() == ProgramRaster.CullMode.FRONT);
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testScriptSide(pRS);
+        testJavaSide(pRS);
+        passTest();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
new file mode 100644
index 0000000..72a401d
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramStore.BlendDstFunc;
+import android.renderscript.ProgramStore.BlendSrcFunc;
+import android.renderscript.ProgramStore.Builder;
+import android.renderscript.ProgramStore.DepthFunc;
+
+public class UT_program_store extends UnitTest {
+    private Resources mRes;
+
+    ProgramStore ditherEnable;
+    ProgramStore colorRWriteEnable;
+    ProgramStore colorGWriteEnable;
+    ProgramStore colorBWriteEnable;
+    ProgramStore colorAWriteEnable;
+    ProgramStore blendSrc;
+    ProgramStore blendDst;
+    ProgramStore depthWriteEnable;
+    ProgramStore depthFunc;
+
+    protected UT_program_store(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "ProgramStore", ctx);
+        mRes = res;
+    }
+
+    private ProgramStore.Builder getDefaultBuilder(RenderScript RS) {
+        ProgramStore.Builder b = new ProgramStore.Builder(RS);
+        b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO, ProgramStore.BlendDstFunc.ZERO);
+        b.setColorMaskEnabled(false, false, false, false);
+        b.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+        b.setDepthMaskEnabled(false);
+        b.setDitherEnabled(false);
+        return b;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_program_store s) {
+        ProgramStore.Builder b = getDefaultBuilder(RS);
+        ditherEnable = b.setDitherEnabled(true).create();
+
+        b = getDefaultBuilder(RS);
+        colorRWriteEnable = b.setColorMaskEnabled(true,  false, false, false).create();
+
+        b = getDefaultBuilder(RS);
+        colorGWriteEnable = b.setColorMaskEnabled(false, true,  false, false).create();
+
+        b = getDefaultBuilder(RS);
+        colorBWriteEnable = b.setColorMaskEnabled(false, false, true,  false).create();
+
+        b = getDefaultBuilder(RS);
+        colorAWriteEnable = b.setColorMaskEnabled(false, false, false, true).create();
+
+        b = getDefaultBuilder(RS);
+        blendSrc = b.setBlendFunc(ProgramStore.BlendSrcFunc.DST_COLOR,
+                                  ProgramStore.BlendDstFunc.ZERO).create();
+
+        b = getDefaultBuilder(RS);
+        blendDst = b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO,
+                                  ProgramStore.BlendDstFunc.DST_ALPHA).create();
+
+        b = getDefaultBuilder(RS);
+        depthWriteEnable = b.setDepthMaskEnabled(true).create();
+
+        b = getDefaultBuilder(RS);
+        depthFunc = b.setDepthFunc(ProgramStore.DepthFunc.GREATER).create();
+
+        s.set_ditherEnable(ditherEnable);
+        s.set_colorRWriteEnable(colorRWriteEnable);
+        s.set_colorGWriteEnable(colorGWriteEnable);
+        s.set_colorBWriteEnable(colorBWriteEnable);
+        s.set_colorAWriteEnable(colorAWriteEnable);
+        s.set_blendSrc(blendSrc);
+        s.set_blendDst(blendDst);
+        s.set_depthWriteEnable(depthWriteEnable);
+        s.set_depthFunc(depthFunc);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_program_store s = new ScriptC_program_store(pRS, mRes, R.raw.program_store);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_program_store_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    void checkObject(ProgramStore ps,
+                     boolean depthMask,
+                     DepthFunc df,
+                     BlendSrcFunc bsf,
+                     BlendDstFunc bdf,
+                     boolean R,
+                     boolean G,
+                     boolean B,
+                     boolean A,
+                     boolean dither) {
+        _RS_ASSERT("ps.getDepthMaskEnabled() == depthMask", ps.getDepthMaskEnabled() == depthMask);
+        _RS_ASSERT("ps.getDepthFunc() == df", ps.getDepthFunc() == df);
+        _RS_ASSERT("ps.getBlendSrcFunc() == bsf", ps.getBlendSrcFunc() == bsf);
+        _RS_ASSERT("ps.getBlendDstFunc() == bdf", ps.getBlendDstFunc() == bdf);
+        _RS_ASSERT("ps.getColorMaskREnabled() == R", ps.getColorMaskREnabled() == R);
+        _RS_ASSERT("ps.getColorMaskGEnabled() == G", ps.getColorMaskGEnabled() == G);
+        _RS_ASSERT("ps.getColorMaskBEnabled() == B", ps.getColorMaskBEnabled() == B);
+        _RS_ASSERT("ps.getColorMaskAEnabled() == A", ps.getColorMaskAEnabled() == A);
+        _RS_ASSERT("ps.getDitherEnabled() == dither", ps.getDitherEnabled() == dither);
+    }
+
+    void varyBuilderColorAndDither(ProgramStore.Builder pb,
+                                   boolean depthMask,
+                                   DepthFunc df,
+                                   BlendSrcFunc bsf,
+                                   BlendDstFunc bdf) {
+        for (int r = 0; r <= 1; r++) {
+            boolean isR = (r == 1);
+            for (int g = 0; g <= 1; g++) {
+                boolean isG = (g == 1);
+                for (int b = 0; b <= 1; b++) {
+                    boolean isB = (b == 1);
+                    for (int a = 0; a <= 1; a++) {
+                        boolean isA = (a == 1);
+                        for (int dither = 0; dither <= 1; dither++) {
+                            boolean isDither = (dither == 1);
+                            pb.setDitherEnabled(isDither);
+                            pb.setColorMaskEnabled(isR, isG, isB, isA);
+                            ProgramStore ps = pb.create();
+                            checkObject(ps, depthMask, df, bsf, bdf, isR, isG, isB, isA, isDither);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public void testJavaSide(RenderScript RS) {
+        for (int depth = 0; depth <= 1; depth++) {
+            boolean depthMask = (depth == 1);
+            for (DepthFunc df : DepthFunc.values()) {
+                for (BlendSrcFunc bsf : BlendSrcFunc.values()) {
+                    for (BlendDstFunc bdf : BlendDstFunc.values()) {
+                        ProgramStore.Builder b = new ProgramStore.Builder(RS);
+                        b.setDepthFunc(df);
+                        b.setDepthMaskEnabled(depthMask);
+                        b.setBlendFunc(bsf, bdf);
+                        varyBuilderColorAndDither(b, depthMask, df, bsf, bdf);
+                    }
+                }
+            }
+        }
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testJavaSide(pRS);
+        testScriptSide(pRS);
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
new file mode 100644
index 0000000..c328cf6
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Sampler;
+import android.renderscript.Sampler.Value;
+
+public class UT_sampler extends UnitTest {
+    private Resources mRes;
+
+    Sampler minification;
+    Sampler magnification;
+    Sampler wrapS;
+    Sampler wrapT;
+    Sampler anisotropy;
+
+    protected UT_sampler(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Sampler", ctx);
+        mRes = res;
+    }
+
+    private Sampler.Builder getDefaultBuilder(RenderScript RS) {
+        Sampler.Builder b = new Sampler.Builder(RS);
+        b.setMinification(Value.NEAREST);
+        b.setMagnification(Value.NEAREST);
+        b.setWrapS(Value.CLAMP);
+        b.setWrapT(Value.CLAMP);
+        b.setAnisotropy(1.0f);
+        return b;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_sampler s) {
+        Sampler.Builder b = getDefaultBuilder(RS);
+        b.setMinification(Value.LINEAR_MIP_LINEAR);
+        minification = b.create();
+
+        b = getDefaultBuilder(RS);
+        b.setMagnification(Value.LINEAR);
+        magnification = b.create();
+
+        b = getDefaultBuilder(RS);
+        b.setWrapS(Value.WRAP);
+        wrapS = b.create();
+
+        b = getDefaultBuilder(RS);
+        b.setWrapT(Value.WRAP);
+        wrapT = b.create();
+
+        b = getDefaultBuilder(RS);
+        b.setAnisotropy(8.0f);
+        anisotropy = b.create();
+
+        s.set_minification(minification);
+        s.set_magnification(magnification);
+        s.set_wrapS(wrapS);
+        s.set_wrapT(wrapT);
+        s.set_anisotropy(anisotropy);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_sampler s = new ScriptC_sampler(pRS, mRes, R.raw.sampler);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_sampler_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    private void testJavaSide(RenderScript RS) {
+        _RS_ASSERT("minification.getMagnification() == Sampler.Value.NEAREST",
+                    minification.getMagnification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR",
+                    minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR);
+        _RS_ASSERT("minification.getWrapS() == Sampler.Value.CLAMP",
+                    minification.getWrapS() == Sampler.Value.CLAMP);
+        _RS_ASSERT("minification.getWrapT() == Sampler.Value.CLAMP",
+                    minification.getWrapT() == Sampler.Value.CLAMP);
+        _RS_ASSERT("minification.getAnisotropy() == 1.0f",
+                    minification.getAnisotropy() == 1.0f);
+
+        _RS_ASSERT("magnification.getMagnification() == Sampler.Value.LINEAR",
+                    magnification.getMagnification() == Sampler.Value.LINEAR);
+        _RS_ASSERT("magnification.getMinification() == Sampler.Value.NEAREST",
+                    magnification.getMinification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("magnification.getWrapS() == Sampler.Value.CLAMP",
+                    magnification.getWrapS() == Sampler.Value.CLAMP);
+        _RS_ASSERT("magnification.getWrapT() == Sampler.Value.CLAMP",
+                    magnification.getWrapT() == Sampler.Value.CLAMP);
+        _RS_ASSERT("magnification.getAnisotropy() == 1.0f",
+                    magnification.getAnisotropy() == 1.0f);
+
+        _RS_ASSERT("wrapS.getMagnification() == Sampler.Value.NEAREST",
+                    wrapS.getMagnification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("wrapS.getMinification() == Sampler.Value.NEAREST",
+                    wrapS.getMinification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("wrapS.getWrapS() == Sampler.Value.WRAP",
+                    wrapS.getWrapS() == Sampler.Value.WRAP);
+        _RS_ASSERT("wrapS.getWrapT() == Sampler.Value.CLAMP",
+                    wrapS.getWrapT() == Sampler.Value.CLAMP);
+        _RS_ASSERT("wrapS.getAnisotropy() == 1.0f",
+                    wrapS.getAnisotropy() == 1.0f);
+
+        _RS_ASSERT("wrapT.getMagnification() == Sampler.Value.NEAREST",
+                    wrapT.getMagnification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("wrapT.getMinification() == Sampler.Value.NEAREST",
+                    wrapT.getMinification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("wrapT.getWrapS() == Sampler.Value.CLAMP",
+                    wrapT.getWrapS() == Sampler.Value.CLAMP);
+        _RS_ASSERT("wrapT.getWrapT() == Sampler.Value.WRAP",
+                    wrapT.getWrapT() == Sampler.Value.WRAP);
+        _RS_ASSERT("wrapT.getAnisotropy() == 1.0f",
+                    wrapT.getAnisotropy() == 1.0f);
+
+        _RS_ASSERT("anisotropy.getMagnification() == Sampler.Value.NEAREST",
+                    anisotropy.getMagnification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("anisotropy.getMinification() == Sampler.Value.NEAREST",
+                    anisotropy.getMinification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("anisotropy.getWrapS() == Sampler.Value.CLAMP",
+                    anisotropy.getWrapS() == Sampler.Value.CLAMP);
+        _RS_ASSERT("anisotropy.getWrapT() == Sampler.Value.CLAMP",
+                    anisotropy.getWrapT() == Sampler.Value.CLAMP);
+        _RS_ASSERT("anisotropy.getAnisotropy() == 1.0f",
+                    anisotropy.getAnisotropy() == 8.0f);
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testScriptSide(pRS);
+        testJavaSide(pRS);
+        passTest();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
index edff83f..fbac124 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
@@ -58,8 +58,8 @@
 
     protected void _RS_ASSERT(String message, boolean b) {
         if(b == false) {
-            result = -1;
             Log.e(name, message + " FAILED");
+            failTest();
         }
     }
 
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
new file mode 100644
index 0000000..0c42d84
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
@@ -0,0 +1,158 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_element simpleElem;
+rs_element complexElem;
+typedef struct ComplexStruct {
+    float subElem0;
+    float subElem1;
+    int subElem2;
+    float arrayElem0[2];
+    int arrayElem1[5];
+    char subElem3;
+    float subElem4;
+    float2 subElem5;
+    float3 subElem6;
+    float4 subElem_7;
+} ComplexStruct_t;
+
+ComplexStruct_t *complexStruct;
+
+static const char *subElemNames[] = {
+    "subElem0",
+    "subElem1",
+    "subElem2",
+    "arrayElem0",
+    "arrayElem1",
+    "subElem3",
+    "subElem4",
+    "subElem5",
+    "subElem6",
+    "subElem_7",
+};
+
+static uint32_t subElemNamesSizes[] = {
+    8,
+    8,
+    8,
+    10,
+    10,
+    8,
+    8,
+    8,
+    8,
+    9,
+};
+
+static uint32_t subElemArraySizes[] = {
+    1,
+    1,
+    1,
+    2,
+    5,
+    1,
+    1,
+    1,
+    1,
+    1,
+};
+
+static void resetStruct() {
+    uint8_t *bytePtr = (uint8_t*)complexStruct;
+    uint32_t sizeOfStruct = sizeof(*complexStruct);
+    for(uint32_t i = 0; i < sizeOfStruct; i ++) {
+        bytePtr[i] = 0;
+    }
+}
+
+static bool equals(const char *name0, const char * name1, uint32_t len) {
+    for (uint32_t i = 0; i < len; i ++) {
+        if (name0[i] != name1[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool test_element_getters() {
+    bool failed = false;
+
+    uint32_t subElemOffsets[10];
+    uint32_t index = 0;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem0   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem1   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem2   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem0 - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem1 - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem3   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem4   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem5   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem6   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem_7  - (uint32_t)complexStruct;
+
+    uint32_t subElemCount = rsElementGetSubElementCount(simpleElem);
+    _RS_ASSERT(subElemCount == 0);
+    _RS_ASSERT(rsElementGetDataKind(simpleElem) == RS_KIND_USER);
+    _RS_ASSERT(rsElementGetDataType(simpleElem) == RS_TYPE_FLOAT_32);
+    _RS_ASSERT(rsElementGetVectorSize(simpleElem) == 3);
+
+    subElemCount = rsElementGetSubElementCount(complexElem);
+    _RS_ASSERT(subElemCount == 10);
+    _RS_ASSERT(rsElementGetDataKind(complexElem) == RS_KIND_USER);
+    _RS_ASSERT(rsElementGetDataType(complexElem) == RS_TYPE_NONE);
+    _RS_ASSERT(rsElementGetVectorSize(complexElem) == 1);
+    _RS_ASSERT(rsElementGetSizeBytes(complexElem) == sizeof(*complexStruct));
+
+    char buffer[64];
+    for (uint32_t i = 0; i < subElemCount; i ++) {
+        rs_element subElem = rsElementGetSubElement(complexElem, i);
+        _RS_ASSERT(rsIsObject(subElem));
+
+        _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, i) == subElemNamesSizes[i] + 1);
+
+        uint32_t written = rsElementGetSubElementName(complexElem, i, buffer, 64);
+        _RS_ASSERT(written == subElemNamesSizes[i]);
+        _RS_ASSERT(equals(buffer, subElemNames[i], written));
+
+        _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, i) == subElemArraySizes[i]);
+        _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, i) == subElemOffsets[i]);
+    }
+
+    // Tests error checking
+    rs_element subElem = rsElementGetSubElement(complexElem, subElemCount);
+    _RS_ASSERT(!rsIsObject(subElem));
+
+    _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, subElemCount) == 0);
+
+    _RS_ASSERT(rsElementGetSubElementName(complexElem, subElemCount, buffer, 64) == 0);
+    _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, NULL, 64) == 0);
+    _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, buffer, 0) == 0);
+    uint32_t written = rsElementGetSubElementName(complexElem, 0, buffer, 5);
+    _RS_ASSERT(written == 4);
+    _RS_ASSERT(buffer[4] == '\0');
+
+    _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, subElemCount) == 0);
+    _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, subElemCount) == 0);
+
+    if (failed) {
+        rsDebug("test_element_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_element_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void element_test() {
+    bool failed = false;
+    failed |= test_element_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
new file mode 100644
index 0000000..627ab99
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
@@ -0,0 +1,64 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_mesh mesh;
+rs_allocation vertexAlloc0;
+rs_allocation vertexAlloc1;
+
+rs_allocation indexAlloc0;
+rs_allocation indexAlloc2;
+
+static bool test_mesh_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsMeshGetVertexAllocationCount(mesh) == 2);
+    _RS_ASSERT(rsMeshGetPrimitiveCount(mesh) == 3);
+
+    rs_allocation meshV0 = rsMeshGetVertexAllocation(mesh, 0);
+    rs_allocation meshV1 = rsMeshGetVertexAllocation(mesh, 1);
+    rs_allocation meshV2 = rsMeshGetVertexAllocation(mesh, 2);
+    _RS_ASSERT(meshV0.p == vertexAlloc0.p);
+    _RS_ASSERT(meshV1.p == vertexAlloc1.p);
+    _RS_ASSERT(!rsIsObject(meshV2));
+
+    rs_allocation meshI0 = rsMeshGetIndexAllocation(mesh, 0);
+    rs_allocation meshI1 = rsMeshGetIndexAllocation(mesh, 1);
+    rs_allocation meshI2 = rsMeshGetIndexAllocation(mesh, 2);
+    rs_allocation meshI3 = rsMeshGetIndexAllocation(mesh, 3);
+    _RS_ASSERT(meshI0.p == indexAlloc0.p);
+    _RS_ASSERT(!rsIsObject(meshI1));
+    _RS_ASSERT(meshI2.p == indexAlloc2.p);
+    _RS_ASSERT(!rsIsObject(meshI3));
+
+    rs_primitive p0 = rsMeshGetPrimitive(mesh, 0);
+    rs_primitive p1 = rsMeshGetPrimitive(mesh, 1);
+    rs_primitive p2 = rsMeshGetPrimitive(mesh, 2);
+    rs_primitive p3 = rsMeshGetPrimitive(mesh, 3);
+
+    _RS_ASSERT(p0 == RS_PRIMITIVE_POINT);
+    _RS_ASSERT(p1 == RS_PRIMITIVE_LINE);
+    _RS_ASSERT(p2 == RS_PRIMITIVE_TRIANGLE);
+    _RS_ASSERT(p3 == RS_PRIMITIVE_INVALID);
+
+    if (failed) {
+        rsDebug("test_mesh_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_mesh_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void mesh_test() {
+    bool failed = false;
+    failed |= test_mesh_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
new file mode 100644
index 0000000..11b8c30
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
@@ -0,0 +1,37 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_raster pointSpriteEnabled;
+rs_program_raster cullMode;
+
+static bool test_program_raster_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true);
+    _RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
+
+    _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(cullMode) == false);
+    _RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
+
+    if (failed) {
+        rsDebug("test_program_raster_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_program_raster_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void program_raster_test() {
+    bool failed = false;
+    failed |= test_program_raster_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
new file mode 100644
index 0000000..3cd8a20
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
@@ -0,0 +1,128 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_store ditherEnable;
+rs_program_store colorRWriteEnable;
+rs_program_store colorGWriteEnable;
+rs_program_store colorBWriteEnable;
+rs_program_store colorAWriteEnable;
+rs_program_store blendSrc;
+rs_program_store blendDst;
+rs_program_store depthWriteEnable;
+rs_program_store depthFunc;
+
+static bool test_program_store_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(depthWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorRWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorGWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorBWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorAWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(ditherEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
+
+    if (failed) {
+        rsDebug("test_program_store_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_program_store_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void program_store_test() {
+    bool failed = false;
+    failed |= test_program_store_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
new file mode 100644
index 0000000..ac9a549
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
@@ -0,0 +1,63 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+rs_sampler minification;
+rs_sampler magnification;
+rs_sampler wrapS;
+rs_sampler wrapT;
+rs_sampler anisotropy;
+
+static bool test_sampler_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsgSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR);
+    _RS_ASSERT(rsgSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(minification) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR);
+    _RS_ASSERT(rsgSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(magnification) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP);
+    _RS_ASSERT(rsgSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(wrapS) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(wrapT) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(anisotropy) == 8.0f);
+
+    if (failed) {
+        rsDebug("test_sampler_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_sampler_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void sampler_test() {
+    bool failed = false;
+    failed |= test_sampler_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+