am b62954b6: am 8f31c230: am 57ce0888: Merge change Id22c0137 into eclair

Merge commit 'b62954b66542e3e2654d97a81123c51805bceca7'

* commit 'b62954b66542e3e2654d97a81123c51805bceca7':
  Throttle low priority RS threads by sleeping once per frame to avoid starving other apps.
diff --git a/Android.mk b/Android.mk
index 262ac8d..3080ab0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -96,11 +96,14 @@
 	rsScript.cpp \
 	rsScriptC.cpp \
 	rsScriptC_Lib.cpp \
+        rsShaderCache.cpp \
 	rsSimpleMesh.cpp \
 	rsThreadIO.cpp \
-	rsType.cpp
+	rsType.cpp \
+	rsVertexArray.cpp
 
-LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libui libacc
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libacc
 LOCAL_LDLIBS := -lpthread -ldl
 LOCAL_MODULE:= libRS
 LOCAL_MODULE_TAGS := optional
diff --git a/java/Film/src/com/android/film/FilmView.java b/java/Film/src/com/android/film/FilmView.java
index 1c5b2bc..4a201fd 100644
--- a/java/Film/src/com/android/film/FilmView.java
+++ b/java/Film/src/com/android/film/FilmView.java
@@ -42,19 +42,29 @@
 
     public FilmView(Context context) {
         super(context);
-
         //setFocusable(true);
     }
 
     private RenderScript mRS;
     private FilmRS mRender;
 
+
     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
         super.surfaceChanged(holder, format, w, h);
+        if (mRS == null) {
+            mRS = createRenderScript(true);
+            mRS.contextSetSurface(w, h, holder.getSurface());
+            mRender = new FilmRS();
+            mRender.init(mRS, getResources(), w, h);
+        }
+    }
 
-        mRS = createRenderScript(true);
-        mRender = new FilmRS();
-        mRender.init(mRS, getResources(), w, h);
+    @Override
+    protected void onDetachedFromWindow() {
+        if(mRS != null) {
+            mRS = null;
+            destroyRenderScript();
+        }
     }
 
     @Override
diff --git a/java/Fountain/src/com/android/fountain/FountainView.java b/java/Fountain/src/com/android/fountain/FountainView.java
index 1e7c5a2..fcb93f4 100644
--- a/java/Fountain/src/com/android/fountain/FountainView.java
+++ b/java/Fountain/src/com/android/fountain/FountainView.java
@@ -51,7 +51,7 @@
     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
         super.surfaceChanged(holder, format, w, h);
         if (mRS == null) {
-            mRS = createRenderScript(false, true);
+            mRS = createRenderScript(false);
             mRS.contextSetSurface(w, h, holder.getSurface());
             mRender = new FountainRS();
             mRender.init(mRS, getResources(), w, h);
diff --git a/java/Rollo/Android.mk b/java/Rollo/Android.mk
deleted file mode 100644
index 5a4957c..0000000
--- a/java/Rollo/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
-
-LOCAL_PACKAGE_NAME := Rollo
-
-include $(BUILD_PACKAGE)
diff --git a/java/Rollo/AndroidManifest.xml b/java/Rollo/AndroidManifest.xml
deleted file mode 100644
index 12cb28f..0000000
--- a/java/Rollo/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.rollo">
-    <application
-        android:label="Rollo"
-        android:icon="@drawable/test_pattern">
-        <activity android:name="Rollo"
-                  android:theme="@android:style/Theme.Translucent"
-                  android:icon="@drawable/test_pattern">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/java/Rollo/res/drawable/test_pattern.png b/java/Rollo/res/drawable/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/java/Rollo/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/browser.png b/java/Rollo/res/raw/browser.png
deleted file mode 100644
index 513f0be..0000000
--- a/java/Rollo/res/raw/browser.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/calendar.png b/java/Rollo/res/raw/calendar.png
deleted file mode 100644
index 030ae73..0000000
--- a/java/Rollo/res/raw/calendar.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/g1155.png b/java/Rollo/res/raw/g1155.png
deleted file mode 100644
index 68e1843..0000000
--- a/java/Rollo/res/raw/g1155.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/g2140.png b/java/Rollo/res/raw/g2140.png
deleted file mode 100644
index 8c4e853..0000000
--- a/java/Rollo/res/raw/g2140.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/maps.png b/java/Rollo/res/raw/maps.png
deleted file mode 100644
index fd5fc39..0000000
--- a/java/Rollo/res/raw/maps.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/market.png b/java/Rollo/res/raw/market.png
deleted file mode 100644
index 83b6910..0000000
--- a/java/Rollo/res/raw/market.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/path1920.png b/java/Rollo/res/raw/path1920.png
deleted file mode 100644
index 3510665..0000000
--- a/java/Rollo/res/raw/path1920.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/path1927.png b/java/Rollo/res/raw/path1927.png
deleted file mode 100644
index fccc846..0000000
--- a/java/Rollo/res/raw/path1927.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/path3099.png b/java/Rollo/res/raw/path3099.png
deleted file mode 100644
index 527ebf6..0000000
--- a/java/Rollo/res/raw/path3099.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/path3950.png b/java/Rollo/res/raw/path3950.png
deleted file mode 100644
index 59a646a..0000000
--- a/java/Rollo/res/raw/path3950.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/path431.png b/java/Rollo/res/raw/path431.png
deleted file mode 100644
index 5d2ed75..0000000
--- a/java/Rollo/res/raw/path431.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/path4481.png b/java/Rollo/res/raw/path4481.png
deleted file mode 100644
index 78be0fc..0000000
--- a/java/Rollo/res/raw/path4481.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/path5168.png b/java/Rollo/res/raw/path5168.png
deleted file mode 100644
index a7c3a19..0000000
--- a/java/Rollo/res/raw/path5168.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/path676.png b/java/Rollo/res/raw/path676.png
deleted file mode 100644
index 2099690..0000000
--- a/java/Rollo/res/raw/path676.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/path754.png b/java/Rollo/res/raw/path754.png
deleted file mode 100644
index 88aed5b..0000000
--- a/java/Rollo/res/raw/path754.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/path815.png b/java/Rollo/res/raw/path815.png
deleted file mode 100644
index 407570f..0000000
--- a/java/Rollo/res/raw/path815.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/photos.png b/java/Rollo/res/raw/photos.png
deleted file mode 100644
index 1ed8f1e..0000000
--- a/java/Rollo/res/raw/photos.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/polygon2408.png b/java/Rollo/res/raw/polygon2408.png
deleted file mode 100644
index 4413954..0000000
--- a/java/Rollo/res/raw/polygon2408.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/res/raw/rollo.c b/java/Rollo/res/raw/rollo.c
deleted file mode 100644
index b31be81..0000000
--- a/java/Rollo/res/raw/rollo.c
+++ /dev/null
@@ -1,184 +0,0 @@
-#pragma version(1)
-#pragma stateVertex(PV)
-#pragma stateFragment(PF)
-#pragma stateStore(PFS)
-
-// Scratch buffer layout
-#define SCRATCH_FADE 0
-#define SCRATCH_ZOOM 1
-#define SCRATCH_ROT 2
-
-//#define STATE_POS_X             0
-#define STATE_DONE              1
-//#define STATE_PRESSURE          2
-#define STATE_ZOOM              3
-//#define STATE_WARP              4
-#define STATE_ORIENTATION       5
-#define STATE_SELECTION         6
-#define STATE_FIRST_VISIBLE     7
-#define STATE_COUNT             8
-#define STATE_TOUCH             9
-
-
-float filter(float val, float target, float str)
-{
-    float delta = (target - val);
-    return val + delta * str;
-}
-
-int main(void* con, int ft, int launchID)
-{
-    int rowCount;
-    int row;
-    int col;
-    int imageID;
-    int done = loadI32(0, STATE_DONE);
-    int selectedID = loadI32(0, STATE_SELECTION);
-
-    float f = loadF(2, 0);
-
-    pfClearColor(0.0f, 0.0f, 0.0f, f);
-    if (done) {
-        if (f > 0.02f) {
-            //f = f - 0.02f;
-            //storeF(2, 0, f);
-        }
-    } else {
-        if (f < 0.8f) {
-            f = f + 0.02f;
-            storeF(2, 0, f);
-        }
-    }
-
-    float touchCut = 1.f;
-    if (loadI32(0, STATE_TOUCH)) {
-        touchCut = 4.f;
-    }
-
-
-    float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
-    float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
-    storeF(2, SCRATCH_ZOOM, zoom);
-
-    float targetRot = loadI32(0, STATE_FIRST_VISIBLE) / 180.0f * 3.14f;
-    targetRot = targetRot * 0.80f - .12f;
-    float drawRot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
-    storeF(2, SCRATCH_ROT, drawRot);
-
-    float diam = 8.f;
-    float scale = 1.0f / zoom;
-
-    // Bug makes 1.0f alpha fail.
-    color(1.0f, 1.0f, 1.0f, 0.99f);
-
-    float rot = drawRot * scale;
-    float rotStep = 16.0f / 180.0f * 3.14f * scale;
-    rowCount = 4;
-    int index = 0;
-    int iconCount = loadI32(0, STATE_COUNT);
-    while (iconCount) {
-        float tmpSin = sinf(rot);
-        float tmpCos = cosf(rot);
-            //debugF("rot", rot);
-
-        float tx1 = tmpSin * diam - (tmpCos * scale * 0.9f);
-        float tx2 = tx1 + (tmpCos * scale * 1.8f);
-        float tz1 = tmpCos * diam + (tmpSin * scale * 0.9f);
-        float tz2 = tz1 - (tmpSin * scale * 1.8f);
-
-        int y;
-        for (y = rowCount -1; (y >= 0) && iconCount; y--) {
-            float ty1 = ((y * 3.1f) - 5.f) * scale;
-            float ty2 = ty1 + scale * 1.8f;
-            bindTexture(NAMED_PF, 0, loadI32(1, index));
-            drawQuad(tx1, ty1, tz1,
-                     tx2, ty1, tz2,
-                     tx2, ty2, tz2,
-                     tx1, ty2, tz1);
-
-            iconCount--;
-            index++;
-        }
-        rot = rot + rotStep;
-    }
-
-    if ((zoom < 1.1f) && (zoom > 0.9f)) {
-        bindProgramVertex(NAMED_PVOrtho);
-        bindProgramFragment(NAMED_PFText);
-        bindProgramStore(NAMED_PFSText);
-
-        rot = drawRot * scale;
-        index = 0;
-        iconCount = loadI32(0, STATE_COUNT);
-        while (iconCount) {
-            int y;
-
-            float tx = 240.f + floorf(sinf(rot) * 430.f) - 64.f + 16.f;
-
-            float alpha = 2.4f - (fabsf(tx - 240.f + 48.f) / 76.f);
-            if (alpha > 0.99f) {
-                alpha = 0.99f;
-            }
-            alpha = alpha * (1.f - (fabsf(zoom - 1.f) * 10.f));
-
-            tx = tx + 0.25f;
-
-            for (y = rowCount -1; (y >= 0) && iconCount; y--) {
-
-                if (alpha > 0) {
-                    color(1.0f, 1.0f, 1.0f, alpha);
-
-                    float ty = 605.f - y * 150.f;
-
-                    ty = ty + 0.25f;
-
-                    bindTexture(NAMED_PFText, 0, loadI32(3, index));
-                    drawRect(tx, ty, tx + 128.f, ty + 32.f, 0.5f);
-                }
-                iconCount--;
-                index++;
-            }
-            rot = rot + rotStep;
-        }
-
-
-        bindProgramVertex(NAMED_PV);
-        bindProgramFragment(NAMED_PF);
-        bindProgramStore(NAMED_PFS);
-    }
-
-    // Draw the selected icon
-    color(1.0f, 1.0f, 1.0f, 0.9f);
-    rot = drawRot * scale;
-    index = 0;
-    iconCount = loadI32(0, STATE_COUNT);
-    while (iconCount) {
-        int y;
-        for (y = rowCount -1; (y >= 0) && iconCount; y--) {
-            if (index == selectedID) {
-
-                float tmpSin = sinf(rot) * scale;
-                float tmpCos = cosf(rot) * scale;
-                float tx1 = tmpSin * diam * 0.9f - tmpCos * 2.f;
-                float tx2 = tx1 + (tmpCos * 4.f);
-                float tz1 = tmpCos * diam * 0.9f + tmpSin * 2.f;
-                float tz2 = tz1 - (tmpSin * 4.f);
-
-                float ty1 = ((y * 3.1f) - 4.5f) * scale;
-                float ty2 = ty1 + scale * 4.f;
-                bindTexture(NAMED_PF, 0, loadI32(1, index));
-                drawQuad(tx1, ty1, tz1,
-                         tx2, ty1, tz2,
-                         tx2, ty2, tz2,
-                         tx1, ty2, tz1);
-            }
-            iconCount--;
-            index++;
-        }
-        rot = rot + rotStep;
-    }
-
-    return 1;
-}
-
-
diff --git a/java/Rollo/res/raw/rollo2.c b/java/Rollo/res/raw/rollo2.c
deleted file mode 100644
index 5b5cb2d..0000000
--- a/java/Rollo/res/raw/rollo2.c
+++ /dev/null
@@ -1,155 +0,0 @@
-#pragma version(1)
-#pragma stateVertex(PV)
-#pragma stateFragment(PF)
-#pragma stateStore(PFS)
-
-// Scratch buffer layout
-#define SCRATCH_FADE 0
-#define SCRATCH_ZOOM 1
-#define SCRATCH_ROT 2
-
-//#define STATE_POS_X             0
-#define STATE_DONE              1
-//#define STATE_PRESSURE          2
-#define STATE_ZOOM              3
-//#define STATE_WARP              4
-#define STATE_ORIENTATION       5
-#define STATE_SELECTION         6
-#define STATE_FIRST_VISIBLE     7
-#define STATE_COUNT             8
-#define STATE_TOUCH             9
-
-float filter(float val, float target, float str)
-{
-    float delta = (target - val);
-    return val + delta * str;
-}
-
-
-int main(void* con, int ft, int launchID)
-{
-    int rowCount;
-    int imageID;
-    int done = loadI32(0, STATE_DONE);
-    int selectedID = loadI32(0, STATE_SELECTION);
-    int iconCount = loadI32(0, STATE_COUNT);
-
-    float f = loadF(2, 0);
-
-    float iconSize = 1.f;
-    float iconSpacing = 0.2f;
-    float z = 4.f;
-
-    pfClearColor(0.0f, 0.0f, 0.0f, f);
-    if (done) {
-    } else {
-        if (f < 0.8f) {
-            f = f + 0.02f;
-            storeF(2, 0, f);
-        }
-    }
-
-    float touchCut = 1.f;
-    if (loadI32(0, STATE_TOUCH)) {
-        touchCut = 5.f;
-    }
-
-
-    float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
-    float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
-    storeF(2, SCRATCH_ZOOM, zoom);
-
-    float targetPos = loadI32(0, STATE_FIRST_VISIBLE) / (-20.0f);
-    float pos = filter(loadF(2, SCRATCH_ROT), targetPos, 0.1f * touchCut);
-    storeF(2, SCRATCH_ROT, pos);
-    pos = pos - 1.f;
-
-    color(1.0f, 1.0f, 1.0f, 1.0f);
-
-
-    // Draw flat icons first
-    int index = ((int)pos) * 4;
-    int row;
-    int col;
-    float xoffset = -0.3f;
-    float gridSize = iconSize * 4.f + iconSpacing * 3.f;
-    float yoffset = (pos - ((int)pos));
-    for (row = 0; row < 4; row ++) {
-        float ty1 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing) - iconSize;
-        float ty2 = ty1 + iconSize;
-
-        for (col = 0; (col < 4) && (index < iconCount); col ++) {
-            if (index >= 0) {
-                bindTexture(NAMED_PF, 0, loadI32(1, index));
-                float fcol = col;
-                float tx1 = xoffset + (-gridSize / 2.f) + (fcol * (iconSize + iconSpacing));
-                float tx2 = tx1 + iconSize;
-
-                drawQuad(tx1, ty1, z,
-                         tx2, ty1, z,
-                         tx2, ty2, z,
-                         tx1, ty2, z);
-            }
-            index++;
-        }
-    }
-
-    // bottom roller
-    {
-        float roll = (1.f - yoffset) * 0.5f * 3.14f;
-        float tmpSin = sinf(roll);
-        float tmpCos = cosf(roll);
-
-        for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
-            float ty2 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing);
-            float ty1 = ty2 - tmpCos * iconSize;
-
-            float tz1 = z + tmpSin * iconSize;
-            float tz2 = z;
-
-            float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
-            float tx2 = tx1 + iconSize;
-
-            bindTexture(NAMED_PF, 0, loadI32(1, index));
-            drawQuad(tx1, ty1, tz1,
-                     tx2, ty1, tz1,
-                     tx2, ty2, tz2,
-                     tx1, ty2, tz2);
-            index++;
-        }
-    }
-
-    // Top roller
-    {
-        index = (((int)pos) * 4) - 4;
-        float roll = yoffset * 0.5f * 3.14f;
-        float tmpSin = sinf(roll);
-        float tmpCos = cosf(roll);
-
-        for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
-            float ty1 = (gridSize / 2.f) - ((float)-1.f - yoffset) * (iconSize + iconSpacing) - iconSize;
-            float ty2 = ty1 + tmpCos * iconSize;
-
-            float tz1 = z;
-            float tz2 = z + tmpSin * iconSize;
-
-            float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
-            float tx2 = tx1 + iconSize;
-
-            bindTexture(NAMED_PF, 0, loadI32(1, index));
-            drawQuad(tx1, ty1, tz1,
-                     tx2, ty1, tz1,
-                     tx2, ty2, tz2,
-                     tx1, ty2, tz2);
-            index++;
-        }
-    }
-
-
-
-
-    return 1;
-}
-
-
-
diff --git a/java/Rollo/res/raw/settings.png b/java/Rollo/res/raw/settings.png
deleted file mode 100644
index dd2cd95..0000000
--- a/java/Rollo/res/raw/settings.png
+++ /dev/null
Binary files differ
diff --git a/java/Rollo/src/com/android/rollo/Rollo.java b/java/Rollo/src/com/android/rollo/Rollo.java
deleted file mode 100644
index 400d801..0000000
--- a/java/Rollo/src/com/android/rollo/Rollo.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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 com.android.rollo;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Config;
-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 java.lang.Runtime;
-
-public class Rollo extends Activity {
-    //EventListener mListener = new EventListener();
-
-    private static final String LOG_TAG = "libRS_jni";
-    private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
-
-    private RolloView mView;
-
-    // get the current looper (from your Activity UI thread for instance
-
-
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new RolloView(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.onResume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onPause();
-        mView.onPause();
-
-        Runtime.getRuntime().exit(0);
-    }
-
-
-    static void log(String message) {
-        if (LOG_ENABLED) {
-            Log.v(LOG_TAG, message);
-        }
-    }
-
-
-}
-
diff --git a/java/Rollo/src/com/android/rollo/RolloRS.java b/java/Rollo/src/com/android/rollo/RolloRS.java
deleted file mode 100644
index ff89bc3..0000000
--- a/java/Rollo/src/com/android/rollo/RolloRS.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * 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 com.android.rollo;
-
-import java.io.Writer;
-
-import android.renderscript.RenderScript;
-import android.renderscript.ProgramVertex;
-import android.renderscript.Element;
-import android.renderscript.Allocation;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.Sampler;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.Typeface;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-public class RolloRS {
-    //public static final int STATE_SELECTED_ID = 0;
-    public static final int STATE_DONE = 1;
-    //public static final int STATE_PRESSURE = 2;
-    public static final int STATE_ZOOM = 3;
-    //public static final int STATE_WARP = 4;
-    public static final int STATE_ORIENTATION = 5;
-    public static final int STATE_SELECTION = 6;
-    public static final int STATE_FIRST_VISIBLE = 7;
-    public static final int STATE_COUNT = 8;
-    public static final int STATE_TOUCH = 9;
-
-
-    public RolloRS() {
-    }
-
-    public void init(RenderScript rs, Resources res, int width, int height) {
-        mRS = rs;
-        mRes = res;
-        mWidth = width;
-        mHeight = height;
-        initNamed();
-        initRS();
-    }
-
-    public void setPosition(float column) {
-        mAllocStateBuf[STATE_FIRST_VISIBLE] = (int)(column * (-20));
-        mAllocState.data(mAllocStateBuf);
-    }
-
-    public void setTouch(boolean touch) {
-        mAllocStateBuf[STATE_TOUCH] = touch ? 1 : 0;
-        mAllocState.data(mAllocStateBuf);
-    }
-
-    public void setZoom(float z) {
-        //Log.e("rs", "zoom " + Float.toString(z));
-
-        mAllocStateBuf[STATE_ZOOM] = (int)(z * 1000.f);
-        mAllocState.data(mAllocStateBuf);
-    }
-
-    public void setSelected(int index) {
-        //Log.e("rs",  "setSelected " + Integer.toString(index));
-
-        mAllocStateBuf[STATE_SELECTION] = index;
-        mAllocStateBuf[STATE_DONE] = 1;
-        mAllocState.data(mAllocStateBuf);
-    }
-
-    private int mWidth;
-    private int mHeight;
-
-    private Resources mRes;
-    private RenderScript mRS;
-    private Script mScript;
-    private Sampler mSampler;
-    private Sampler mSamplerText;
-    private ProgramStore mPSBackground;
-    private ProgramStore mPSText;
-    private ProgramFragment mPFImages;
-    private ProgramFragment mPFText;
-    private ProgramVertex mPV;
-    private ProgramVertex.MatrixAllocation mPVAlloc;
-    private ProgramVertex mPVOrtho;
-    private ProgramVertex.MatrixAllocation mPVOrthoAlloc;
-    private Allocation[] mIcons;
-    private Allocation[] mLabels;
-
-    private int[] mAllocStateBuf;
-    private Allocation mAllocState;
-
-    private int[] mAllocIconIDBuf;
-    private Allocation mAllocIconID;
-
-    private int[] mAllocLabelIDBuf;
-    private Allocation mAllocLabelID;
-
-    private int[] mAllocScratchBuf;
-    private Allocation mAllocScratch;
-
-    private void initNamed() {
-        Sampler.Builder sb = new Sampler.Builder(mRS);
-        sb.setMin(Sampler.Value.LINEAR);//_MIP_LINEAR);
-        sb.setMag(Sampler.Value.LINEAR);
-        sb.setWrapS(Sampler.Value.CLAMP);
-        sb.setWrapT(Sampler.Value.CLAMP);
-        mSampler = sb.create();
-
-        sb.setMin(Sampler.Value.NEAREST);
-        sb.setMag(Sampler.Value.NEAREST);
-        mSamplerText = sb.create();
-
-
-        ProgramFragment.Builder bf = new ProgramFragment.Builder(mRS, null, null);
-        bf.setTexEnable(true, 0);
-        bf.setTexEnvMode(ProgramFragment.EnvMode.MODULATE, 0);
-        mPFImages = bf.create();
-        mPFImages.setName("PF");
-        mPFImages.bindSampler(mSampler, 0);
-
-        bf.setTexEnvMode(ProgramFragment.EnvMode.MODULATE, 0);
-        mPFText = bf.create();
-        mPFText.setName("PFText");
-        mPFText.bindSampler(mSamplerText, 0);
-
-        ProgramStore.Builder bs = new ProgramStore.Builder(mRS, null, null);
-        bs.setDepthFunc(ProgramStore.DepthFunc.LESS);
-        bs.setDitherEnable(false);
-        bs.setDepthMask(true);
-        bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
-                        ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
-        mPSBackground = bs.create();
-        mPSBackground.setName("PFS");
-
-        bs.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
-        bs.setDepthMask(false);
-        bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
-                        ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
-        mPSText = bs.create();
-        mPSText.setName("PFSText");
-
-        mPVAlloc = new ProgramVertex.MatrixAllocation(mRS);
-        mPVAlloc.setupProjectionNormalized(mWidth, mHeight);
-
-        ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
-        mPV = pvb.create();
-        mPV.setName("PV");
-        mPV.bindAllocation(mPVAlloc);
-
-        mPVOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
-        mPVOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
-
-        pvb.setTextureMatrixEnable(true);
-        mPVOrtho = pvb.create();
-        mPVOrtho.setName("PVOrtho");
-        mPVOrtho.bindAllocation(mPVOrthoAlloc);
-
-        mRS.contextBindProgramVertex(mPV);
-
-        mAllocScratchBuf = new int[32];
-        mAllocScratch = Allocation.createSized(mRS,
-            Element.USER_I32(mRS), mAllocScratchBuf.length);
-        mAllocScratch.data(mAllocScratchBuf);
-
-        Log.e("rs", "Done loading named");
-
-
-
-        {
-            mIcons = new Allocation[29];
-            mAllocIconIDBuf = new int[mIcons.length];
-            mAllocIconID = Allocation.createSized(mRS,
-                Element.USER_I32(mRS), mAllocIconIDBuf.length);
-
-            mLabels = new Allocation[29];
-            mAllocLabelIDBuf = new int[mLabels.length];
-            mAllocLabelID = Allocation.createSized(mRS,
-                Element.USER_I32(mRS), mLabels.length);
-
-            Element ie8888 = Element.RGBA_8888(mRS);
-
-            mIcons[0] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.browser, ie8888, true);
-            mIcons[1] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.market, ie8888, true);
-            mIcons[2] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.photos, ie8888, true);
-            mIcons[3] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.settings, ie8888, true);
-            mIcons[4] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.calendar, ie8888, true);
-            mIcons[5] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.g1155, ie8888, true);
-            mIcons[6] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.g2140, ie8888, true);
-            mIcons[7] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.maps, ie8888, true);
-            mIcons[8] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path431, ie8888, true);
-            mIcons[9] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path676, ie8888, true);
-            mIcons[10] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path754, ie8888, true);
-            mIcons[11] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path815, ie8888, true);
-            mIcons[12] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path1920, ie8888, true);
-            mIcons[13] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path1927, ie8888, true);
-            mIcons[14] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path3099, ie8888, true);
-            mIcons[15] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path3950, ie8888, true);
-            mIcons[16] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path4481, ie8888, true);
-            mIcons[17] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path5168, ie8888, true);
-            mIcons[18] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.polygon2408, ie8888, true);
-
-            mLabels[0] = makeTextBitmap("browser");
-            mLabels[1] = makeTextBitmap("market");
-            mLabels[2] = makeTextBitmap("photos");
-            mLabels[3] = makeTextBitmap("settings");
-            mLabels[4] = makeTextBitmap("calendar");
-            mLabels[5] = makeTextBitmap("g1155");
-            mLabels[6] = makeTextBitmap("g2140");
-            mLabels[7] = makeTextBitmap("maps");
-            mLabels[8] = makeTextBitmap("path431");
-            mLabels[9] = makeTextBitmap("path676");
-            mLabels[10] = makeTextBitmap("path754");
-            mLabels[11] = makeTextBitmap("path815");
-            mLabels[12] = makeTextBitmap("path1920");
-            mLabels[13] = makeTextBitmap("path1927");
-            mLabels[14] = makeTextBitmap("path3099");
-            mLabels[15] = makeTextBitmap("path3950");
-            mLabels[16] = makeTextBitmap("path4481");
-            mLabels[17] = makeTextBitmap("path5168");
-            mLabels[18] = makeTextBitmap("polygon2408");
-
-            mIcons[19] = mIcons[0];
-            mIcons[20] = mIcons[1];
-            mIcons[21] = mIcons[2];
-            mIcons[22] = mIcons[3];
-            mIcons[23] = mIcons[4];
-            mIcons[24] = mIcons[5];
-            mIcons[25] = mIcons[6];
-            mIcons[26] = mIcons[7];
-            mIcons[27] = mIcons[8];
-            mIcons[28] = mIcons[9];
-
-            mLabels[19] = mLabels[0];
-            mLabels[20] = mLabels[1];
-            mLabels[21] = mLabels[2];
-            mLabels[22] = mLabels[3];
-            mLabels[23] = mLabels[4];
-            mLabels[24] = mLabels[5];
-            mLabels[25] = mLabels[6];
-            mLabels[26] = mLabels[7];
-            mLabels[27] = mLabels[8];
-            mLabels[28] = mLabels[9];
-
-            for(int ct=0; ct < mIcons.length; ct++) {
-                mIcons[ct].uploadToTexture(0);
-                mLabels[ct].uploadToTexture(0);
-                mAllocIconIDBuf[ct] = mIcons[ct].getID();
-                mAllocLabelIDBuf[ct] = mLabels[ct].getID();
-            }
-            mAllocIconID.data(mAllocIconIDBuf);
-            mAllocLabelID.data(mAllocLabelIDBuf);
-        }
-
-    }
-
-    Allocation makeTextBitmap(String t) {
-        Bitmap b = Bitmap.createBitmap(128, 32, Bitmap.Config.ARGB_8888);
-        Canvas c = new Canvas(b);
-        Paint p = new Paint();
-        p.setTypeface(Typeface.DEFAULT_BOLD);
-        p.setTextSize(20);
-        p.setColor(0xffffffff);
-        c.drawText(t, 2, 26, p);
-        return Allocation.createFromBitmap(mRS, b, Element.RGBA_8888(mRS), true);
-    }
-
-
-    private void initRS() {
-        ScriptC.Builder sb = new ScriptC.Builder(mRS);
-        sb.setScript(mRes, R.raw.rollo);
-        //sb.setScript(mRes, R.raw.rollo2);
-        sb.setRoot(true);
-        mScript = sb.create();
-        mScript.setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
-        mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, -1, 0, mAllocIconIDBuf.length, 0, 0};
-        mAllocState = Allocation.createSized(mRS,
-            Element.USER_I32(mRS), mAllocStateBuf.length);
-        mScript.bindAllocation(mAllocState, 0);
-        mScript.bindAllocation(mAllocIconID, 1);
-        mScript.bindAllocation(mAllocScratch, 2);
-        mScript.bindAllocation(mAllocLabelID, 3);
-        setPosition(0);
-        setZoom(1);
-
-        //RenderScript.File f = mRS.fileOpen("/sdcard/test.a3d");
-
-        mRS.contextBindRootScript(mScript);
-    }
-}
-
-
diff --git a/java/Rollo/src/com/android/rollo/RolloView.java b/java/Rollo/src/com/android/rollo/RolloView.java
deleted file mode 100644
index 7524a0e..0000000
--- a/java/Rollo/src/com/android/rollo/RolloView.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * 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 com.android.rollo;
-
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
-import java.lang.Float;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-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.graphics.PixelFormat;
-
-
-public class RolloView extends RSSurfaceView {
-    public RolloView(Context context) {
-        super(context);
-        setFocusable(true);
-        getHolder().setFormat(PixelFormat.TRANSLUCENT);
-    }
-
-    private RenderScript mRS;
-    private RolloRS mRender;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-
-        mRS = createRenderScript(false);
-        mRender = new RolloRS();
-        mRender.init(mRS, getResources(), w, h);
-    }
-
-    @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);
-    }
-
-    boolean mControlMode = false;
-    boolean mZoomMode = false;
-    boolean mFlingMode = false;
-    float mFlingX = 0;
-    float mFlingY = 0;
-    float mColumn = -1;
-    float mOldColumn;
-    float mZoom = 1;
-
-    int mIconCount = 29;
-    int mRows = 4;
-    int mColumns = (mIconCount + mRows - 1) / mRows;
-
-    float mMaxZoom = ((float)mColumns) / 3.f;
-
-
-    void setColumn(boolean clamp)
-    {
-        //Log.e("rs", " col = " + Float.toString(mColumn));
-        float c = mColumn;
-        if(c > (mColumns -2)) {
-            c = (mColumns -2);
-        }
-        if(c < 0) {
-            c = 0;
-        }
-        mRender.setPosition(c);
-        if(clamp) {
-            mColumn = c;
-        }
-    }
-
-    void computeSelection(float x, float y)
-    {
-        float col = mColumn + (x - 0.5f) * 4 + 1.25f;
-        int iCol = (int)(col + 0.25f);
-
-        float row = (y / 0.8f) * mRows;
-        int iRow = (int)(row - 0.5f);
-
-        mRender.setSelected(iCol * mRows + iRow);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        boolean ret = true;
-        int act = ev.getAction();
-        if (act == ev.ACTION_UP) {
-            ret = false;
-        }
-
-        float nx = ev.getX() / getWidth();
-        float ny = ev.getY() / getHeight();
-
-        //Log.e("rs", "width=" + Float.toString(getWidth()));
-        //Log.e("rs", "height=" + Float.toString(getHeight()));
-
-        mRender.setTouch(ret);
-
-        if((ny > 0.85f) || mControlMode) {
-            mFlingMode = false;
-
-            // Projector control
-            if((nx > 0.2f) && (nx < 0.8f) || mControlMode) {
-                if(act != ev.ACTION_UP) {
-                    float zoom = mMaxZoom;
-                    if(mControlMode) {
-                        if(!mZoomMode) {
-                            zoom = 1.f;
-                        }
-                        float dx = nx - mFlingX;
-
-                        if((ny < 0.9) && mZoomMode) {
-                            zoom = mMaxZoom - ((0.9f - ny) * 10.f);
-                            if(zoom < 1) {
-                                zoom = 1;
-                                mZoomMode = false;
-                            }
-                            mOldColumn = mColumn;
-                        }
-                        mColumn += dx * 4;// * zoom;
-                        if(zoom > 1.01f) {
-                            mColumn += (mZoom - zoom) * (nx - 0.5f) * 4 * zoom;
-                        }
-                    } else {
-                        mOldColumn = mColumn;
-                        mColumn = ((float)mColumns) / 2;
-                        mControlMode = true;
-                        mZoomMode = true;
-                    }
-                    mZoom = zoom;
-                    mFlingX = nx;
-                    mRender.setZoom(zoom);
-                    if(mZoom < 1.01f) {
-                        computeSelection(nx, ny);
-                    }
-                } else {
-                    mControlMode = false;
-                    mColumn = mOldColumn;
-                    mRender.setZoom(1.f);
-                    mRender.setSelected(-1);
-                }
-            } else {
-                // Do something with corners here....
-            }
-            setColumn(true);
-
-        } else {
-            // icon control
-            if(act != ev.ACTION_UP) {
-                if(mFlingMode) {
-                    mColumn += (mFlingX - nx) * 4;
-                    setColumn(true);
-                }
-                mFlingMode = true;
-                mFlingX = nx;
-                mFlingY = ny;
-            } else {
-                mFlingMode = false;
-                mColumn = (float)(java.lang.Math.floor(mColumn * 0.25f + 0.3f) * 4.f) + 1.f;
-                setColumn(true);
-            }
-        }
-
-
-        return ret;
-    }
-
-    @Override
-    public boolean onTrackballEvent(MotionEvent ev)
-    {
-        float x = ev.getX();
-        float y = ev.getY();
-        //Float tx = new Float(x);
-        //Float ty = new Float(y);
-        //Log.e("rs", "tbe " + tx.toString() + ", " + ty.toString());
-
-
-        return true;
-    }
-
-}
-
-
diff --git a/rs.spec b/rs.spec
index a4e72d9..c7ae18a 100644
--- a/rs.spec
+++ b/rs.spec
@@ -372,6 +372,11 @@
 	param bool pointSpriteEnable
 	}
 
+ProgramFragmentSetShader {
+	param const char * text
+	param uint32_t length
+	}
+
 ProgramFragmentBindTexture {
 	param RsProgramFragment pf
 	param uint32_t slot
@@ -414,6 +419,11 @@
 	param bool enable
 	}
 
+ProgramVertexSetShader {
+	param const char * text
+	param uint32_t length
+	}
+
 ProgramVertexAddLight {
 	param RsLight light
 	}
diff --git a/rsAllocation.cpp b/rsAllocation.cpp
index ff8d29f..3aee6b8 100644
--- a/rsAllocation.cpp
+++ b/rsAllocation.cpp
@@ -148,6 +148,7 @@
         return;
     }
     memcpy(mPtr, data, size);
+    sendDirty();
 }
 
 void Allocation::read(void *data)
@@ -168,6 +169,7 @@
         return;
     }
     memcpy(ptr, data, size);
+    sendDirty();
 }
 
 void Allocation::subData(uint32_t xoff, uint32_t yoff,
@@ -192,6 +194,7 @@
         src += lineSize;
         dst += destW * eSize;
     }
+    sendDirty();
 }
 
 void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
@@ -199,6 +202,22 @@
 {
 }
 
+void Allocation::addProgramToDirty(const Program *p)
+{
+    mToDirtyList.add(p);
+}
+
+void Allocation::removeProgramToDirty(const Program *p)
+{
+    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
+        if (mToDirtyList[ct] == p) {
+            mToDirtyList.removeAt(ct);
+            return;
+        }
+    }
+    rsAssert(0);
+}
+
 void Allocation::dumpLOGV(const char *prefix) const
 {
     ObjectBase::dumpLOGV(prefix);
@@ -215,9 +234,14 @@
     LOGV("%s allocation mIsTexture=%i mTextureID=%i, mIsVertexBuffer=%i, mBufferID=%i",
           prefix, mIsTexture, mTextureID, mIsVertexBuffer, mBufferID);
 
-
 }
 
+void Allocation::sendDirty() const
+{
+    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
+        mToDirtyList[ct]->forceDirty();
+    }
+}
 
 /////////////////
 //
@@ -452,31 +476,24 @@
     RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, _dst, _src, genMips, tmp);
     free(tmp);
     return ret;
-
-
-
-
 }
 
 void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes)
 {
     Allocation *a = static_cast<Allocation *>(va);
     a->data(data, sizeBytes);
-    rsc->allocationCheck(a);
 }
 
 void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
 {
     Allocation *a = static_cast<Allocation *>(va);
     a->subData(xoff, count, data, sizeBytes);
-    rsc->allocationCheck(a);
 }
 
 void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
 {
     Allocation *a = static_cast<Allocation *>(va);
     a->subData(xoff, yoff, w, h, data, sizeBytes);
-    rsc->allocationCheck(a);
 }
 
 void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
diff --git a/rsAllocation.h b/rsAllocation.h
index f54284a..490abcf 100644
--- a/rsAllocation.h
+++ b/rsAllocation.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace renderscript {
 
-
+class Program;
 
 class Allocation : public ObjectBase
 {
@@ -65,13 +65,19 @@
     void enableGLVertexBuffers() const;
     void setupGLIndexBuffers() const;
 
+    void addProgramToDirty(const Program *);
+    void removeProgramToDirty(const Program *);
+
     virtual void dumpLOGV(const char *prefix) const;
 
-
 protected:
+    void sendDirty() const;
+
     ObjectBaseRef<const Type> mType;
     void * mPtr;
 
+    Vector<const Program *> mToDirtyList;
+
     // Usage restrictions
     bool mCpuWrite;
     bool mCpuRead;
diff --git a/rsContext.cpp b/rsContext.cpp
index 3652f0a..f815bad 100644
--- a/rsContext.cpp
+++ b/rsContext.cpp
@@ -50,11 +50,12 @@
     }
 }
 
-void Context::initEGL()
+void Context::initEGL(bool useGL2)
 {
     mEGL.mNumConfigs = -1;
     EGLint configAttribs[128];
     EGLint *configAttribsPtr = configAttribs;
+    EGLint context_attribs2[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
 
     memset(configAttribs, 0, sizeof(configAttribs));
 
@@ -62,6 +63,12 @@
     configAttribsPtr[1] = EGL_WINDOW_BIT;
     configAttribsPtr += 2;
 
+    if (useGL2) {
+        configAttribsPtr[0] = EGL_RENDERABLE_TYPE;
+        configAttribsPtr[1] = EGL_OPENGL_ES2_BIT;
+        configAttribsPtr += 2;
+    }
+
     if (mUseDepth) {
         configAttribsPtr[0] = EGL_DEPTH_SIZE;
         configAttribsPtr[1] = 16;
@@ -91,7 +98,11 @@
     //eglChooseConfig(mEGL.mDisplay, configAttribs, &mEGL.mConfig, 1, &mEGL.mNumConfigs);
 
 
-    mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, EGL_NO_CONTEXT, NULL);
+    if (useGL2) {
+        mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, EGL_NO_CONTEXT, context_attribs2);
+    } else {
+        mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, EGL_NO_CONTEXT, NULL);
+    }
     checkEglError("eglCreateContext");
     if (mEGL.mContext == EGL_NO_CONTEXT) {
         LOGE("eglCreateContext returned EGL_NO_CONTEXT");
@@ -225,10 +236,20 @@
 
 void Context::setupCheck()
 {
-    mFragmentStore->setupGL(this, &mStateFragmentStore);
-    mFragment->setupGL(this, &mStateFragment);
-    mRaster->setupGL(this, &mStateRaster);
-    mVertex->setupGL(this, &mStateVertex);
+    if (checkVersion2_0()) {
+        mShaderCache.lookup(mVertex.get(), mFragment.get());
+
+        mFragmentStore->setupGL2(this, &mStateFragmentStore);
+        mFragment->setupGL2(this, &mStateFragment, &mShaderCache);
+        mRaster->setupGL2(this, &mStateRaster);
+        mVertex->setupGL2(this, &mStateVertex, &mShaderCache);
+
+    } else {
+        mFragmentStore->setupGL(this, &mStateFragmentStore);
+        mFragment->setupGL(this, &mStateFragment);
+        mRaster->setupGL(this, &mStateRaster);
+        mVertex->setupGL(this, &mStateVertex);
+    }
 }
 
 static bool getProp(const char *str)
@@ -250,10 +271,6 @@
      rsc->props.mLogScripts = getProp("debug.rs.script");
      rsc->props.mLogObjects = getProp("debug.rs.objects");
 
-     //pthread_mutex_lock(&gInitMutex);
-     //rsc->initEGL();
-     //pthread_mutex_unlock(&gInitMutex);
-
      ScriptTLSStruct *tlsStruct = new ScriptTLSStruct;
      if (!tlsStruct) {
          LOGE("Error allocating tls storage");
@@ -274,6 +291,7 @@
      rsc->setFragment(NULL);
      rsc->mStateFragmentStore.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
      rsc->setFragmentStore(NULL);
+     rsc->mStateVertexArray.init(rsc);
 
      rsc->mRunning = true;
      bool mDraw = true;
@@ -457,7 +475,7 @@
         if (!mEGL.mContext) {
             first = true;
             pthread_mutex_lock(&gInitMutex);
-            initEGL();
+            initEGL(true);
             pthread_mutex_unlock(&gInitMutex);
         }
 
@@ -488,14 +506,24 @@
 
             //LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
             LOGV("GL Version %s", mGL.mVersion);
-            LOGV("GL Vendor %s", mGL.mVendor);
+            //LOGV("GL Vendor %s", mGL.mVendor);
             LOGV("GL Renderer %s", mGL.mRenderer);
             //LOGV("GL Extensions %s", mGL.mExtensions);
 
-            if ((strlen((const char *)mGL.mVersion) < 12) || memcmp(mGL.mVersion, "OpenGL ES-CM", 12)) {
+            const char *verptr = NULL;
+            if (strlen((const char *)mGL.mVersion) > 9) {
+                if (!memcmp(mGL.mVersion, "OpenGL ES-CM", 12)) {
+                    verptr = (const char *)mGL.mVersion + 12;
+                }
+                if (!memcmp(mGL.mVersion, "OpenGL ES ", 10)) {
+                    verptr = (const char *)mGL.mVersion + 9;
+                }
+            }
+
+            if (!verptr) {
                 LOGE("Error, OpenGL ES Lite not supported");
             } else {
-                sscanf((const char *)mGL.mVersion + 13, "%i.%i", &mGL.mMajorVersion, &mGL.mMinorVersion);
+                sscanf(verptr, " %i.%i", &mGL.mMajorVersion, &mGL.mMinorVersion);
             }
         }
 
@@ -544,13 +572,6 @@
     }
 }
 
-void Context::allocationCheck(const Allocation *a)
-{
-    mVertex->checkUpdatedAllocation(a);
-    mFragment->checkUpdatedAllocation(a);
-    mFragmentStore->checkUpdatedAllocation(a);
-}
-
 void Context::setVertex(ProgramVertex *pv)
 {
     if (pv == NULL) {
@@ -558,7 +579,6 @@
     } else {
         mVertex.set(pv);
     }
-    mVertex->forceDirty();
 }
 
 void Context::assignName(ObjectBase *obj, const char *name, uint32_t len)
diff --git a/rsContext.h b/rsContext.h
index 1770ee6..708551c 100644
--- a/rsContext.h
+++ b/rsContext.h
@@ -37,6 +37,8 @@
 #include "rsProgramFragmentStore.h"
 #include "rsProgramRaster.h"
 #include "rsProgramVertex.h"
+#include "rsShaderCache.h"
+#include "rsVertexArray.h"
 
 #include "rsgApiStructs.h"
 #include "rsLocklessFifo.h"
@@ -72,8 +74,10 @@
     ProgramRasterState mStateRaster;
     ProgramVertexState mStateVertex;
     LightState mStateLight;
+    VertexArrayState mStateVertexArray;
 
     ScriptCState mScriptC;
+    ShaderCache mShaderCache;
 
     void swapBuffers();
     void setRootScript(Script *);
@@ -90,7 +94,6 @@
     const ProgramVertex * getVertex() {return mVertex.get();}
 
     void setupCheck();
-    void allocationCheck(const Allocation *);
 
     void pause();
     void resume();
@@ -224,7 +227,7 @@
 private:
     Context();
 
-    void initEGL();
+    void initEGL(bool useGL2);
     void deinitEGL();
 
     uint32_t runRootScript();
diff --git a/rsProgram.cpp b/rsProgram.cpp
index 5f2a609..db40f16 100644
--- a/rsProgram.cpp
+++ b/rsProgram.cpp
@@ -17,6 +17,9 @@
 #include "rsContext.h"
 #include "rsProgram.h"
 
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
 using namespace android;
 using namespace android::renderscript;
 
@@ -25,6 +28,10 @@
 {
     mAllocFile = __FILE__;
     mAllocLine = __LINE__;
+    mDirty = true;
+    mShaderID = 0;
+    mAttribCount = 0;
+    mUniformCount = 0;
 
     mElementIn.set(in);
     mElementOut.set(out);
@@ -32,19 +39,66 @@
 
 Program::~Program()
 {
+    bindAllocation(NULL);
 }
 
 
 void Program::bindAllocation(Allocation *alloc)
 {
+    if (mConstants.get() == alloc) {
+        return;
+    }
+    if (mConstants.get()) {
+        mConstants.get()->removeProgramToDirty(this);
+    }
     mConstants.set(alloc);
+    if (alloc) {
+        alloc->addProgramToDirty(this);
+    }
     mDirty = true;
 }
 
-void Program::checkUpdatedAllocation(const Allocation *alloc)
+void Program::createShader()
 {
-    if (mConstants.get() == alloc) {
-        mDirty = true;
+}
+
+bool Program::loadShader(uint32_t type)
+{
+    mShaderID = glCreateShader(type);
+    rsAssert(mShaderID);
+
+    LOGV("Loading shader type %x, ID %i", type, mShaderID);
+    LOGE(mShader.string());
+
+    if (mShaderID) {
+        const char * ss = mShader.string();
+        glShaderSource(mShaderID, 1, &ss, NULL);
+        glCompileShader(mShaderID);
+
+        GLint compiled = 0;
+        glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
+        if (!compiled) {
+            GLint infoLen = 0;
+            glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen) {
+                char* buf = (char*) malloc(infoLen);
+                if (buf) {
+                    glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
+                    LOGE("Could not compile shader \n%s\n", buf);
+                    free(buf);
+                }
+                glDeleteShader(mShaderID);
+                mShaderID = 0;
+                return false;
+            }
+        }
     }
+    LOGV("--Shader load result %x ", glGetError());
+    return true;
+}
+
+void Program::setShader(const char *txt, uint32_t len)
+{
+    mUserShader.setTo(txt, len);
 }
 
diff --git a/rsProgram.h b/rsProgram.h
index 57c654f..abd461b 100644
--- a/rsProgram.h
+++ b/rsProgram.h
@@ -25,15 +25,27 @@
 namespace renderscript {
 
 
+class ShaderCache;
 
 class Program : public ObjectBase
 {
 public:
+    const static uint32_t MAX_ATTRIBS = 8;
+    const static uint32_t MAX_UNIFORMS = 16;
+
     Program(Context *, Element *in, Element *out);
     virtual ~Program();
 
     void bindAllocation(Allocation *);
-    void checkUpdatedAllocation(const Allocation *);
+    virtual void createShader();
+
+    uint32_t getShaderID() const {return mShaderID;}
+    void setShader(const char *, uint32_t len);
+
+    uint32_t getAttribCount() const {return mAttribCount;}
+    uint32_t getUniformCount() const {return mUniformCount;}
+    const String8 & getAttribName(uint32_t i) const {return mAttribNames[i];}
+    const String8 & getUniformName(uint32_t i) const {return mUniformNames[i];}
 
 protected:
     // Components not listed in "in" will be passed though
@@ -44,10 +56,19 @@
     ObjectBaseRef<Allocation> mConstants;
 
     mutable bool mDirty;
+    String8 mShader;
+    String8 mUserShader;
+    uint32_t mShaderID;
 
+    uint32_t mAttribCount;
+    uint32_t mUniformCount;
+    String8 mAttribNames[MAX_ATTRIBS];
+    String8 mUniformNames[MAX_UNIFORMS];
+
+    bool loadShader(uint32_t type);
 
 public:
-    void forceDirty() {mDirty = true;}
+    void forceDirty() const {mDirty = true;}
 };
 
 
diff --git a/rsProgramFragment.cpp b/rsProgramFragment.cpp
index 708a0e0..b239ce8 100644
--- a/rsProgramFragment.cpp
+++ b/rsProgramFragment.cpp
@@ -19,6 +19,8 @@
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
 
 using namespace android;
 using namespace android::renderscript;
@@ -109,6 +111,105 @@
     mDirty = false;
 }
 
+void ProgramFragment::setupGL2(const Context *rsc, ProgramFragmentState *state, ShaderCache *sc)
+{
+    //LOGE("sgl2 frag1 %x", glGetError());
+    if ((state->mLast.get() == this) && !mDirty) {
+        //return;
+    }
+    state->mLast.set(this);
+
+    for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
+        glActiveTexture(GL_TEXTURE0 + ct);
+        if (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) {
+            glDisable(GL_TEXTURE_2D);
+            continue;
+        }
+
+        glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
+        if (mSamplers[ct].get()) {
+            mSamplers[ct]->setupGL();
+        } else {
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+        }
+
+        glEnable(GL_TEXTURE_2D);
+        glUniform1i(sc->fragUniformSlot(ct), ct);
+    }
+
+    glActiveTexture(GL_TEXTURE0);
+    mDirty = false;
+
+    //LOGE("sgl2 frag2 %x", glGetError());
+}
+
+void ProgramFragment::loadShader() {
+    Program::loadShader(GL_FRAGMENT_SHADER);
+}
+
+void ProgramFragment::createShader()
+{
+    mShader.setTo("precision mediump float;\n");
+    mShader.append("varying vec4 varColor;\n");
+    mShader.append("varying vec4 varTex0;\n");
+
+    uint32_t mask = mTextureEnableMask;
+    uint32_t texNum = 0;
+    while (mask) {
+        if (mask & 1) {
+            char buf[64];
+            mShader.append("uniform sampler2D uni_Tex");
+            sprintf(buf, "%i", texNum);
+            mShader.append(buf);
+            mShader.append(";\n");
+        }
+        mask >>= 1;
+        texNum++;
+    }
+
+
+    mShader.append("void main() {\n");
+    //mShader.append("  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n");
+    mShader.append("  vec4 col = varColor;\n");
+
+    if (mTextureEnableMask) {
+        if (mPointSpriteEnable) {
+            mShader.append("  vec2 tex0 = gl_PointCoord;\n");
+        } else {
+            mShader.append("  vec2 tex0 = varTex0.xy;\n");
+        }
+    }
+
+    mask = mTextureEnableMask;
+    texNum = 0;
+    while (mask) {
+        if (mask & 1) {
+            switch(mEnvModes[texNum]) {
+            case RS_TEX_ENV_MODE_REPLACE:
+                mShader.append("  col = texture2D(uni_Tex0, tex0);\n");
+                break;
+            case RS_TEX_ENV_MODE_MODULATE:
+                mShader.append("  col *= texture2D(uni_Tex0, tex0);\n");
+                break;
+            case RS_TEX_ENV_MODE_DECAL:
+                mShader.append("  col = texture2D(uni_Tex0, tex0);\n");
+                break;
+            }
+
+        }
+        mask >>= 1;
+        texNum++;
+    }
+
+    //mShader.append("  col.a = 1.0;\n");
+    //mShader.append("  col.r = 0.5;\n");
+
+    mShader.append("  gl_FragColor = col;\n");
+    mShader.append("}\n");
+}
 
 void ProgramFragment::bindTexture(uint32_t slot, Allocation *a)
 {
@@ -173,7 +274,14 @@
     }
 }
 
+void ProgramFragment::init(Context *rsc)
+{
+    mUniformCount = 2;
+    mUniformNames[0].setTo("uni_Tex0");
+    mUniformNames[1].setTo("uni_Tex1");
 
+    createShader();
+}
 
 ProgramFragmentState::ProgramFragmentState()
 {
@@ -190,6 +298,7 @@
 {
     ProgramFragment *pf = new ProgramFragment(rsc, NULL, NULL, false);
     mDefault.set(pf);
+    pf->init(rsc);
 }
 
 void ProgramFragmentState::deinit(Context *rsc)
@@ -237,10 +346,16 @@
     rsc->mStateFragment.mPF->setTexEnable(slot, enable);
 }
 
+void rsi_ProgramFragmentSetShader(Context *rsc, const char *txt, uint32_t len)
+{
+    rsc->mStateFragment.mPF->setShader(txt, len);
+}
+
 RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc)
 {
     ProgramFragment *pf = rsc->mStateFragment.mPF;
     pf->incUserRef();
+    pf->init(rsc);
     rsc->mStateFragment.mPF = 0;
     return pf;
 }
diff --git a/rsProgramFragment.h b/rsProgramFragment.h
index e26c6e8..6fc852e 100644
--- a/rsProgramFragment.h
+++ b/rsProgramFragment.h
@@ -36,7 +36,7 @@
     virtual ~ProgramFragment();
 
     virtual void setupGL(const Context *, ProgramFragmentState *);
-
+    virtual void setupGL2(const Context *, ProgramFragmentState *, ShaderCache *sc);
 
 
     void bindTexture(uint32_t slot, Allocation *);
@@ -46,6 +46,9 @@
     void setEnvMode(uint32_t slot, RsTexEnvMode);
     void setTexEnable(uint32_t slot, bool);
 
+    virtual void createShader();
+    virtual void loadShader();
+    virtual void init(Context *rsc);
 
 
 protected:
diff --git a/rsProgramFragmentStore.cpp b/rsProgramFragmentStore.cpp
index de33d9c..d7d5c75 100644
--- a/rsProgramFragmentStore.cpp
+++ b/rsProgramFragmentStore.cpp
@@ -83,10 +83,44 @@
     } else {
         glDisable(GL_DITHER);
     }
-
-
 }
 
+void ProgramFragmentStore::setupGL2(const Context *rsc, ProgramFragmentStoreState *state)
+{
+    if (state->mLast.get() == this) {
+        return;
+    }
+    state->mLast.set(this);
+
+    glColorMask(mColorRWriteEnable,
+                mColorGWriteEnable,
+                mColorBWriteEnable,
+                mColorAWriteEnable);
+    if (mBlendEnable) {
+        glEnable(GL_BLEND);
+        glBlendFunc(mBlendSrc, mBlendDst);
+    } else {
+        glDisable(GL_BLEND);
+    }
+
+    //LOGE("pfs  %i, %i, %x", mDepthWriteEnable, mDepthTestEnable, mDepthFunc);
+
+    glDepthMask(mDepthWriteEnable);
+    if(mDepthTestEnable || mDepthWriteEnable) {
+        glEnable(GL_DEPTH_TEST);
+        glDepthFunc(mDepthFunc);
+    } else {
+        glDisable(GL_DEPTH_TEST);
+    }
+
+    if (mDitherEnable) {
+        glEnable(GL_DITHER);
+    } else {
+        glDisable(GL_DITHER);
+    }
+}
+
+
 void ProgramFragmentStore::setDitherEnable(bool enable)
 {
     mDitherEnable = enable;
diff --git a/rsProgramFragmentStore.h b/rsProgramFragmentStore.h
index a344387..3f9d8c9 100644
--- a/rsProgramFragmentStore.h
+++ b/rsProgramFragmentStore.h
@@ -32,6 +32,7 @@
     virtual ~ProgramFragmentStore();
 
     virtual void setupGL(const Context *, ProgramFragmentStoreState *);
+    virtual void setupGL2(const Context *, ProgramFragmentStoreState *);
 
     void setDepthFunc(RsDepthFunc);
     void setDepthMask(bool);
diff --git a/rsProgramRaster.cpp b/rsProgramRaster.cpp
index 51ae7cf..f0039f7 100644
--- a/rsProgramRaster.cpp
+++ b/rsProgramRaster.cpp
@@ -86,6 +86,14 @@
     }
 }
 
+void ProgramRaster::setupGL2(const Context *rsc, ProgramRasterState *state)
+{
+    if (state->mLast.get() == this) {
+        return;
+    }
+    state->mLast.set(this);
+}
+
 
 
 ProgramRasterState::ProgramRasterState()
diff --git a/rsProgramRaster.h b/rsProgramRaster.h
index a6d5ba8..4efecb4 100644
--- a/rsProgramRaster.h
+++ b/rsProgramRaster.h
@@ -37,6 +37,7 @@
     virtual ~ProgramRaster();
 
     virtual void setupGL(const Context *, ProgramRasterState *);
+    virtual void setupGL2(const Context *, ProgramRasterState *);
 
     void setLineWidth(float w);
     void setPointSize(float s);
diff --git a/rsProgramVertex.cpp b/rsProgramVertex.cpp
index 68f589f..482739c 100644
--- a/rsProgramVertex.cpp
+++ b/rsProgramVertex.cpp
@@ -19,6 +19,8 @@
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
 
 using namespace android;
 using namespace android::renderscript;
@@ -92,6 +94,74 @@
     mDirty = false;
 }
 
+void ProgramVertex::loadShader() {
+    Program::loadShader(GL_VERTEX_SHADER);
+}
+
+void ProgramVertex::createShader()
+{
+    mShader.setTo("");
+
+    for (uint32_t ct=0; ct < mAttribCount; ct++) {
+        mShader.append("attribute vec4 ");
+        mShader.append(mAttribNames[ct]);
+        mShader.append(";\n");
+    }
+
+    for (uint32_t ct=0; ct < mUniformCount; ct++) {
+        mShader.append("uniform mat4 ");
+        mShader.append(mUniformNames[ct]);
+        mShader.append(";\n");
+    }
+
+    mShader.append("varying vec4 varColor;\n");
+    mShader.append("varying vec4 varTex0;\n");
+
+    if (mUserShader.length() > 1) {
+        mShader.append(mUserShader);
+    } else {
+        mShader.append("void main() {\n");
+        mShader.append("  gl_Position = uni_MVP * attrib_Position;\n");
+        mShader.append("  gl_PointSize = attrib_PointSize.x;\n");
+
+        mShader.append("  varColor = attrib_Color;\n");
+        if (mTextureMatrixEnable) {
+            mShader.append("  varTex0 = uni_TexMatrix * attrib_T0;\n");
+        } else {
+            mShader.append("  varTex0 = attrib_T0;\n");
+        }
+        //mShader.append("  pos.x = pos.x / 480.0;\n");
+        //mShader.append("  pos.y = pos.y / 800.0;\n");
+        //mShader.append("  gl_Position = pos;\n");
+        mShader.append("}\n");
+    }
+}
+
+void ProgramVertex::setupGL2(const Context *rsc, ProgramVertexState *state, ShaderCache *sc)
+{
+    //LOGE("sgl2 vtx1 %x", glGetError());
+    if ((state->mLast.get() == this) && !mDirty) {
+        //return;
+    }
+
+    const float *f = static_cast<const float *>(mConstants->getPtr());
+
+    Matrix mvp;
+    mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
+    Matrix t;
+    t.load(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]);
+    mvp.multiply(&t);
+
+    glUniformMatrix4fv(sc->vtxUniformSlot(0), 1, GL_FALSE, mvp.m);
+    if (mTextureMatrixEnable) {
+        glUniformMatrix4fv(sc->vtxUniformSlot(1), 1, GL_FALSE,
+                           &f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET]);
+    }
+
+    state->mLast.set(this);
+    //LOGE("sgl2 vtx2 %x", glGetError());
+}
+
 void ProgramVertex::addLight(const Light *l)
 {
     if (mLightCount < MAX_LIGHTS) {
@@ -130,6 +200,25 @@
     mvp.vectorMultiply(v4out, v3in);
 }
 
+void ProgramVertex::init(Context *rsc)
+{
+    mAttribCount = 6;
+    mAttribNames[VertexArray::POSITION].setTo("attrib_Position");
+    mAttribNames[VertexArray::COLOR].setTo("attrib_Color");
+    mAttribNames[VertexArray::NORMAL].setTo("attrib_Normal");
+    mAttribNames[VertexArray::POINT_SIZE].setTo("attrib_PointSize");
+    mAttribNames[VertexArray::TEXTURE_0].setTo("attrib_T0");
+    mAttribNames[VertexArray::TEXTURE_1].setTo("attrib_T1");
+
+    mUniformCount = 2;
+    mUniformNames[0].setTo("uni_MVP");
+    mUniformNames[1].setTo("uni_TexMatrix");
+
+    createShader();
+}
+
+///////////////////////////////////////////////////////////////////////
+
 ProgramVertexState::ProgramVertexState()
 {
     mPV = NULL;
@@ -154,7 +243,7 @@
     Allocation *alloc = (Allocation *)rsi_AllocationCreateTyped(rsc, mAllocType.get());
     mDefaultAlloc.set(alloc);
     mDefault.set(pv);
-
+    pv->init(rsc);
     pv->bindAllocation(alloc);
 
     updateSize(rsc, w, h);
@@ -194,6 +283,7 @@
 {
     ProgramVertex *pv = rsc->mStateVertex.mPV;
     pv->incUserRef();
+    pv->init(rsc);
     rsc->mStateVertex.mPV = 0;
     return pv;
 }
@@ -209,6 +299,11 @@
     rsc->mStateVertex.mPV->setTextureMatrixEnable(enable);
 }
 
+void rsi_ProgramVertexSetShader(Context *rsc, const char *txt, uint32_t len)
+{
+    rsc->mStateVertex.mPV->setShader(txt, len);
+}
+
 void rsi_ProgramVertexAddLight(Context *rsc, RsLight light)
 {
     rsc->mStateVertex.mPV->addLight(static_cast<const Light *>(light));
diff --git a/rsProgramVertex.h b/rsProgramVertex.h
index a97ba38..aa626da 100644
--- a/rsProgramVertex.h
+++ b/rsProgramVertex.h
@@ -34,6 +34,7 @@
     virtual ~ProgramVertex();
 
     virtual void setupGL(const Context *rsc, ProgramVertexState *state);
+    virtual void setupGL2(const Context *rsc, ProgramVertexState *state, ShaderCache *sc);
 
 
     void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;}
@@ -45,6 +46,10 @@
 
     void transformToScreen(const Context *, float *v4out, const float *v3in) const;
 
+    virtual void createShader();
+    virtual void loadShader();
+    virtual void init(Context *);
+
 
 protected:
     uint32_t mLightCount;
diff --git a/rsSampler.cpp b/rsSampler.cpp
index b793750..f9bdb2e 100644
--- a/rsSampler.cpp
+++ b/rsSampler.cpp
@@ -64,7 +64,6 @@
 
     };
 
-
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, trans[mWrapS]);
diff --git a/rsScriptC_Lib.cpp b/rsScriptC_Lib.cpp
index 23888ff..55a8391 100644
--- a/rsScriptC_Lib.cpp
+++ b/rsScriptC_Lib.cpp
@@ -26,6 +26,8 @@
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
 
 #include <time.h>
 
@@ -102,8 +104,9 @@
 
 static void SC_updateSimpleMesh(RsSimpleMesh mesh)
 {
+    GET_TLS();
     SimpleMesh *sm = static_cast<SimpleMesh *>(mesh);
-    sm->uploadAll();
+    sm->uploadAll(rsc);
 }
 
 static uint32_t SC_loadU32(uint32_t bank, uint32_t offset)
@@ -683,13 +686,13 @@
     rsc->setupCheck();
 
     float vtx[] = { x1, y1, z1, x2, y2, z2 };
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glVertexPointer(3, GL_FLOAT, 0, vtx);
-
-    glDisableClientState(GL_NORMAL_ARRAY);
-    glDisableClientState(GL_COLOR_ARRAY);
+    VertexArray va;
+    va.setPosition(2, GL_FLOAT, 12, (uint32_t)&vtx);
+    if (rsc->checkVersion2_0()) {
+        va.setupGL2(&rsc->mStateVertexArray, &rsc->mShaderCache);
+    } else {
+        va.setupGL(&rsc->mStateVertexArray);
+    }
 
     glDrawArrays(GL_LINES, 0, 2);
 }
@@ -701,12 +704,13 @@
 
     float vtx[] = { x, y, z };
 
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glVertexPointer(3, GL_FLOAT, 0, vtx);
-
-    glDisableClientState(GL_NORMAL_ARRAY);
-    glDisableClientState(GL_COLOR_ARRAY);
+    VertexArray va;
+    va.setPosition(1, GL_FLOAT, 12, (uint32_t)&vtx);
+    if (rsc->checkVersion2_0()) {
+        va.setupGL2(&rsc->mStateVertexArray, &rsc->mShaderCache);
+    } else {
+        va.setupGL(&rsc->mStateVertexArray);
+    }
 
     glDrawArrays(GL_POINTS, 0, 1);
 }
@@ -721,6 +725,7 @@
                                  float u4, float v4)
 {
     GET_TLS();
+    rsc->setupCheck();
 
     //LOGE("Quad");
     //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
@@ -731,26 +736,17 @@
     float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
     const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
 
-    rsc->setupCheck();
+    VertexArray va;
+    va.setPosition(2, GL_FLOAT, 12, (uint32_t)&vtx);
+    va.setTexture(2, GL_FLOAT, 8, (uint32_t)&tex, 0);
+    //va.setTexture(2, GL_FLOAT, 8, (uint32_t)&tex, 1);
+    //
+    if (rsc->checkVersion2_0()) {
+        va.setupGL2(&rsc->mStateVertexArray, &rsc->mShaderCache);
+    } else {
+        va.setupGL(&rsc->mStateVertexArray);
+    }
 
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
-
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glVertexPointer(3, GL_FLOAT, 0, vtx);
-
-    glClientActiveTexture(GL_TEXTURE0);
-    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-    glTexCoordPointer(2, GL_FLOAT, 0, tex);
-    glClientActiveTexture(GL_TEXTURE1);
-    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-    glTexCoordPointer(2, GL_FLOAT, 0, tex);
-    glClientActiveTexture(GL_TEXTURE0);
-
-    glDisableClientState(GL_NORMAL_ARRAY);
-    glDisableClientState(GL_COLOR_ARRAY);
-
-    //glColorPointer(4, GL_UNSIGNED_BYTE, 12, ptr);
 
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 }
@@ -769,18 +765,24 @@
 static void SC_drawSpriteScreenspace(float x, float y, float z, float w, float h)
 {
     GET_TLS();
-    rsc->setupCheck();
+    ObjectBaseRef<const ProgramVertex> tmp(rsc->getVertex());
+    rsc->setVertex(rsc->getDefaultProgramVertex());
+    //rsc->setupCheck();
 
-    GLint crop[4] = {0, h, w, -h};
-    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
-    glDrawTexfOES(x, y, z, w, h);
+    //GLint crop[4] = {0, h, w, -h};
+
+    float sh = rsc->getHeight();
+
+    SC_drawQuad(x,   sh - y,     z,
+                x+w, sh - y,     z,
+                x+w, sh - (y+h), z,
+                x,   sh - (y+h), z);
+    rsc->setVertex((ProgramVertex *)tmp.get());
 }
 
 static void SC_drawSprite(float x, float y, float z, float w, float h)
 {
     GET_TLS();
-    rsc->setupCheck();
-
     float vin[3] = {x, y, z};
     float vout[4];
 
@@ -802,9 +804,8 @@
     //LOGE("ds  out2 %f %f %f", vout[0], vout[1], vout[2]);
 
     // U, V, W, H
-    GLint crop[4] = {0, h, w, -h};
-    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
-    glDrawTexiOES(vout[0], vout[1], 0/*vout[2]*/, w, h);
+    SC_drawSpriteScreenspace(vout[0], vout[1], z, h, w);
+    //rsc->setupCheck();
 }
 
 
@@ -822,7 +823,7 @@
     GET_TLS();
     SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
     rsc->setupCheck();
-    sm->render();
+    sm->render(rsc);
 }
 
 static void SC_drawSimpleMeshRange(RsSimpleMesh vsm, uint32_t start, uint32_t len)
@@ -830,7 +831,7 @@
     GET_TLS();
     SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
     rsc->setupCheck();
-    sm->renderRange(start, len);
+    sm->renderRange(rsc, start, len);
 }
 
 
@@ -840,7 +841,12 @@
 
 static void SC_color(float r, float g, float b, float a)
 {
-    glColor4f(r, g, b, a);
+    GET_TLS();
+    if (rsc->checkVersion2_0()) {
+        glVertexAttrib4f(1, r, g, b, a);
+    } else {
+        glColor4f(r, g, b, a);
+    }
 }
 
 static void SC_ambient(float r, float g, float b, float a)
@@ -945,9 +951,14 @@
 
 static void SC_hsb(float h, float s, float b, float a)
 {
+    GET_TLS();
     float rgb[3];
     SC_hsbToRgb(h, s, b, rgb);
-    glColor4f(rgb[0], rgb[1], rgb[2], a);
+    if (rsc->checkVersion2_0()) {
+        glVertexAttrib4f(1, rgb[0], rgb[1], rgb[2], a);
+    } else {
+        glColor4f(rgb[0], rgb[1], rgb[2], a);
+    }
 }
 
 static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
diff --git a/rsShaderCache.cpp b/rsShaderCache.cpp
new file mode 100644
index 0000000..4b16677
--- /dev/null
+++ b/rsShaderCache.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2009 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"
+
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ShaderCache::ShaderCache()
+{
+    mEntryCount = 0;
+    mEntryAllocationCount = 16;
+    mEntries = (entry_t *)calloc(mEntryAllocationCount, sizeof(entry_t));
+}
+
+ShaderCache::~ShaderCache()
+{
+    for (uint32_t ct=0; ct < mEntryCount; ct++) {
+        glDeleteProgram(mEntries[ct].program);
+    }
+
+    mEntryCount = 0;
+    mEntryAllocationCount = 0;
+    free(mEntries);
+}
+
+bool ShaderCache::lookup(ProgramVertex *vtx, ProgramFragment *frag)
+{
+    if (!vtx->getShaderID()) {
+        vtx->loadShader();
+    }
+    if (!frag->getShaderID()) {
+        frag->loadShader();
+    }
+    //LOGV("ShaderCache lookup  vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
+
+    for (uint32_t ct=0; ct < mEntryCount; ct++) {
+        if ((mEntries[ct].vtx == vtx->getShaderID()) &&
+            (mEntries[ct].frag == frag->getShaderID())) {
+
+            //LOGV("SC using program %i", mEntries[ct].program);
+            glUseProgram(mEntries[ct].program);
+            mCurrent = &mEntries[ct];
+            //LOGV("ShaderCache hit, using %i", ct);
+            return true;
+        }
+    }
+    // Not in cache, add it.
+
+    if (mEntryAllocationCount == mEntryCount) {
+        // Out of space, make some.
+        mEntryAllocationCount *= 2;
+        entry_t *e = (entry_t *)calloc(mEntryAllocationCount, sizeof(entry_t));
+        if (!e) {
+            LOGE("Out of memory for ShaderCache::lookup");
+            return false;
+        }
+        memcpy(e, mEntries, sizeof(entry_t) * mEntryCount);
+        free(mEntries);
+        mEntries = e;
+    }
+
+    //LOGV("ShaderCache miss, using %i", mEntryCount);
+    //LOGE("e0 %x", glGetError());
+
+    entry_t *e = &mEntries[mEntryCount];
+    mCurrent = e;
+    e->vtx = vtx->getShaderID();
+    e->frag = frag->getShaderID();
+    e->program = glCreateProgram();
+    if (mEntries[mEntryCount].program) {
+        GLuint pgm = e->program;
+        glAttachShader(pgm, vtx->getShaderID());
+        //LOGE("e1 %x", glGetError());
+        glAttachShader(pgm, frag->getShaderID());
+
+        glBindAttribLocation(pgm, VertexArray::POSITION, "attrib_Position");
+        glBindAttribLocation(pgm, VertexArray::COLOR, "attrib_Color");
+
+
+        //LOGE("e2 %x", glGetError());
+        glLinkProgram(pgm);
+        //LOGE("e3 %x", glGetError());
+        GLint linkStatus = GL_FALSE;
+        glGetProgramiv(pgm, GL_LINK_STATUS, &linkStatus);
+        if (linkStatus != GL_TRUE) {
+            GLint bufLength = 0;
+            glGetProgramiv(pgm, GL_INFO_LOG_LENGTH, &bufLength);
+            if (bufLength) {
+                char* buf = (char*) malloc(bufLength);
+                if (buf) {
+                    glGetProgramInfoLog(pgm, bufLength, NULL, buf);
+                    LOGE("Could not link program:\n%s\n", buf);
+                    free(buf);
+                }
+            }
+            glDeleteProgram(pgm);
+        }
+        for (uint32_t ct=0; ct < vtx->getAttribCount(); ct++) {
+            e->mVtxAttribSlots[ct] = glGetAttribLocation(pgm, vtx->getAttribName(ct));
+            LOGV("vtx A, %s = %d\n", vtx->getAttribName(ct).string(), e->mVtxAttribSlots[ct]);
+        }
+        for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
+            e->mVtxUniformSlots[ct] = glGetUniformLocation(pgm, vtx->getUniformName(ct));
+            LOGV("vtx U, %s = %d\n", vtx->getUniformName(ct).string(), e->mVtxUniformSlots[ct]);
+        }
+        for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
+            e->mFragUniformSlots[ct] = glGetUniformLocation(pgm, frag->getUniformName(ct));
+            LOGV("frag U, %s = %d\n", frag->getUniformName(ct).string(), e->mFragUniformSlots[ct]);
+        }
+    }
+
+    //LOGV("SC made program %i", e->program);
+    glUseProgram(e->program);
+    mEntryCount++;
+    return true;
+}
+
+void ShaderCache::cleanupVertex(uint32_t id)
+{
+}
+
+void ShaderCache::cleanupFragment(uint32_t id)
+{
+}
+
+void ShaderCache::cleanupAll()
+{
+}
+
diff --git a/rsShaderCache.h b/rsShaderCache.h
new file mode 100644
index 0000000..4d9f8ec
--- /dev/null
+++ b/rsShaderCache.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009 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_SHADER_CACHE_H
+#define ANDROID_SHADER_CACHE_H
+
+
+#include "rsObjectBase.h"
+#include "rsVertexArray.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class ShaderCache
+{
+public:
+    ShaderCache();
+    virtual ~ShaderCache();
+
+    bool lookup(ProgramVertex *, ProgramFragment *);
+
+    void cleanupVertex(uint32_t id);
+    void cleanupFragment(uint32_t id);
+
+    void cleanupAll();
+
+    int32_t vtxAttribSlot(uint32_t a) const {return mCurrent->mVtxAttribSlots[a];}
+    int32_t vtxUniformSlot(uint32_t a) const {return mCurrent->mVtxUniformSlots[a];}
+    int32_t fragAttribSlot(uint32_t a) const {return mCurrent->mFragAttribSlots[a];}
+    int32_t fragUniformSlot(uint32_t a) const {return mCurrent->mFragUniformSlots[a];}
+
+protected:
+    typedef struct {
+        uint32_t vtx;
+        uint32_t frag;
+        uint32_t program;
+        int32_t mVtxAttribSlots[Program::MAX_ATTRIBS];
+        int32_t mVtxUniformSlots[Program::MAX_UNIFORMS];
+        int32_t mFragAttribSlots[Program::MAX_ATTRIBS];
+        int32_t mFragUniformSlots[Program::MAX_UNIFORMS];
+    } entry_t;
+    entry_t *mEntries;
+    entry_t *mCurrent;
+
+    uint32_t mEntryCount;
+    uint32_t mEntryAllocationCount;
+
+};
+
+
+
+}
+}
+#endif //ANDROID_SHADER_CACHE_H
+
+
+
+
diff --git a/rsSimpleMesh.cpp b/rsSimpleMesh.cpp
index b082fd7..edfe967 100644
--- a/rsSimpleMesh.cpp
+++ b/rsSimpleMesh.cpp
@@ -34,39 +34,36 @@
     delete[] mVertexBuffers;
 }
 
-void SimpleMesh::render() const
+void SimpleMesh::render(Context *rsc) const
 {
     if (mPrimitiveType.get()) {
-        renderRange(0, mPrimitiveType->getDimX());
+        renderRange(rsc, 0, mPrimitiveType->getDimX());
         return;
     }
 
     if (mIndexType.get()) {
-        renderRange(0, mIndexType->getDimX());
+        renderRange(rsc, 0, mIndexType->getDimX());
         return;
     }
 
-    renderRange(0, mVertexTypes[0]->getDimX());
+    renderRange(rsc, 0, mVertexTypes[0]->getDimX());
 }
 
-void SimpleMesh::renderRange(uint32_t start, uint32_t len) const
+void SimpleMesh::renderRange(Context *rsc, uint32_t start, uint32_t len) const
 {
     if (len < 1) {
         return;
     }
 
-    glDisableClientState(GL_VERTEX_ARRAY);
-    glDisableClientState(GL_NORMAL_ARRAY);
-    glDisableClientState(GL_COLOR_ARRAY);
-    for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
-        glClientActiveTexture(GL_TEXTURE0 + ct);
-        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    }
-    glClientActiveTexture(GL_TEXTURE0);
-
+    VertexArray va;
     for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
-        glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[ct]->getBufferObjectID());
-        mVertexTypes[ct]->enableGLVertexBuffer();
+        va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
+        mVertexTypes[ct]->enableGLVertexBuffer(&va);
+    }
+    if (rsc->checkVersion2_0()) {
+        va.setupGL2(0, &rsc->mShaderCache);
+    } else {
+        va.setupGL(0);
     }
 
     if (mIndexType.get()) {
@@ -77,7 +74,7 @@
     }
 }
 
-void SimpleMesh::uploadAll()
+void SimpleMesh::uploadAll(Context *rsc)
 {
     for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
         if (mVertexBuffers[ct].get()) {
diff --git a/rsSimpleMesh.h b/rsSimpleMesh.h
index 1e5c908..6defbda 100644
--- a/rsSimpleMesh.h
+++ b/rsSimpleMesh.h
@@ -45,9 +45,9 @@
     uint32_t mGLPrimitive;
 
 
-    void render() const;
-    void renderRange(uint32_t start, uint32_t len) const;
-    void uploadAll();
+    void render(Context *) const;
+    void renderRange(Context *, uint32_t start, uint32_t len) const;
+    void uploadAll(Context *);
 
 
 protected:
diff --git a/rsType.cpp b/rsType.cpp
index ddaa2f0..044ec46 100644
--- a/rsType.cpp
+++ b/rsType.cpp
@@ -245,7 +245,7 @@
     }
 }
 
-void Type::enableGLVertexBuffer() const
+void Type::enableGLVertexBuffer(VertexArray *va) const
 {
     // Note: We are only going to enable buffers and never disable them
     // here.  The reasonis more than one Allocation may be used as a vertex
@@ -254,49 +254,39 @@
 
     uint32_t stride = mElement->getSizeBytes();
     if (mGL.mVtx.size) {
-        //LOGE("va vtx %i %x, %i, %p", mGL.mVtx.size, mGL.mVtx.type, stride, (void *)mGL.mVtx.offset);
-        glEnableClientState(GL_VERTEX_ARRAY);
-        glVertexPointer(mGL.mVtx.size,
+        va->setPosition(mGL.mVtx.size,
                         mGL.mVtx.type,
                         stride,
-                        (void *)mGL.mVtx.offset);
+                        mGL.mVtx.offset);
     }
 
     if (mGL.mNorm.size) {
-        //LOGE("va norm %i %x, %i, %p", mGL.mNorm.size, mGL.mNorm.type, stride, (void *)mGL.mNorm.offset);
-        glEnableClientState(GL_NORMAL_ARRAY);
-        rsAssert(mGL.mNorm.size == 3);
-        glNormalPointer(mGL.mNorm.type,
-                        stride,
-                        (void *)mGL.mNorm.offset);
+        va->setNormal(mGL.mNorm.type,
+                      stride,
+                      mGL.mNorm.offset);
     }
 
     if (mGL.mColor.size) {
-        glEnableClientState(GL_COLOR_ARRAY);
-        glColorPointer(mGL.mColor.size,
-                       mGL.mColor.type,
-                       stride,
-                       (void *)mGL.mColor.offset);
+        va->setColor(mGL.mColor.size,
+                     mGL.mColor.type,
+                     stride,
+                     mGL.mColor.offset);
     }
 
     for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
         if (mGL.mTex[ct].size) {
-            //LOGE("va tex%i %i %x, %i, %p", ct, mGL.mTex[ct].size, mGL.mTex[ct].type, stride, (void *)mGL.mTex[ct].offset);
-            glClientActiveTexture(GL_TEXTURE0 + ct);
-            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-            glTexCoordPointer(mGL.mTex[ct].size,
-                              mGL.mTex[ct].type,
-                              stride,
-                              (void *)mGL.mTex[ct].offset);
+            va->setTexture(mGL.mTex[ct].size,
+                           mGL.mTex[ct].type,
+                           stride,
+                           mGL.mTex[ct].offset,
+                           ct);
         }
     }
-    glClientActiveTexture(GL_TEXTURE0);
 
     if (mGL.mPointSize.size) {
-        glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
-        glPointSizePointerOES(mGL.mPointSize.type,
-                              stride,
-                              (void *)mGL.mPointSize.offset);
+        va->setPointSize(mGL.mPointSize.type,
+                         stride,
+                         mGL.mPointSize.offset);
     }
 
 }
diff --git a/rsType.h b/rsType.h
index 2c43405..d261d58 100644
--- a/rsType.h
+++ b/rsType.h
@@ -67,7 +67,7 @@
     void clear();
     void compute();
 
-    void enableGLVertexBuffer() const;
+    void enableGLVertexBuffer(class VertexArray *) const;
 
     void dumpLOGV(const char *prefix) const;
 
diff --git a/rsVertexArray.cpp b/rsVertexArray.cpp
new file mode 100644
index 0000000..34d42ed
--- /dev/null
+++ b/rsVertexArray.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2009 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"
+
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+VertexArray::VertexArray()
+{
+    memset(mAttribs, 0, sizeof(mAttribs));
+    mActiveBuffer = 0;
+}
+
+VertexArray::~VertexArray()
+{
+}
+
+
+void VertexArray::clearAll()
+{
+    memset(mAttribs, 0, sizeof(mAttribs));
+    mActiveBuffer = 0;
+}
+
+void VertexArray::clear(AttribName n)
+{
+    mAttribs[n].size = 0;
+}
+
+void VertexArray::setPosition(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset)
+{
+    mAttribs[POSITION].buffer = mActiveBuffer;
+    mAttribs[POSITION].type = type;
+    mAttribs[POSITION].size = size;
+    mAttribs[POSITION].offset = offset;
+    mAttribs[POSITION].stride = stride;
+    mAttribs[POSITION].normalized = false;
+}
+
+void VertexArray::setColor(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset)
+{
+    mAttribs[COLOR].buffer = mActiveBuffer;
+    mAttribs[COLOR].type = type;
+    mAttribs[COLOR].size = size;
+    mAttribs[COLOR].offset = offset;
+    mAttribs[COLOR].stride = stride;
+    mAttribs[COLOR].normalized = type != GL_FLOAT;
+}
+
+void VertexArray::setNormal(uint32_t type, uint32_t stride, uint32_t offset)
+{
+    mAttribs[NORMAL].buffer = mActiveBuffer;
+    mAttribs[NORMAL].type = type;
+    mAttribs[NORMAL].size = 3;
+    mAttribs[NORMAL].offset = offset;
+    mAttribs[NORMAL].stride = stride;
+    mAttribs[NORMAL].normalized = type != GL_FLOAT;
+}
+
+void VertexArray::setPointSize(uint32_t type, uint32_t stride, uint32_t offset)
+{
+    mAttribs[POINT_SIZE].buffer = mActiveBuffer;
+    mAttribs[POINT_SIZE].type = type;
+    mAttribs[POINT_SIZE].size = 1;
+    mAttribs[POINT_SIZE].offset = offset;
+    mAttribs[POINT_SIZE].stride = stride;
+    mAttribs[POINT_SIZE].normalized = false;
+}
+
+void VertexArray::setTexture(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset, uint32_t num)
+{
+    mAttribs[TEXTURE_0 + num].buffer = mActiveBuffer;
+    mAttribs[TEXTURE_0 + num].type = type;
+    mAttribs[TEXTURE_0 + num].size = size;
+    mAttribs[TEXTURE_0 + num].offset = offset;
+    mAttribs[TEXTURE_0 + num].stride = stride;
+    mAttribs[TEXTURE_0 + num].normalized = false;
+}
+
+void VertexArray::logAttrib(uint32_t idx) const {
+    LOGE("va %i: buf=%i  size=%i  type=0x%x  stride=0x%x  offset=0x%x", idx,
+         mAttribs[idx].buffer,
+         mAttribs[idx].size,
+         mAttribs[idx].type,
+         mAttribs[idx].stride,
+         mAttribs[idx].offset);
+}
+
+void VertexArray::setupGL(class VertexArrayState *state) const
+{
+    if (mAttribs[POSITION].size) {
+        //logAttrib(POSITION);
+        glEnableClientState(GL_VERTEX_ARRAY);
+        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[POSITION].buffer);
+        glVertexPointer(mAttribs[POSITION].size,
+                        mAttribs[POSITION].type,
+                        mAttribs[POSITION].stride,
+                        (void *)mAttribs[POSITION].offset);
+    } else {
+        rsAssert(0);
+    }
+
+    if (mAttribs[NORMAL].size) {
+        //logAttrib(NORMAL);
+        glEnableClientState(GL_NORMAL_ARRAY);
+        rsAssert(mAttribs[NORMAL].size == 3);
+        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[NORMAL].buffer);
+        glNormalPointer(mAttribs[NORMAL].type,
+                        mAttribs[NORMAL].stride,
+                        (void *)mAttribs[NORMAL].offset);
+    } else {
+        glDisableClientState(GL_NORMAL_ARRAY);
+    }
+
+    if (mAttribs[COLOR].size) {
+        //logAttrib(COLOR);
+        glEnableClientState(GL_COLOR_ARRAY);
+        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[COLOR].buffer);
+        glColorPointer(mAttribs[COLOR].size,
+                       mAttribs[COLOR].type,
+                       mAttribs[COLOR].stride,
+                       (void *)mAttribs[COLOR].offset);
+    } else {
+        glDisableClientState(GL_COLOR_ARRAY);
+    }
+
+    for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
+        glClientActiveTexture(GL_TEXTURE0 + ct);
+        if (mAttribs[TEXTURE_0 + ct].size) {
+            //logAttrib(TEXTURE_0 + ct);
+            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[TEXTURE_0 + ct].buffer);
+            glTexCoordPointer(mAttribs[TEXTURE_0 + ct].size,
+                              mAttribs[TEXTURE_0 + ct].type,
+                              mAttribs[TEXTURE_0 + ct].stride,
+                              (void *)mAttribs[TEXTURE_0 + ct].offset);
+        } else {
+            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+        }
+    }
+    glClientActiveTexture(GL_TEXTURE0);
+
+    if (mAttribs[POINT_SIZE].size) {
+        //logAttrib(POINT_SIZE);
+        glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
+        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[POINT_SIZE].buffer);
+        glPointSizePointerOES(mAttribs[POINT_SIZE].type,
+                              mAttribs[POINT_SIZE].stride,
+                              (void *)mAttribs[POINT_SIZE].offset);
+    } else {
+        glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
+    }
+}
+
+void VertexArray::setupGL2(class VertexArrayState *state, ShaderCache *sc) const
+{
+    for (int ct=1; ct < _LAST; ct++) {
+        glDisableVertexAttribArray(ct);
+    }
+
+    for (int ct=0; ct < _LAST; ct++) {
+        if (mAttribs[ct].size) {
+            //logAttrib(ct);
+            glEnableVertexAttribArray(sc->vtxAttribSlot(ct));
+            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
+            //LOGV("attp %i %i", ct, sc->vtxAttribSlot(ct));
+
+            glVertexAttribPointer(sc->vtxAttribSlot(ct),
+                                  mAttribs[ct].size,
+                                  mAttribs[ct].type,
+                                  mAttribs[ct].normalized,
+                                  mAttribs[ct].stride,
+                                  (void *)mAttribs[ct].offset);
+        } else {
+            //glDisableVertexAttribArray(ct);
+            rsAssert(ct);
+        }
+    }
+}
+////////////////////////////////////////////
+
+void VertexArrayState::init(Context *) {
+    memset(this, 0, sizeof(this));
+}
+
diff --git a/rsVertexArray.h b/rsVertexArray.h
new file mode 100644
index 0000000..235ffef
--- /dev/null
+++ b/rsVertexArray.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 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_VERTEX_ARRAY_H
+#define ANDROID_VERTEX_ARRAY_H
+
+
+#include "rsObjectBase.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class ShaderCache;
+
+// An element is a group of Components that occupies one cell in a structure.
+class VertexArray
+{
+public:
+    VertexArray();
+    virtual ~VertexArray();
+
+    enum AttribName {
+        POSITION,
+        COLOR,
+        NORMAL,
+        POINT_SIZE,
+        TEXTURE_0,
+        TEXTURE_1,
+        _LAST
+    };
+
+    typedef struct {
+        uint32_t buffer;
+        uint32_t offset;
+        uint32_t type;
+        uint32_t size;
+        uint32_t stride;
+        bool normalized;
+    } Attrib;
+
+
+    void clearAll();
+    void clear(AttribName);
+
+    void setActiveBuffer(uint32_t id) {mActiveBuffer = id;}
+
+    void setPosition(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset);
+    void setColor(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset);
+    void setNormal(uint32_t type, uint32_t stride, uint32_t offset);
+    void setPointSize(uint32_t type, uint32_t stride, uint32_t offset);
+    void setTexture(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset, uint32_t num);
+
+    void setupGL(class VertexArrayState *) const;
+    void setupGL2(class VertexArrayState *, ShaderCache *) const;
+    void logAttrib(uint32_t idx) const;
+
+protected:
+    uint32_t mActiveBuffer;
+    Attrib mAttribs[_LAST];
+};
+
+
+class VertexArrayState {
+public:
+    void init(Context *);
+
+    VertexArray::Attrib mAttribs[VertexArray::_LAST];
+};
+
+
+}
+}
+#endif //ANDROID_LIGHT_H
+
+
+