Moving renderscript GL code into the HAL
This change affects
 - shaders
 - meshes
 - fonts
 - quad rendering

Change-Id: I2a53acb4cd1fa8f4c6e67668f6ee969f3d7f7aa1
diff --git a/Android.mk b/Android.mk
index a99a599..232ab36 100644
--- a/Android.mk
+++ b/Android.mk
@@ -110,20 +110,23 @@
 	rsScriptC.cpp \
 	rsScriptC_Lib.cpp \
 	rsScriptC_LibGL.cpp \
-	rsShaderCache.cpp \
 	rsSignal.cpp \
 	rsStream.cpp \
 	rsThreadIO.cpp \
 	rsType.cpp \
-	rsVertexArray.cpp \
 	driver/rsdBcc.cpp \
 	driver/rsdCore.cpp \
 	driver/rsdGL.cpp \
+	driver/rsdMesh.cpp \
+	driver/rsdMeshObj.cpp \
+	driver/rsdProgram.cpp \
 	driver/rsdProgramRaster.cpp \
 	driver/rsdProgramStore.cpp \
 	driver/rsdRuntimeMath.cpp \
-	driver/rsdRuntimeStubs.cpp
-
+	driver/rsdRuntimeStubs.cpp \
+	driver/rsdShader.cpp \
+	driver/rsdShaderCache.cpp \
+	driver/rsdVertexArray.cpp
 
 LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc
 
diff --git a/driver/rsdCore.cpp b/driver/rsdCore.cpp
index 5b80439..d5d23c7 100644
--- a/driver/rsdCore.cpp
+++ b/driver/rsdCore.cpp
@@ -19,6 +19,9 @@
 #include "rsdGL.h"
 #include "rsdProgramStore.h"
 #include "rsdProgramRaster.h"
+#include "rsdProgramVertex.h"
+#include "rsdProgramFragment.h"
+#include "rsdMesh.h"
 
 #include <malloc.h>
 #include "rsContext.h"
@@ -69,6 +72,24 @@
         rsdProgramRasterInit,
         rsdProgramRasterSetActive,
         rsdProgramRasterDestroy
+    },
+
+    {
+        rsdProgramVertexInit,
+        rsdProgramVertexSetActive,
+        rsdProgramVertexDestroy
+    },
+
+    {
+        rsdProgramFragmentInit,
+        rsdProgramFragmentSetActive,
+        rsdProgramFragmentDestroy
+    },
+
+    {
+        rsdMeshInit,
+        rsdMeshDraw,
+        rsdMeshDestroy
     }
 
 };
diff --git a/driver/rsdGL.cpp b/driver/rsdGL.cpp
index 26e1bdf..48690d5 100644
--- a/driver/rsdGL.cpp
+++ b/driver/rsdGL.cpp
@@ -40,6 +40,8 @@
 
 #include <malloc.h>
 #include "rsContext.h"
+#include "rsdShaderCache.h"
+#include "rsdVertexArray.h"
 
 using namespace android;
 using namespace android::renderscript;
@@ -128,6 +130,11 @@
 void rsdGLShutdown(const Context *rsc) {
     RsdHal *dc = (RsdHal *)rsc->mHal.drv;
 
+    dc->gl.shaderCache->cleanupAll();
+    delete dc->gl.shaderCache;
+
+    delete dc->gl.vertexArrayState;
+
     LOGV("%p, deinitEGL", rsc);
 
     if (dc->gl.egl.context != EGL_NO_CONTEXT) {
@@ -287,6 +294,10 @@
         DumpDebug(dc);
     }
 
+    dc->gl.shaderCache = new RsdShaderCache();
+    dc->gl.vertexArrayState = new RsdVertexArrayState();
+    dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
+
     LOGV("initGLThread end %p", rsc);
     return true;
 }
diff --git a/driver/rsdGL.h b/driver/rsdGL.h
index 246931f..351b2d5 100644
--- a/driver/rsdGL.h
+++ b/driver/rsdGL.h
@@ -19,7 +19,8 @@
 
 #include <rs_hal.h>
 
-
+class RsdShaderCache;
+class RsdVertexArrayState;
 
 typedef void (* InvokeFunc_t)(void);
 typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
@@ -64,6 +65,8 @@
     ANativeWindow *wndSurface;
     uint32_t width;
     uint32_t height;
+    RsdShaderCache *shaderCache;
+    RsdVertexArrayState *vertexArrayState;
 } RsdGL;
 
 
diff --git a/driver/rsdMesh.cpp b/driver/rsdMesh.cpp
new file mode 100644
index 0000000..eb62ddb
--- /dev/null
+++ b/driver/rsdMesh.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsMesh.h>
+
+#include "rsdCore.h"
+#include "rsdMesh.h"
+#include "rsdMeshObj.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+bool rsdMeshInit(const Context *rsc, const Mesh *m) {
+    RsdMeshObj *drv = NULL;
+    if(m->mHal.drv) {
+        drv = (RsdMeshObj*)m->mHal.drv;
+        delete drv;
+    }
+    drv = new RsdMeshObj(rsc, m);
+    m->mHal.drv = drv;
+    return drv->init();
+}
+
+void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) {
+    if(m->mHal.drv) {
+        RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+        if (!dc->gl.shaderCache->setup(rsc)) {
+            return;
+        }
+
+        RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv;
+        drv->renderPrimitiveRange(rsc, primIndex, start, len);
+    }
+}
+
+void rsdMeshDestroy(const Context *rsc, const Mesh *m) {
+    if(m->mHal.drv) {
+        RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv;
+        delete drv;
+    }
+}
+
+
diff --git a/driver/rsdMesh.h b/driver/rsdMesh.h
new file mode 100644
index 0000000..d2714fd
--- /dev/null
+++ b/driver/rsdMesh.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSD_MESH_H
+#define RSD_MESH_H
+
+#include <rs_hal.h>
+
+
+bool rsdMeshInit(const android::renderscript::Context *rsc,
+                 const android::renderscript::Mesh *m);
+void rsdMeshDraw(const android::renderscript::Context *rsc,
+                 const android::renderscript::Mesh *m,
+                 uint32_t primIndex, uint32_t start, uint32_t len);
+void rsdMeshDestroy(const android::renderscript::Context *rsc,
+                    const android::renderscript::Mesh *m);
+
+
+#endif
diff --git a/driver/rsdMeshObj.cpp b/driver/rsdMeshObj.cpp
new file mode 100644
index 0000000..6bb33f7
--- /dev/null
+++ b/driver/rsdMeshObj.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES/glext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsMesh.h>
+
+#include "rsdMeshObj.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+RsdMeshObj::RsdMeshObj(const Context *rsc, const Mesh *rsMesh) {
+    mRSMesh = rsMesh;
+
+    mAttribs = NULL;
+    mAttribAllocationIndex = NULL;
+    mGLPrimitives = NULL;
+
+    mAttribCount = 0;
+}
+
+RsdMeshObj::~RsdMeshObj() {
+    if (mAttribs) {
+        delete[] mAttribs;
+        delete[] mAttribAllocationIndex;
+    }
+    if (mGLPrimitives) {
+        delete[] mGLPrimitives;
+    }
+}
+
+bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
+    // Do not create attribs for padding
+    if (elem->getFieldName(fieldIdx)[0] == '#') {
+        return false;
+    }
+
+    // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
+    // Filter rs types accordingly
+    RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
+    if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
+        dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
+        dt != RS_TYPE_SIGNED_16) {
+        return false;
+    }
+
+    // Now make sure they are not arrays
+    uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
+    if (arraySize != 1) {
+        return false;
+    }
+
+    return true;
+}
+
+bool RsdMeshObj::init() {
+
+    updateGLPrimitives();
+
+    // Count the number of gl attrs to initialize
+    mAttribCount = 0;
+    for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
+        const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
+        for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
+            if (isValidGLComponent(elem, ct)) {
+                mAttribCount ++;
+            }
+        }
+    }
+
+    if (mAttribs) {
+        delete [] mAttribs;
+        delete [] mAttribAllocationIndex;
+        mAttribs = NULL;
+        mAttribAllocationIndex = NULL;
+    }
+    if (!mAttribCount) {
+        return false;
+    }
+
+    mAttribs = new RsdVertexArray::Attrib[mAttribCount];
+    mAttribAllocationIndex = new uint32_t[mAttribCount];
+
+    uint32_t userNum = 0;
+    for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
+        const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
+        uint32_t stride = elem->getSizeBytes();
+        for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
+            const Component &c = elem->getField(fieldI)->getComponent();
+
+            if (!isValidGLComponent(elem, fieldI)) {
+                continue;
+            }
+
+            mAttribs[userNum].size = c.getVectorSize();
+            mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
+            mAttribs[userNum].type = c.getGLType();
+            mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+            mAttribs[userNum].stride = stride;
+            String8 tmp(RS_SHADER_ATTR);
+            tmp.append(elem->getFieldName(fieldI));
+            mAttribs[userNum].name.setTo(tmp.string());
+
+            // Remember which allocation this attribute came from
+            mAttribAllocationIndex[userNum] = ct;
+            userNum ++;
+        }
+    }
+
+    return true;
+}
+
+void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
+    if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) {
+        LOGE("Invalid mesh or parameters");
+        return;
+    }
+
+    rsc->checkError("Mesh::renderPrimitiveRange 1");
+    // update attributes with either buffer information or data ptr based on their current state
+    for (uint32_t ct=0; ct < mAttribCount; ct++) {
+        uint32_t allocIndex = mAttribAllocationIndex[ct];
+        Allocation *alloc = mRSMesh->mHal.state.vertexBuffers[allocIndex].get();
+        if (alloc->getIsBufferObject() && alloc->getBufferObjectID()) {
+            mAttribs[ct].buffer = alloc->getBufferObjectID();
+            mAttribs[ct].ptr = NULL;
+        } else {
+            mAttribs[ct].buffer = 0;
+            mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr();
+        }
+    }
+
+    RsdVertexArray va(mAttribs, mAttribCount);
+    va.setupGL2(rsc);
+
+    rsc->checkError("Mesh::renderPrimitiveRange 2");
+    Mesh::Primitive_t *prim = mRSMesh->mHal.state.primitives[primIndex];
+    if (prim->mIndexBuffer.get()) {
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID());
+        glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
+    } else {
+        glDrawArrays(mGLPrimitives[primIndex], start, len);
+    }
+
+    rsc->checkError("Mesh::renderPrimitiveRange");
+}
+
+void RsdMeshObj::updateGLPrimitives() {
+    mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount];
+    for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) {
+        switch (mRSMesh->mHal.state.primitives[i]->mPrimitive) {
+            case RS_PRIMITIVE_POINT:          mGLPrimitives[i] = GL_POINTS; break;
+            case RS_PRIMITIVE_LINE:           mGLPrimitives[i] = GL_LINES; break;
+            case RS_PRIMITIVE_LINE_STRIP:     mGLPrimitives[i] = GL_LINE_STRIP; break;
+            case RS_PRIMITIVE_TRIANGLE:       mGLPrimitives[i] = GL_TRIANGLES; break;
+            case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break;
+            case RS_PRIMITIVE_TRIANGLE_FAN:   mGLPrimitives[i] = GL_TRIANGLE_FAN; break;
+        }
+    }
+}
diff --git a/driver/rsdMeshObj.h b/driver/rsdMeshObj.h
new file mode 100644
index 0000000..8b1271b
--- /dev/null
+++ b/driver/rsdMeshObj.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RSD_MESH_OBJ_H
+#define ANDROID_RSD_MESH_OBJ_H
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+    class Context;
+    class Mesh;
+    class Element;
+
+}
+}
+
+#include "driver/rsdVertexArray.h"
+
+// An element is a group of Components that occupies one cell in a structure.
+class RsdMeshObj {
+public:
+    RsdMeshObj(const android::renderscript::Context *,
+            const android::renderscript::Mesh *);
+    ~RsdMeshObj();
+
+    void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
+
+    bool init();
+
+protected:
+    const android::renderscript::Mesh *mRSMesh;
+
+    uint32_t *mGLPrimitives;
+    void updateGLPrimitives();
+
+    bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx);
+    // Attribues that allow us to map to GL
+    RsdVertexArray::Attrib *mAttribs;
+    // This allows us to figure out which allocation the attribute
+    // belongs to. In the event the allocation is uploaded to GL
+    // buffer, it lets us properly map it
+    uint32_t *mAttribAllocationIndex;
+    uint32_t mAttribCount;
+};
+
+#endif //ANDROID_RSD_MESH_OBJ_H
+
+
+
diff --git a/driver/rsdProgram.cpp b/driver/rsdProgram.cpp
new file mode 100644
index 0000000..502c5ee
--- /dev/null
+++ b/driver/rsdProgram.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "rsdCore.h"
+#include "rsdProgramVertex.h"
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
+#include "rsContext.h"
+#include "rsProgramVertex.h"
+#include "rsProgramFragment.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+bool rsdProgramVertexInit(const Context *rsc, const ProgramVertex *pv,
+                          const char* shader, uint32_t shaderLen) {
+    RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen);
+    pv->mHal.drv = drv;
+
+    return drv->createShader();
+}
+
+void rsdProgramVertexSetActive(const Context *rsc, const ProgramVertex *pv) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+    dc->gl.shaderCache->setActiveVertex((RsdShader*)pv->mHal.drv);
+}
+
+void rsdProgramVertexDestroy(const Context *rsc, const ProgramVertex *pv) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+    RsdShader *drv = NULL;
+    if(pv->mHal.drv) {
+        drv = (RsdShader*)pv->mHal.drv;
+        if (rsc->props.mLogShaders) {
+            LOGV("Destroying vertex shader with ID %u", drv->getShaderID());
+        }
+        if (drv->getShaderID()) {
+            dc->gl.shaderCache->cleanupVertex(drv->getShaderID());
+        }
+        delete drv;
+    }
+}
+
+bool rsdProgramFragmentInit(const Context *rsc, const ProgramFragment *pf,
+                          const char* shader, uint32_t shaderLen) {
+    RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen);
+    pf->mHal.drv = drv;
+
+    return drv->createShader();
+}
+
+void rsdProgramFragmentSetActive(const Context *rsc, const ProgramFragment *pf) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+    dc->gl.shaderCache->setActiveFragment((RsdShader*)pf->mHal.drv);
+}
+
+void rsdProgramFragmentDestroy(const Context *rsc, const ProgramFragment *pf) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+    RsdShader *drv = NULL;
+    if(pf->mHal.drv) {
+        drv = (RsdShader*)pf->mHal.drv;
+        if (rsc->props.mLogShaders) {
+            LOGV("Destroying fragment shader with ID %u", drv->getShaderID());
+        }
+        if (drv->getShaderID()) {
+            dc->gl.shaderCache->cleanupFragment(drv->getShaderID());
+        }
+        delete drv;
+    }
+}
+
+
diff --git a/driver/rsdProgramFragment.h b/driver/rsdProgramFragment.h
new file mode 100644
index 0000000..366cb40
--- /dev/null
+++ b/driver/rsdProgramFragment.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSD_PROGRAM_FRAGMENT_H
+#define RSD_PROGRAM_FRAGMENT_H
+
+#include <rs_hal.h>
+
+
+bool rsdProgramFragmentInit(const android::renderscript::Context *rsc,
+                            const android::renderscript::ProgramFragment *,
+                            const char* shader, uint32_t shaderLen);
+void rsdProgramFragmentSetActive(const android::renderscript::Context *rsc,
+                                 const android::renderscript::ProgramFragment *);
+void rsdProgramFragmentDestroy(const android::renderscript::Context *rsc,
+                               const android::renderscript::ProgramFragment *);
+
+
+#endif //RSD_PROGRAM_Fragment_H
diff --git a/driver/rsdProgramVertex.h b/driver/rsdProgramVertex.h
new file mode 100644
index 0000000..e998572
--- /dev/null
+++ b/driver/rsdProgramVertex.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSD_PROGRAM_VERTEX_H
+#define RSD_PROGRAM_VERTEX_H
+
+#include <rs_hal.h>
+
+bool rsdProgramVertexInit(const android::renderscript::Context *rsc,
+                          const android::renderscript::ProgramVertex *,
+                          const char* shader, uint32_t shaderLen);
+void rsdProgramVertexSetActive(const android::renderscript::Context *rsc,
+                               const android::renderscript::ProgramVertex *);
+void rsdProgramVertexDestroy(const android::renderscript::Context *rsc,
+                             const android::renderscript::ProgramVertex *);
+
+
+#endif //RSD_PROGRAM_VERTEX_H
diff --git a/driver/rsdRuntimeMath.cpp b/driver/rsdRuntimeMath.cpp
index 093e311..acb990d 100644
--- a/driver/rsdRuntimeMath.cpp
+++ b/driver/rsdRuntimeMath.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/driver/rsdRuntimeStubs.cpp b/driver/rsdRuntimeStubs.cpp
index b70a123..9cbff95 100644
--- a/driver/rsdRuntimeStubs.cpp
+++ b/driver/rsdRuntimeStubs.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/driver/rsdShader.cpp b/driver/rsdShader.cpp
new file mode 100644
index 0000000..fc623d6
--- /dev/null
+++ b/driver/rsdShader.cpp
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsProgram.h>
+
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+RsdShader::RsdShader(const Program *p, uint32_t type,
+                       const char * shaderText, uint32_t shaderLength) {
+
+    mUserShader.setTo(shaderText, shaderLength);
+    mRSProgram = p;
+    mType = type;
+    initMemberVars();
+    initAttribAndUniformArray();
+    init();
+}
+
+RsdShader::~RsdShader() {
+    if (mShaderID) {
+        glDeleteShader(mShaderID);
+    }
+
+    delete[] mAttribNames;
+    delete[] mUniformNames;
+    delete[] mUniformArraySizes;
+}
+
+void RsdShader::initMemberVars() {
+    mDirty = true;
+    mShaderID = 0;
+    mAttribCount = 0;
+    mUniformCount = 0;
+
+    mAttribNames = NULL;
+    mUniformNames = NULL;
+    mUniformArraySizes = NULL;
+
+    mIsValid = false;
+}
+
+void RsdShader::init() {
+    uint32_t attribCount = 0;
+    uint32_t uniformCount = 0;
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+        initAddUserElement(mRSProgram->mHal.state.inputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
+    }
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+        initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
+    }
+
+    mTextureUniformIndexStart = uniformCount;
+    char buf[256];
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
+        snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
+        mUniformNames[uniformCount].setTo(buf);
+        mUniformArraySizes[uniformCount] = 1;
+        uniformCount++;
+    }
+}
+
+String8 RsdShader::getGLSLInputString() const {
+    String8 s;
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+        const Element *e = mRSProgram->mHal.state.inputElements[ct].get();
+        for (uint32_t field=0; field < e->getFieldCount(); field++) {
+            const Element *f = e->getField(field);
+
+            // Cannot be complex
+            rsAssert(!f->getFieldCount());
+            switch (f->getComponent().getVectorSize()) {
+            case 1: s.append("attribute float ATTRIB_"); break;
+            case 2: s.append("attribute vec2 ATTRIB_"); break;
+            case 3: s.append("attribute vec3 ATTRIB_"); break;
+            case 4: s.append("attribute vec4 ATTRIB_"); break;
+            default:
+                rsAssert(0);
+            }
+
+            s.append(e->getFieldName(field));
+            s.append(";\n");
+        }
+    }
+    return s;
+}
+
+void RsdShader::appendAttributes() {
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+        const Element *e = mRSProgram->mHal.state.inputElements[ct].get();
+        for (uint32_t field=0; field < e->getFieldCount(); field++) {
+            const Element *f = e->getField(field);
+            const char *fn = e->getFieldName(field);
+
+            if (fn[0] == '#') {
+                continue;
+            }
+
+            // Cannot be complex
+            rsAssert(!f->getFieldCount());
+            switch (f->getComponent().getVectorSize()) {
+            case 1: mShader.append("attribute float ATTRIB_"); break;
+            case 2: mShader.append("attribute vec2 ATTRIB_"); break;
+            case 3: mShader.append("attribute vec3 ATTRIB_"); break;
+            case 4: mShader.append("attribute vec4 ATTRIB_"); break;
+            default:
+                rsAssert(0);
+            }
+
+            mShader.append(fn);
+            mShader.append(";\n");
+        }
+    }
+}
+
+void RsdShader::appendTextures() {
+    char buf[256];
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
+        if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
+            snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+        } else {
+            snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
+        }
+        mShader.append(buf);
+    }
+}
+
+bool RsdShader::createShader() {
+
+    if (mType == GL_FRAGMENT_SHADER) {
+        mShader.append("precision mediump float;\n");
+    }
+    appendUserConstants();
+    appendAttributes();
+    appendTextures();
+
+    mShader.append(mUserShader);
+
+    return true;
+}
+
+bool RsdShader::loadShader(const Context *rsc) {
+    mShaderID = glCreateShader(mType);
+    rsAssert(mShaderID);
+
+    if (rsc->props.mLogShaders) {
+        LOGV("Loading shader type %x, ID %i", mType, mShaderID);
+        LOGV("%s", 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;
+                rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
+                return false;
+            }
+        }
+    }
+
+    if (rsc->props.mLogShaders) {
+        LOGV("--Shader load result %x ", glGetError());
+    }
+    mIsValid = true;
+    return true;
+}
+
+void RsdShader::appendUserConstants() {
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+        const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+        for (uint32_t field=0; field < e->getFieldCount(); field++) {
+            const Element *f = e->getField(field);
+            const char *fn = e->getFieldName(field);
+
+            if (fn[0] == '#') {
+                continue;
+            }
+
+            // Cannot be complex
+            rsAssert(!f->getFieldCount());
+            if (f->getType() == RS_TYPE_MATRIX_4X4) {
+                mShader.append("uniform mat4 UNI_");
+            } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
+                mShader.append("uniform mat3 UNI_");
+            } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
+                mShader.append("uniform mat2 UNI_");
+            } else {
+                switch (f->getComponent().getVectorSize()) {
+                case 1: mShader.append("uniform float UNI_"); break;
+                case 2: mShader.append("uniform vec2 UNI_"); break;
+                case 3: mShader.append("uniform vec3 UNI_"); break;
+                case 4: mShader.append("uniform vec4 UNI_"); break;
+                default:
+                    rsAssert(0);
+                }
+            }
+
+            mShader.append(fn);
+            if (e->getFieldArraySize(field) > 1) {
+                mShader.appendFormat("[%d]", e->getFieldArraySize(field));
+            }
+            mShader.append(";\n");
+        }
+    }
+}
+
+void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
+    RsDataType dataType = field->getType();
+    uint32_t elementSize = field->getSizeBytes() / sizeof(float);
+    for (uint32_t i = 0; i < arraySize; i ++) {
+        if (arraySize > 1) {
+            LOGV("Array Element [%u]", i);
+        }
+        if (dataType == RS_TYPE_MATRIX_4X4) {
+            LOGV("Matrix4x4");
+            LOGV("{%f, %f, %f, %f",  fd[0], fd[4], fd[8], fd[12]);
+            LOGV(" %f, %f, %f, %f",  fd[1], fd[5], fd[9], fd[13]);
+            LOGV(" %f, %f, %f, %f",  fd[2], fd[6], fd[10], fd[14]);
+            LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]);
+        } else if (dataType == RS_TYPE_MATRIX_3X3) {
+            LOGV("Matrix3x3");
+            LOGV("{%f, %f, %f",  fd[0], fd[3], fd[6]);
+            LOGV(" %f, %f, %f",  fd[1], fd[4], fd[7]);
+            LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]);
+        } else if (dataType == RS_TYPE_MATRIX_2X2) {
+            LOGV("Matrix2x2");
+            LOGV("{%f, %f",  fd[0], fd[2]);
+            LOGV(" %f, %f}", fd[1], fd[3]);
+        } else {
+            switch (field->getComponent().getVectorSize()) {
+            case 1:
+                LOGV("Uniform 1 = %f", fd[0]);
+                break;
+            case 2:
+                LOGV("Uniform 2 = %f %f", fd[0], fd[1]);
+                break;
+            case 3:
+                LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
+                break;
+            case 4:
+                LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
+                break;
+            default:
+                rsAssert(0);
+            }
+        }
+        LOGE("Element size %u data=%p", elementSize, fd);
+        fd += elementSize;
+        LOGE("New data=%p", fd);
+    }
+}
+
+void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd,
+                         int32_t slot, uint32_t arraySize ) {
+    RsDataType dataType = field->getType();
+    if (dataType == RS_TYPE_MATRIX_4X4) {
+        glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
+    } else if (dataType == RS_TYPE_MATRIX_3X3) {
+        glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
+    } else if (dataType == RS_TYPE_MATRIX_2X2) {
+        glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
+    } else {
+        switch (field->getComponent().getVectorSize()) {
+        case 1:
+            glUniform1fv(slot, arraySize, fd);
+            break;
+        case 2:
+            glUniform2fv(slot, arraySize, fd);
+            break;
+        case 3:
+            glUniform3fv(slot, arraySize, fd);
+            break;
+        case 4:
+            glUniform4fv(slot, arraySize, fd);
+            break;
+        default:
+            rsAssert(0);
+        }
+    }
+}
+
+void RsdShader::setupTextures(const Context *rsc, RsdShaderCache *sc) {
+    if (mRSProgram->mHal.state.texturesCount == 0) {
+        return;
+    }
+
+    uint32_t numTexturesToBind = mRSProgram->mHal.state.texturesCount;
+    uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures();
+    if (numTexturesToBind >= numTexturesAvailable) {
+        LOGE("Attempting to bind %u textures on shader id %u, but only %u are available",
+             mRSProgram->mHal.state.texturesCount, (uint32_t)this, numTexturesAvailable);
+        rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available");
+        numTexturesToBind = numTexturesAvailable;
+    }
+
+    for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
+        glActiveTexture(GL_TEXTURE0 + ct);
+        if (!mRSProgram->mHal.state.textures[ct].get()) {
+            LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct);
+            rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound");
+            continue;
+        }
+
+        GLenum target = (GLenum)mRSProgram->mHal.state.textures[ct]->getGLTarget();
+        if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
+            LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
+            rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
+        }
+        glBindTexture(target, mRSProgram->mHal.state.textures[ct]->getTextureID());
+        rsc->checkError("ProgramFragment::setupGL2 tex bind");
+        if (mRSProgram->mHal.state.samplers[ct].get()) {
+            mRSProgram->mHal.state.samplers[ct]->setupGL(rsc, mRSProgram->mHal.state.textures[ct].get());
+        } else {
+            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+            glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+            glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+            glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+            rsc->checkError("ProgramFragment::setupGL2 tex env");
+        }
+
+        glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
+        rsc->checkError("ProgramFragment::setupGL2 uniforms");
+    }
+
+    glActiveTexture(GL_TEXTURE0);
+    mDirty = false;
+    rsc->checkError("ProgramFragment::setupGL2");
+}
+
+void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool isFragment) {
+    uint32_t uidx = 0;
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+        Allocation *alloc = mRSProgram->mHal.state.constants[ct].get();
+        if (!alloc) {
+            LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
+            rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
+            continue;
+        }
+
+        const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
+        const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+        for (uint32_t field=0; field < e->getFieldCount(); field++) {
+            const Element *f = e->getField(field);
+            const char *fieldName = e->getFieldName(field);
+            // If this field is padding, skip it
+            if (fieldName[0] == '#') {
+                continue;
+            }
+
+            uint32_t offset = e->getFieldOffsetBytes(field);
+            const float *fd = reinterpret_cast<const float *>(&data[offset]);
+
+            int32_t slot = -1;
+            uint32_t arraySize = 1;
+            if (!isFragment) {
+                slot = sc->vtxUniformSlot(uidx);
+                arraySize = sc->vtxUniformSize(uidx);
+            } else {
+                slot = sc->fragUniformSlot(uidx);
+                arraySize = sc->fragUniformSize(uidx);
+            }
+            if (rsc->props.mLogShadersUniforms) {
+                LOGV("Uniform  slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
+            }
+            uidx ++;
+            if (slot < 0) {
+                continue;
+            }
+
+            if (rsc->props.mLogShadersUniforms) {
+                logUniform(f, fd, arraySize);
+            }
+            setUniform(rsc, f, fd, slot, arraySize);
+        }
+    }
+}
+
+void RsdShader::setup(const android::renderscript::Context *rsc, RsdShaderCache *sc) {
+
+    setupUserConstants(rsc, sc, mType == GL_FRAGMENT_SHADER);
+    setupTextures(rsc, sc);
+}
+
+void RsdShader::initAttribAndUniformArray() {
+    mAttribCount = 0;
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+        const Element *elem = mRSProgram->mHal.state.inputElements[ct].get();
+        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
+            if (elem->getFieldName(field)[0] != '#') {
+                mAttribCount ++;
+            }
+        }
+    }
+
+    mUniformCount = 0;
+    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+        const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+
+        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
+            if (elem->getFieldName(field)[0] != '#') {
+                mUniformCount ++;
+            }
+        }
+    }
+    mUniformCount += mRSProgram->mHal.state.texturesCount;
+
+    if (mAttribCount) {
+        mAttribNames = new String8[mAttribCount];
+    }
+    if (mUniformCount) {
+        mUniformNames = new String8[mUniformCount];
+        mUniformArraySizes = new uint32_t[mUniformCount];
+    }
+}
+
+void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
+    rsAssert(e->getFieldCount());
+    for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
+        const Element *ce = e->getField(ct);
+        if (ce->getFieldCount()) {
+            initAddUserElement(ce, names, arrayLengths, count, prefix);
+        } else if (e->getFieldName(ct)[0] != '#') {
+            String8 tmp(prefix);
+            tmp.append(e->getFieldName(ct));
+            names[*count].setTo(tmp.string());
+            if (arrayLengths) {
+                arrayLengths[*count] = e->getFieldArraySize(ct);
+            }
+            (*count)++;
+        }
+    }
+}
diff --git a/driver/rsdShader.h b/driver/rsdShader.h
new file mode 100644
index 0000000..37b1c3d
--- /dev/null
+++ b/driver/rsdShader.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RSD_SHADER_H
+#define ANDROID_RSD_SHADER_H
+
+#include <utils/String8.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Element;
+class Context;
+class Program;
+
+}
+}
+
+class RsdShaderCache;
+
+#define RS_SHADER_ATTR "ATTRIB_"
+#define RS_SHADER_UNI "UNI_"
+
+class RsdShader {
+public:
+
+    RsdShader(const android::renderscript::Program *p, uint32_t type,
+               const char * shaderText, uint32_t shaderLength);
+    virtual ~RsdShader();
+
+    bool createShader();
+
+    uint32_t getShaderID() const {return mShaderID;}
+
+    uint32_t getAttribCount() const {return mAttribCount;}
+    uint32_t getUniformCount() const {return mUniformCount;}
+    const android::String8 & getAttribName(uint32_t i) const {return mAttribNames[i];}
+    const android::String8 & getUniformName(uint32_t i) const {return mUniformNames[i];}
+    uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];}
+
+    android::String8 getGLSLInputString() const;
+
+    bool isValid() const {return mIsValid;}
+    void forceDirty() const {mDirty = true;}
+
+    bool loadShader(const android::renderscript::Context *);
+    void setup(const android::renderscript::Context *, RsdShaderCache *sc);
+
+protected:
+
+    const android::renderscript::Program *mRSProgram;
+    bool mIsValid;
+
+    // Applies to vertex and fragment shaders only
+    void appendUserConstants();
+    void setupUserConstants(const android::renderscript::Context *rsc, RsdShaderCache *sc, bool isFragment);
+    void initAddUserElement(const android::renderscript::Element *e, android::String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix);
+    void setupTextures(const android::renderscript::Context *rsc, RsdShaderCache *sc);
+
+    void appendAttributes();
+    void appendTextures();
+
+    void initAttribAndUniformArray();
+
+    mutable bool mDirty;
+    android::String8 mShader;
+    android::String8 mUserShader;
+    uint32_t mShaderID;
+    uint32_t mType;
+
+    uint32_t mTextureCount;
+    uint32_t mAttribCount;
+    uint32_t mUniformCount;
+    android::String8 *mAttribNames;
+    android::String8 *mUniformNames;
+    uint32_t *mUniformArraySizes;
+
+    int32_t mTextureUniformIndexStart;
+
+    void logUniform(const android::renderscript::Element *field, const float *fd, uint32_t arraySize );
+    void setUniform(const android::renderscript::Context *rsc, const android::renderscript::Element *field, const float *fd, int32_t slot, uint32_t arraySize );
+    void initMemberVars();
+    void init();
+};
+
+#endif //ANDROID_RSD_SHADER_H
+
+
+
+
diff --git a/rsShaderCache.cpp b/driver/rsdShaderCache.cpp
similarity index 81%
rename from rsShaderCache.cpp
rename to driver/rsdShaderCache.cpp
index e8d89c2..18a8225 100644
--- a/rsShaderCache.cpp
+++ b/driver/rsdShaderCache.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,25 +14,30 @@
  * limitations under the License.
  */
 
-#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
+#include <rs_hal.h>
+#include <rsContext.h>
+
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
 #include <GLES/gl.h>
 #include <GLES2/gl2.h>
-#endif //ANDROID_RS_SERIALIZE
 
 using namespace android;
 using namespace android::renderscript;
 
 
-ShaderCache::ShaderCache() {
+RsdShaderCache::RsdShaderCache() {
     mEntries.setCapacity(16);
+    mVertexDirty = true;
+    mFragmentDirty = true;
 }
 
-ShaderCache::~ShaderCache() {
+RsdShaderCache::~RsdShaderCache() {
     cleanupAll();
 }
 
-void ShaderCache::updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID,
+void RsdShaderCache::updateUniformArrayData(const Context *rsc, RsdShader *prog, uint32_t linkedID,
                                          UniformData *data, const char* logTag,
                                          UniformQueryData **uniformList, uint32_t uniListSize) {
 
@@ -54,14 +59,14 @@
     }
 }
 
-void ShaderCache::populateUniformData(Program *prog, uint32_t linkedID, UniformData *data) {
+void RsdShaderCache::populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data) {
     for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) {
        data[ct].slot = glGetUniformLocation(linkedID, prog->getUniformName(ct));
        data[ct].arraySize = prog->getUniformArraySize(ct);
     }
 }
 
-bool ShaderCache::hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag) {
+bool RsdShaderCache::hasArrayUniforms(RsdShader *vtx, RsdShader *frag) {
     UniformData *data = mCurrent->vtxUniforms;
     for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
         if (data[ct].slot >= 0 && data[ct].arraySize > 1) {
@@ -77,7 +82,31 @@
     return false;
 }
 
-bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag) {
+bool RsdShaderCache::setup(const Context *rsc) {
+    if (!mVertexDirty && !mFragmentDirty) {
+        return true;
+    }
+
+    if (!link(rsc)) {
+        return false;
+    }
+
+    if (mFragmentDirty) {
+        mFragment->setup(rsc, this);
+        mFragmentDirty = false;
+    }
+    if (mVertexDirty) {
+        mVertex->setup(rsc, this);
+        mVertexDirty = false;
+    }
+
+    return true;
+}
+
+bool RsdShaderCache::link(const Context *rsc) {
+
+    RsdShader *vtx = mVertex;
+    RsdShader *frag = mFragment;
     if (!vtx->getShaderID()) {
         vtx->loadShader(rsc);
     }
@@ -89,7 +118,7 @@
     if (!vtx->getShaderID() || !frag->getShaderID()) {
         return false;
     }
-    //LOGV("ShaderCache lookup  vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
+    //LOGV("rsdShaderCache lookup  vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
     uint32_t entryCount = mEntries.size();
     for (uint32_t ct = 0; ct < entryCount; ct ++) {
         if ((mEntries[ct]->vtx == vtx->getShaderID()) &&
@@ -98,13 +127,13 @@
             //LOGV("SC using program %i", mEntries[ct]->program);
             glUseProgram(mEntries[ct]->program);
             mCurrent = mEntries[ct];
-            //LOGV("ShaderCache hit, using %i", ct);
-            rsc->checkError("ShaderCache::lookup (hit)");
+            //LOGV("RsdShaderCache hit, using %i", ct);
+            rsc->checkError("RsdShaderCache::link (hit)");
             return true;
         }
     }
 
-    //LOGV("ShaderCache miss");
+    //LOGV("RsdShaderCache miss");
     //LOGE("e0 %x", glGetError());
     ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(),
                                        vtx->getUniformCount(),
@@ -120,12 +149,10 @@
         //LOGE("e1 %x", glGetError());
         glAttachShader(pgm, frag->getShaderID());
 
-        if (!vtx->isUserProgram()) {
-            glBindAttribLocation(pgm, 0, "ATTRIB_position");
-            glBindAttribLocation(pgm, 1, "ATTRIB_color");
-            glBindAttribLocation(pgm, 2, "ATTRIB_normal");
-            glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
-        }
+        glBindAttribLocation(pgm, 0, "ATTRIB_position");
+        glBindAttribLocation(pgm, 1, "ATTRIB_color");
+        glBindAttribLocation(pgm, 2, "ATTRIB_normal");
+        glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
 
         //LOGE("e2 %x", glGetError());
         glLinkProgram(pgm);
@@ -203,11 +230,12 @@
 
     //LOGV("SC made program %i", e->program);
     glUseProgram(e->program);
-    rsc->checkError("ShaderCache::lookup (miss)");
+    rsc->checkError("RsdShaderCache::link (miss)");
+
     return true;
 }
 
-int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const {
+int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const {
     for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) {
         if (attrName == mCurrent->vtxAttrs[ct].name) {
             return mCurrent->vtxAttrs[ct].slot;
@@ -216,7 +244,7 @@
     return -1;
 }
 
-void ShaderCache::cleanupVertex(uint32_t id) {
+void RsdShaderCache::cleanupVertex(uint32_t id) {
     int32_t numEntries = (int32_t)mEntries.size();
     for (int32_t ct = 0; ct < numEntries; ct ++) {
         if (mEntries[ct]->vtx == id) {
@@ -230,7 +258,7 @@
     }
 }
 
-void ShaderCache::cleanupFragment(uint32_t id) {
+void RsdShaderCache::cleanupFragment(uint32_t id) {
     int32_t numEntries = (int32_t)mEntries.size();
     for (int32_t ct = 0; ct < numEntries; ct ++) {
         if (mEntries[ct]->frag == id) {
@@ -244,7 +272,7 @@
     }
 }
 
-void ShaderCache::cleanupAll() {
+void RsdShaderCache::cleanupAll() {
     for (uint32_t ct=0; ct < mEntries.size(); ct++) {
         glDeleteProgram(mEntries[ct]->program);
         free(mEntries[ct]);
diff --git a/rsShaderCache.h b/driver/rsdShaderCache.h
similarity index 74%
rename from rsShaderCache.h
rename to driver/rsdShaderCache.h
index 3540366..17ee3e8 100644
--- a/rsShaderCache.h
+++ b/driver/rsdShaderCache.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,38 +14,59 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_SHADER_CACHE_H
-#define ANDROID_SHADER_CACHE_H
+#ifndef ANDROID_RSD_SHADER_CACHE_H
+#define ANDROID_RSD_SHADER_CACHE_H
 
-
-#include "rsObjectBase.h"
-#include "rsVertexArray.h"
-
-// ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
 
+class Context;
+
+}
+}
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+class RsdShader;
+
+// ---------------------------------------------------------------------------
 
 // An element is a group of Components that occupies one cell in a structure.
-class ShaderCache {
+class RsdShaderCache {
 public:
-    ShaderCache();
-    virtual ~ShaderCache();
+    RsdShaderCache();
+    virtual ~RsdShaderCache();
 
-    bool lookup(Context *rsc, ProgramVertex *, ProgramFragment *);
+    void setActiveVertex(RsdShader *pv) {
+        mVertexDirty = true;
+        mVertex = pv;
+    }
+
+    void setActiveFragment(RsdShader *pf) {
+        mFragmentDirty = true;
+        mFragment = pf;
+    }
+
+    bool setup(const android::renderscript::Context *rsc);
 
     void cleanupVertex(uint32_t id);
     void cleanupFragment(uint32_t id);
 
     void cleanupAll();
 
-    int32_t vtxAttribSlot(const String8 &attrName) const;
+    int32_t vtxAttribSlot(const android::String8 &attrName) const;
     int32_t vtxUniformSlot(uint32_t a) const {return mCurrent->vtxUniforms[a].slot;}
     uint32_t vtxUniformSize(uint32_t a) const {return mCurrent->vtxUniforms[a].arraySize;}
     int32_t fragUniformSlot(uint32_t a) const {return mCurrent->fragUniforms[a].slot;}
     uint32_t fragUniformSize(uint32_t a) const {return mCurrent->fragUniforms[a].arraySize;}
 
 protected:
+    bool link(const android::renderscript::Context *rsc);
+    bool mFragmentDirty;
+    bool mVertexDirty;
+    RsdShader *mVertex;
+    RsdShader *mFragment;
+
     struct UniformQueryData {
         char *name;
         uint32_t nameLength;
@@ -111,21 +132,19 @@
         UniformData *vtxUniforms;
         UniformData *fragUniforms;
     };
-    Vector<ProgramEntry*> mEntries;
+    android::Vector<ProgramEntry*> mEntries;
     ProgramEntry *mCurrent;
 
-    bool hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag);
-    void populateUniformData(Program *prog, uint32_t linkedID, UniformData *data);
-    void updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID,
+    bool hasArrayUniforms(RsdShader *vtx, RsdShader *frag);
+    void populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data);
+    void updateUniformArrayData(const android::renderscript::Context *rsc,
+                                RsdShader *prog, uint32_t linkedID,
                                 UniformData *data, const char* logTag,
                                 UniformQueryData **uniformList, uint32_t uniListSize);
 };
 
 
-
-}
-}
-#endif //ANDROID_SHADER_CACHE_H
+#endif //ANDROID_RSD_SHADER_CACHE_H
 
 
 
diff --git a/rsVertexArray.cpp b/driver/rsdVertexArray.cpp
similarity index 73%
rename from rsVertexArray.cpp
rename to driver/rsdVertexArray.cpp
index 354ee89..d0a5a54 100644
--- a/rsVertexArray.cpp
+++ b/driver/rsdVertexArray.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,28 +14,32 @@
  * limitations under the License.
  */
 
-#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
+#include <rs_hal.h>
+#include <rsContext.h>
+
 #include <GLES/gl.h>
 #include <GLES2/gl2.h>
-#endif
+
+#include "rsdCore.h"
+#include "rsdVertexArray.h"
+#include "rsdShaderCache.h"
 
 using namespace android;
 using namespace android::renderscript;
 
-VertexArray::VertexArray(const Attrib *attribs, uint32_t numAttribs) {
+RsdVertexArray::RsdVertexArray(const Attrib *attribs, uint32_t numAttribs) {
     mAttribs = attribs;
     mCount = numAttribs;
 }
 
-VertexArray::~VertexArray() {
+RsdVertexArray::~RsdVertexArray() {
 }
 
-VertexArray::Attrib::Attrib() {
+RsdVertexArray::Attrib::Attrib() {
     clear();
 }
 
-void VertexArray::Attrib::clear() {
+void RsdVertexArray::Attrib::clear() {
     buffer = 0;
     offset = 0;
     type = 0;
@@ -46,7 +50,7 @@
     name.setTo("");
 }
 
-void VertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride,
+void RsdVertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride,
                               bool normalized, uint32_t offset,
                               const char *name) {
     clear();
@@ -58,7 +62,7 @@
     this->name.setTo(name);
 }
 
-void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
+void RsdVertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
     if (idx == 0) {
         LOGV("Starting vertex attribute binding");
     }
@@ -74,11 +78,15 @@
          mAttribs[idx].offset);
 }
 
-void VertexArray::setupGL2(const Context *rsc,
-                           class VertexArrayState *state,
-                           ShaderCache *sc) const {
-    rsc->checkError("VertexArray::setupGL2 start");
+void RsdVertexArray::setupGL2(const Context *rsc) const {
+
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+    RsdVertexArrayState *state = dc->gl.vertexArrayState;
+    RsdShaderCache *sc = dc->gl.shaderCache;
+
+    rsc->checkError("RsdVertexArray::setupGL2 start");
     uint32_t maxAttrs = state->mAttrsEnabledSize;
+
     for (uint32_t ct=1; ct < maxAttrs; ct++) {
         if(state->mAttrsEnabled[ct]) {
             glDisableVertexAttribArray(ct);
@@ -86,7 +94,7 @@
         }
     }
 
-    rsc->checkError("VertexArray::setupGL2 disabled");
+    rsc->checkError("RsdVertexArray::setupGL2 disabled");
     for (uint32_t ct=0; ct < mCount; ct++) {
         int32_t slot = sc->vtxAttribSlot(mAttribs[ct].name);
         if (rsc->props.mLogShadersAttr) {
@@ -105,22 +113,22 @@
                               mAttribs[ct].stride,
                               mAttribs[ct].ptr + mAttribs[ct].offset);
     }
-    rsc->checkError("VertexArray::setupGL2 done");
+    rsc->checkError("RsdVertexArray::setupGL2 done");
 }
 ////////////////////////////////////////////
-VertexArrayState::VertexArrayState() {
+RsdVertexArrayState::RsdVertexArrayState() {
     mAttrsEnabled = NULL;
     mAttrsEnabledSize = 0;
 }
 
-VertexArrayState::~VertexArrayState() {
+RsdVertexArrayState::~RsdVertexArrayState() {
     if (mAttrsEnabled) {
         delete[] mAttrsEnabled;
         mAttrsEnabled = NULL;
     }
 }
-void VertexArrayState::init(Context *rsc) {
-    mAttrsEnabledSize = rsc->getMaxVertexAttributes();
+void RsdVertexArrayState::init(uint32_t maxAttrs) {
+    mAttrsEnabledSize = maxAttrs;
     mAttrsEnabled = new bool[mAttrsEnabledSize];
     for (uint32_t ct = 0; ct < mAttrsEnabledSize; ct++) {
         mAttrsEnabled[ct] = false;
diff --git a/rsVertexArray.h b/driver/rsdVertexArray.h
similarity index 69%
rename from rsVertexArray.h
rename to driver/rsdVertexArray.h
index 45d9e82..925a6ae 100644
--- a/rsVertexArray.h
+++ b/driver/rsdVertexArray.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,20 +14,21 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_VERTEX_ARRAY_H
-#define ANDROID_VERTEX_ARRAY_H
+#ifndef ANDROID_RSD_VERTEX_ARRAY_H
+#define ANDROID_RSD_VERTEX_ARRAY_H
 
-
-#include "rsObjectBase.h"
-
-// ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
 
-class ShaderCache;
+class Context;
+
+}
+}
+
+#include <utils/String8.h>
 
 // An element is a group of Components that occupies one cell in a structure.
-class VertexArray {
+class RsdVertexArray {
 public:
     class Attrib {
     public:
@@ -38,17 +39,17 @@
         uint32_t size;
         uint32_t stride;
         bool normalized;
-        String8 name;
+        android::String8 name;
 
         Attrib();
         void clear();
         void set(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name);
     };
 
-    VertexArray(const Attrib *attribs, uint32_t numAttribs);
-    virtual ~VertexArray();
+    RsdVertexArray(const Attrib *attribs, uint32_t numAttribs);
+    virtual ~RsdVertexArray();
 
-    void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const;
+    void setupGL2(const android::renderscript::Context *rsc) const;
     void logAttrib(uint32_t idx, uint32_t slot) const;
 
 protected:
@@ -61,20 +62,18 @@
 };
 
 
-class VertexArrayState {
+class RsdVertexArrayState {
 public:
-    VertexArrayState();
-    ~VertexArrayState();
-    void init(Context *);
+    RsdVertexArrayState();
+    ~RsdVertexArrayState();
+    void init(uint32_t maxAttrs);
 
     bool *mAttrsEnabled;
     uint32_t mAttrsEnabledSize;
 };
 
 
-}
-}
-#endif //ANDROID_VERTEX_ARRAY_H
+#endif //ANDROID_RSD_VERTEX_ARRAY_H
 
 
 
diff --git a/rsContext.cpp b/rsContext.cpp
index 50f5f55..a07ded3 100644
--- a/rsContext.cpp
+++ b/rsContext.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -215,15 +215,11 @@
 }
 
 bool Context::setupCheck() {
-    if (!mShaderCache.lookup(this, mVertex.get(), mFragment.get())) {
-        LOGE("Context::setupCheck() 1 fail");
-        return false;
-    }
 
     mFragmentStore->setup(this, &mStateFragmentStore);
-    mFragment->setupGL2(this, &mStateFragment, &mShaderCache);
+    mFragment->setupGL2(this, &mStateFragment);
     mRaster->setup(this, &mStateRaster);
-    mVertex->setupGL2(this, &mStateVertex, &mShaderCache);
+    mVertex->setupGL2(this, &mStateVertex);
     mFBOCache.setupGL2(this);
     return true;
 }
@@ -295,7 +291,6 @@
         rsc->setProgramStore(NULL);
         rsc->mStateFont.init(rsc);
         rsc->setFont(NULL);
-        rsc->mStateVertexArray.init(rsc);
     }
 
     rsc->mRunning = true;
@@ -356,7 +351,6 @@
          mStateFragment.deinit(this);
          mStateFragmentStore.deinit(this);
          mStateFont.deinit(this);
-         mShaderCache.cleanupAll();
     }
     //LOGV("destroyWorkerThreadResources 2");
     mExit = true;
diff --git a/rsContext.h b/rsContext.h
index df85a6b..107f639 100644
--- a/rsContext.h
+++ b/rsContext.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -37,9 +37,7 @@
 #include "rsProgramStore.h"
 #include "rsProgramRaster.h"
 #include "rsProgramVertex.h"
-#include "rsShaderCache.h"
 #include "rsFBOCache.h"
-#include "rsVertexArray.h"
 
 #include "rsgApiStructs.h"
 #include "rsLocklessFifo.h"
@@ -111,11 +109,9 @@
     ProgramStoreState mStateFragmentStore;
     ProgramRasterState mStateRaster;
     ProgramVertexState mStateVertex;
-    VertexArrayState mStateVertexArray;
     FontState mStateFont;
 
     ScriptCState mScriptC;
-    ShaderCache mShaderCache;
     FBOCache mFBOCache;
 
     void swapBuffers();
diff --git a/rsFont.cpp b/rsFont.cpp
index b7b85b6..5e47ddb 100644
--- a/rsFont.cpp
+++ b/rsFont.cpp
@@ -25,11 +25,6 @@
 #include FT_FREETYPE_H
 #include FT_BITMAP_H
 
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
 using namespace android;
 using namespace android::renderscript;
 
@@ -457,7 +452,7 @@
 
     // This will dirty the texture and the shader so next time
     // we draw it will upload the data
-    mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
+    mTextTexture->deferredUploadToTexture(mRSC);
     mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
 
     // Some debug code
@@ -568,7 +563,6 @@
     }
 
     indexAlloc->deferredUploadToBufferObject(mRSC);
-    mIndexBuffer.set(indexAlloc);
 
     const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
     const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
@@ -585,7 +579,10 @@
     Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
     mTextMeshPtr = (float*)vertexAlloc->getPtr();
 
-    mVertexArray.set(vertexAlloc);
+    mMesh.set(new Mesh(mRSC, 1, 1));
+    mMesh->setVertexBuffer(vertexAlloc, 0);
+    mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
+    mMesh->init();
 }
 
 // We don't want to allocate anything unless we actually draw text
@@ -625,18 +622,7 @@
         return;
     }
 
-    float *vtx = (float*)mVertexArray->getPtr();
-    float *tex = vtx + 3;
-
-    VertexArray::Attrib attribs[2];
-    attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
-    attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
-    VertexArray va(attribs, 2);
-    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
-
-    mIndexBuffer->uploadCheck(mRSC);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
-    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
+    mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
 }
 
 void FontState::appendMeshQuad(float x1, float y1, float z1,
@@ -787,8 +773,7 @@
 
     mFontShaderFConstant.clear();
 
-    mIndexBuffer.clear();
-    mVertexArray.clear();
+    mMesh.clear();
 
     mFontShaderF.clear();
     mFontSampler.clear();
diff --git a/rsFont.h b/rsFont.h
index 91a5da9..d18c0d9 100644
--- a/rsFont.h
+++ b/rsFont.h
@@ -230,9 +230,7 @@
     uint32_t mMaxNumberOfQuads;
 
     void initVertexArrayBuffers();
-    ObjectBaseRef<Allocation> mIndexBuffer;
-    ObjectBaseRef<Allocation> mVertexArray;
-
+    ObjectBaseRef<Mesh> mMesh;
 
     bool mInitialized;
 
diff --git a/rsMesh.cpp b/rsMesh.cpp
index e29c800..ed29063 100644
--- a/rsMesh.cpp
+++ b/rsMesh.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,46 +15,53 @@
  */
 
 #include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES2/gl2.h>
-#include <GLES/glext.h>
-#endif
 
 using namespace android;
 using namespace android::renderscript;
 
 Mesh::Mesh(Context *rsc) : ObjectBase(rsc) {
-    mPrimitives = NULL;
-    mPrimitivesCount = 0;
-    mVertexBuffers = NULL;
-    mVertexBufferCount = 0;
+    mHal.drv = NULL;
+    mHal.state.primitives = NULL;
+    mHal.state.primitivesCount = 0;
+    mHal.state.vertexBuffers = NULL;
+    mHal.state.vertexBuffersCount = 0;
+    mInitialized = false;
+}
 
-#ifndef ANDROID_RS_SERIALIZE
-    mAttribs = NULL;
-    mAttribAllocationIndex = NULL;
-
-    mAttribCount = 0;
-#endif
+Mesh::Mesh(Context *rsc,
+           uint32_t vertexBuffersCount,
+           uint32_t primitivesCount) : ObjectBase(rsc) {
+    mHal.drv = NULL;
+    mHal.state.primitivesCount = primitivesCount;
+    mHal.state.primitives = new Primitive_t *[mHal.state.primitivesCount];
+    for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) {
+        mHal.state.primitives[i] = new Primitive_t;
+    }
+    mHal.state.vertexBuffersCount = vertexBuffersCount;
+    mHal.state.vertexBuffers = new ObjectBaseRef<Allocation>[mHal.state.vertexBuffersCount];
 }
 
 Mesh::~Mesh() {
-    if (mVertexBuffers) {
-        delete[] mVertexBuffers;
-    }
-
-    if (mPrimitives) {
-        for (uint32_t i = 0; i < mPrimitivesCount; i ++) {
-            delete mPrimitives[i];
-        }
-        delete[] mPrimitives;
-    }
-
 #ifndef ANDROID_RS_SERIALIZE
-    if (mAttribs) {
-        delete[] mAttribs;
-        delete[] mAttribAllocationIndex;
+    mRSC->mHal.funcs.mesh.destroy(mRSC, this);
+#endif
+
+    if (mHal.state.vertexBuffers) {
+        delete[] mHal.state.vertexBuffers;
     }
+
+    if (mHal.state.primitives) {
+        for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) {
+            mHal.state.primitives[i]->mIndexBuffer.clear();
+            delete mHal.state.primitives[i];
+        }
+        delete[] mHal.state.primitives;
+    }
+}
+
+void Mesh::init() {
+#ifndef ANDROID_RS_SERIALIZE
+    mRSC->mHal.funcs.mesh.init(mRSC, this);
 #endif
 }
 
@@ -66,15 +73,15 @@
     stream->addString(&name);
 
     // Store number of vertex streams
-    stream->addU32(mVertexBufferCount);
-    for (uint32_t vCount = 0; vCount < mVertexBufferCount; vCount ++) {
-        mVertexBuffers[vCount]->serialize(stream);
+    stream->addU32(mHal.state.vertexBuffersCount);
+    for (uint32_t vCount = 0; vCount < mHal.state.vertexBuffersCount; vCount ++) {
+        mHal.state.vertexBuffers[vCount]->serialize(stream);
     }
 
-    stream->addU32(mPrimitivesCount);
+    stream->addU32(mHal.state.primitivesCount);
     // Store the primitives
-    for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) {
-        Primitive_t * prim = mPrimitives[pCount];
+    for (uint32_t pCount = 0; pCount < mHal.state.primitivesCount; pCount ++) {
+        Primitive_t * prim = mHal.state.primitives[pCount];
 
         stream->addU8((uint8_t)prim->mPrimitive);
 
@@ -95,45 +102,60 @@
         return NULL;
     }
 
-    Mesh * mesh = new Mesh(rsc);
-
     String8 name;
     stream->loadString(&name);
-    mesh->setName(name.string(), name.size());
 
-    mesh->mVertexBufferCount = stream->loadU32();
-    if (mesh->mVertexBufferCount) {
-        mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexBufferCount];
+    uint32_t vertexBuffersCount = stream->loadU32();
+    ObjectBaseRef<Allocation> *vertexBuffers = NULL;
+    if (vertexBuffersCount) {
+        vertexBuffers = new ObjectBaseRef<Allocation>[vertexBuffersCount];
 
-        for (uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) {
+        for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
             Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
-            mesh->mVertexBuffers[vCount].set(vertexAlloc);
+            vertexBuffers[vCount].set(vertexAlloc);
         }
     }
 
-    mesh->mPrimitivesCount = stream->loadU32();
-    if (mesh->mPrimitivesCount) {
-        mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount];
+    uint32_t primitivesCount = stream->loadU32();
+    ObjectBaseRef<Allocation> *indexBuffers = NULL;
+    RsPrimitive *primitives = NULL;
+    if (primitivesCount) {
+        indexBuffers = new ObjectBaseRef<Allocation>[primitivesCount];
+        primitives = new RsPrimitive[primitivesCount];
 
         // load all primitives
-        for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) {
-            Primitive_t * prim = new Primitive_t;
-            mesh->mPrimitives[pCount] = prim;
-
-            prim->mPrimitive = (RsPrimitive)stream->loadU8();
+        for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
+            primitives[pCount] = (RsPrimitive)stream->loadU8();
 
             // Check to see if the index buffer was stored
             uint32_t isIndexPresent = stream->loadU32();
             if (isIndexPresent) {
                 Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
-                prim->mIndexBuffer.set(indexAlloc);
+                indexBuffers[pCount].set(indexAlloc);
             }
         }
     }
 
+    Mesh *mesh = new Mesh(rsc, vertexBuffersCount, primitivesCount);
+    mesh->setName(name.string(), name.size());
+    for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
+        mesh->setVertexBuffer(vertexBuffers[vCount].get(), vCount);
+    }
+    for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
+        mesh->setPrimitive(indexBuffers[pCount].get(), primitives[pCount], pCount);
+    }
+
+    // Cleanup
+    if (vertexBuffersCount) {
+        delete[] vertexBuffers;
+    }
+    if (primitivesCount) {
+        delete[] indexBuffers;
+        delete[] primitives;
+    }
+
 #ifndef ANDROID_RS_SERIALIZE
-    mesh->updateGLPrimitives();
-    mesh->initVertexAttribs();
+    mesh->init();
     mesh->uploadAll(rsc);
 #endif
     return mesh;
@@ -141,167 +163,58 @@
 
 #ifndef ANDROID_RS_SERIALIZE
 
-bool Mesh::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
-    // Do not create attribs for padding
-    if (elem->getFieldName(fieldIdx)[0] == '#') {
-        return false;
-    }
-
-    // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
-    // Filter rs types accordingly
-    RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
-    if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
-       dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
-       dt != RS_TYPE_SIGNED_16) {
-        return false;
-    }
-
-    // Now make sure they are not arrays
-    uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
-    if (arraySize != 1) {
-        return false;
-    }
-
-    return true;
-}
-
-void Mesh::initVertexAttribs() {
-    // Count the number of gl attrs to initialize
-    mAttribCount = 0;
-    for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
-        const Element *elem = mVertexBuffers[ct]->getType()->getElement();
-        for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
-            if (isValidGLComponent(elem, ct)) {
-                mAttribCount ++;
-            }
-        }
-    }
-
-    if (mAttribs) {
-        delete [] mAttribs;
-        delete [] mAttribAllocationIndex;
-        mAttribs = NULL;
-        mAttribAllocationIndex = NULL;
-    }
-    if (!mAttribCount) {
-        return;
-    }
-
-    mAttribs = new VertexArray::Attrib[mAttribCount];
-    mAttribAllocationIndex = new uint32_t[mAttribCount];
-
-    uint32_t userNum = 0;
-    for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
-        const Element *elem = mVertexBuffers[ct]->getType()->getElement();
-        uint32_t stride = elem->getSizeBytes();
-        for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
-            const Component &c = elem->getField(fieldI)->getComponent();
-
-            if (!isValidGLComponent(elem, fieldI)) {
-                continue;
-            }
-
-            mAttribs[userNum].size = c.getVectorSize();
-            mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
-            mAttribs[userNum].type = c.getGLType();
-            mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
-            mAttribs[userNum].stride = stride;
-            String8 tmp(RS_SHADER_ATTR);
-            tmp.append(elem->getFieldName(fieldI));
-            mAttribs[userNum].name.setTo(tmp.string());
-
-            // Remember which allocation this attribute came from
-            mAttribAllocationIndex[userNum] = ct;
-            userNum ++;
-        }
-    }
-}
-
 void Mesh::render(Context *rsc) const {
-    for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
+    for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
         renderPrimitive(rsc, ct);
     }
 }
 
 void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const {
-    if (primIndex >= mPrimitivesCount) {
+    if (primIndex >= mHal.state.primitivesCount) {
         LOGE("Invalid primitive index");
         return;
     }
 
-    Primitive_t *prim = mPrimitives[primIndex];
+    Primitive_t *prim = mHal.state.primitives[primIndex];
 
     if (prim->mIndexBuffer.get()) {
         renderPrimitiveRange(rsc, primIndex, 0, prim->mIndexBuffer->getType()->getDimX());
         return;
     }
 
-    renderPrimitiveRange(rsc, primIndex, 0, mVertexBuffers[0]->getType()->getDimX());
+    renderPrimitiveRange(rsc, primIndex, 0, mHal.state.vertexBuffers[0]->getType()->getDimX());
 }
 
 void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
-    if (len < 1 || primIndex >= mPrimitivesCount || mAttribCount == 0) {
+    if (len < 1 || primIndex >= mHal.state.primitivesCount) {
         LOGE("Invalid mesh or parameters");
         return;
     }
 
-    rsc->checkError("Mesh::renderPrimitiveRange 1");
-    for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
-        mVertexBuffers[ct]->uploadCheck(rsc);
-    }
-    // update attributes with either buffer information or data ptr based on their current state
-    for (uint32_t ct=0; ct < mAttribCount; ct++) {
-        uint32_t allocIndex = mAttribAllocationIndex[ct];
-        Allocation *alloc = mVertexBuffers[allocIndex].get();
-        if (alloc->getIsBufferObject()) {
-            mAttribs[ct].buffer = alloc->getBufferObjectID();
-            mAttribs[ct].ptr = NULL;
-        } else {
-            mAttribs[ct].buffer = 0;
-            mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr();
-        }
+    for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) {
+        mHal.state.vertexBuffers[ct]->uploadCheck(rsc);
     }
 
-    VertexArray va(mAttribs, mAttribCount);
-    va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
-
-    rsc->checkError("Mesh::renderPrimitiveRange 2");
-    Primitive_t *prim = mPrimitives[primIndex];
+    Primitive_t *prim = mHal.state.primitives[primIndex];
     if (prim->mIndexBuffer.get()) {
         prim->mIndexBuffer->uploadCheck(rsc);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID());
-        glDrawElements(prim->mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
-    } else {
-        glDrawArrays(prim->mGLPrimitive, start, len);
     }
+    rsc->checkError("Mesh::renderPrimitiveRange upload check");
 
-    rsc->checkError("Mesh::renderPrimitiveRange");
+    mRSC->mHal.funcs.mesh.draw(mRSC, this, primIndex, start, len);
+    rsc->checkError("Mesh::renderPrimitiveRange draw");
 }
 
-
 void Mesh::uploadAll(Context *rsc) {
-    for (uint32_t ct = 0; ct < mVertexBufferCount; ct ++) {
-        if (mVertexBuffers[ct].get()) {
-            mVertexBuffers[ct]->deferredUploadToBufferObject(rsc);
+    for (uint32_t ct = 0; ct < mHal.state.vertexBuffersCount; ct ++) {
+        if (mHal.state.vertexBuffers[ct].get()) {
+            mHal.state.vertexBuffers[ct]->deferredUploadToBufferObject(rsc);
         }
     }
 
-    for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
-        if (mPrimitives[ct]->mIndexBuffer.get()) {
-            mPrimitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc);
-        }
-    }
-}
-
-void Mesh::updateGLPrimitives() {
-    for (uint32_t i = 0; i < mPrimitivesCount; i ++) {
-        switch (mPrimitives[i]->mPrimitive) {
-            case RS_PRIMITIVE_POINT:          mPrimitives[i]->mGLPrimitive = GL_POINTS; break;
-            case RS_PRIMITIVE_LINE:           mPrimitives[i]->mGLPrimitive = GL_LINES; break;
-            case RS_PRIMITIVE_LINE_STRIP:     mPrimitives[i]->mGLPrimitive = GL_LINE_STRIP; break;
-            case RS_PRIMITIVE_TRIANGLE:       mPrimitives[i]->mGLPrimitive = GL_TRIANGLES; break;
-            case RS_PRIMITIVE_TRIANGLE_STRIP: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_STRIP; break;
-            case RS_PRIMITIVE_TRIANGLE_FAN:   mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_FAN; break;
+    for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
+        if (mHal.state.primitives[ct]->mIndexBuffer.get()) {
+            mHal.state.primitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc);
         }
     }
 }
@@ -312,8 +225,8 @@
     uint32_t stride = 0;
     uint32_t numVerts = 0;
     // First we need to find the position ptr and stride
-    for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
-        const Type *bufferType = mVertexBuffers[ct]->getType();
+    for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) {
+        const Type *bufferType = mHal.state.vertexBuffers[ct]->getType();
         const Element *bufferElem = bufferType->getElement();
 
         for (uint32_t ct=0; ct < bufferElem->getFieldCount(); ct++) {
@@ -321,7 +234,7 @@
                 vectorSize = bufferElem->getField(ct)->getComponent().getVectorSize();
                 stride = bufferElem->getSizeBytes() / sizeof(float);
                 uint32_t offset = bufferElem->getFieldOffsetBytes(ct);
-                posPtr = (float*)((uint8_t*)mVertexBuffers[ct]->getPtr() + offset);
+                posPtr = (float*)((uint8_t*)mHal.state.vertexBuffers[ct]->getPtr() + offset);
                 numVerts = bufferType->getDimX();
                 break;
             }
@@ -353,73 +266,62 @@
 namespace renderscript {
 
 RsMesh rsi_MeshCreate(Context *rsc, uint32_t vtxCount, uint32_t idxCount) {
-    Mesh *sm = new Mesh(rsc);
+    Mesh *sm = new Mesh(rsc, vtxCount, idxCount);
     sm->incUserRef();
 
-    sm->mPrimitivesCount = idxCount;
-    sm->mPrimitives = new Mesh::Primitive_t *[sm->mPrimitivesCount];
-    for (uint32_t ct = 0; ct < idxCount; ct ++) {
-        sm->mPrimitives[ct] = new Mesh::Primitive_t;
-    }
-
-    sm->mVertexBufferCount = vtxCount;
-    sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
-
     return sm;
 }
 
 void rsi_MeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    rsAssert(slot < sm->mVertexBufferCount);
+    rsAssert(slot < sm->mHal.state.vertexBuffersCount);
 
-    sm->mVertexBuffers[slot].set((Allocation *)va);
+    sm->setVertexBuffer((Allocation *)va, slot);
 }
 
 void rsi_MeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    rsAssert(slot < sm->mPrimitivesCount);
+    rsAssert(slot < sm->mHal.state.primitivesCount);
 
-    sm->mPrimitives[slot]->mIndexBuffer.set((Allocation *)va);
-    sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType;
-    sm->updateGLPrimitives();
+    sm->setPrimitive((Allocation *)va, (RsPrimitive)primType, slot);
 }
 
 void rsi_MeshInitVertexAttribs(Context *rsc, RsMesh mv) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    sm->initVertexAttribs();
+    sm->init();
 }
 
 }}
 
 void rsaMeshGetVertexBufferCount(RsContext con, RsMesh mv, int32_t *numVtx) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    *numVtx = sm->mVertexBufferCount;
+    *numVtx = sm->mHal.state.vertexBuffersCount;
 }
 
 void rsaMeshGetIndexCount(RsContext con, RsMesh mv, int32_t *numIdx) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    *numIdx = sm->mPrimitivesCount;
+    *numIdx = sm->mHal.state.primitivesCount;
 }
 
 void rsaMeshGetVertices(RsContext con, RsMesh mv, RsAllocation *vtxData, uint32_t vtxDataCount) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    rsAssert(vtxDataCount == sm->mVertexBufferCount);
+    rsAssert(vtxDataCount == sm->mHal.state.vertexBuffersCount);
 
     for (uint32_t ct = 0; ct < vtxDataCount; ct ++) {
-        vtxData[ct] = sm->mVertexBuffers[ct].get();
-        sm->mVertexBuffers[ct]->incUserRef();
+        vtxData[ct] = sm->mHal.state.vertexBuffers[ct].get();
+        sm->mHal.state.vertexBuffers[ct]->incUserRef();
     }
 }
 
 void rsaMeshGetIndices(RsContext con, RsMesh mv, RsAllocation *va, uint32_t *primType, uint32_t idxDataCount) {
     Mesh *sm = static_cast<Mesh *>(mv);
-    rsAssert(idxDataCount == sm->mPrimitivesCount);
+    rsAssert(idxDataCount == sm->mHal.state.primitivesCount);
 
     for (uint32_t ct = 0; ct < idxDataCount; ct ++) {
-        va[ct] = sm->mPrimitives[ct]->mIndexBuffer.get();
-        primType[ct] = sm->mPrimitives[ct]->mPrimitive;
-        if (sm->mPrimitives[ct]->mIndexBuffer.get()) {
-            sm->mPrimitives[ct]->mIndexBuffer->incUserRef();
+        va[ct] = sm->mHal.state.primitives[ct]->mIndexBuffer.get();
+        primType[ct] = sm->mHal.state.primitives[ct]->mPrimitive;
+        if (sm->mHal.state.primitives[ct]->mIndexBuffer.get()) {
+            sm->mHal.state.primitives[ct]->mIndexBuffer->incUserRef();
         }
     }
 }
diff --git a/rsMesh.h b/rsMesh.h
index 3e080e2..1e279f4 100644
--- a/rsMesh.h
+++ b/rsMesh.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,57 +29,65 @@
 class Mesh : public ObjectBase {
 public:
     Mesh(Context *);
+    Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
     ~Mesh();
 
-    // Contains vertex data
-    // Position, normal, texcoord, etc could either be strided in one allocation
-    // of provided separetely in multiple ones
-    ObjectBaseRef<Allocation> *mVertexBuffers;
-    uint32_t mVertexBufferCount;
-
     // Either mIndexBuffer, mPrimitiveBuffer or both could have a NULL reference
     // If both are null, mPrimitive only would be used to render the mesh
-    struct Primitive_t
-    {
+    struct Primitive_t {
         ObjectBaseRef<Allocation> mIndexBuffer;
-
         RsPrimitive mPrimitive;
-        uint32_t mGLPrimitive;
     };
 
+    // compatibility to not break the build
+    ObjectBaseRef<Allocation> *mVertexBuffers;
+    uint32_t mVertexBufferCount;
     Primitive_t ** mPrimitives;
     uint32_t mPrimitivesCount;
+    // end compatibility
 
     virtual void serialize(OStream *stream) const;
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
     static Mesh *createFromStream(Context *rsc, IStream *stream);
+    void init();
 
-#ifndef ANDROID_RS_SERIALIZE
+    struct Hal {
+        mutable void *drv;
+
+        struct State {
+            // Contains vertex data
+            // Position, normal, texcoord, etc could either be strided in one allocation
+            // of provided separetely in multiple ones
+            ObjectBaseRef<Allocation> *vertexBuffers;
+            uint32_t vertexBuffersCount;
+
+            Primitive_t ** primitives;
+            uint32_t primitivesCount;
+        };
+        State state;
+    };
+    Hal mHal;
+
+    void setVertexBuffer(Allocation *vb, uint32_t index) {
+        mHal.state.vertexBuffers[index].set(vb);
+    }
+
+    void setPrimitive(Allocation *idx, RsPrimitive prim, uint32_t index) {
+        mHal.state.primitives[index]->mIndexBuffer.set(idx);
+        mHal.state.primitives[index]->mPrimitive = prim;
+    }
+
     void render(Context *) const;
     void renderPrimitive(Context *, uint32_t primIndex) const;
     void renderPrimitiveRange(Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
     void uploadAll(Context *);
-    void updateGLPrimitives();
-
-
 
     // Bounding volumes
     float mBBoxMin[3];
     float mBBoxMax[3];
     void computeBBox();
-
-    void initVertexAttribs();
-
 protected:
-    bool isValidGLComponent(const Element *elem, uint32_t fieldIdx);
-    // Attribues that allow us to map to GL
-    VertexArray::Attrib *mAttribs;
-    // This allows us to figure out which allocation the attribute
-    // belongs to. In the event the allocation is uploaded to GL
-    // buffer, it lets us properly map it
-    uint32_t *mAttribAllocationIndex;
-    uint32_t mAttribCount;
-#endif
+    bool mInitialized;
 };
 
 class MeshContext {
@@ -92,7 +100,7 @@
 
 }
 }
-#endif //ANDROID_RS_TRIANGLE_MESH_H
+#endif //ANDROID_RS_MESH_H
 
 
 
diff --git a/rsProgram.cpp b/rsProgram.cpp
index 4ef05bf..28fa061 100644
--- a/rsProgram.cpp
+++ b/rsProgram.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,11 +15,6 @@
  */
 
 #include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
 #include "rsProgram.h"
 
 using namespace android;
@@ -36,26 +31,22 @@
     initMemberVars();
     for (uint32_t ct=0; ct < paramLength; ct+=2) {
         if (params[ct] == RS_PROGRAM_PARAM_INPUT) {
-            mInputCount++;
-        }
-        if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) {
-            mOutputCount++;
+            mHal.state.inputElementsCount++;
         }
         if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) {
-            mConstantCount++;
+            mHal.state.constantsCount++;
         }
         if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) {
-            mTextureCount++;
+            mHal.state.texturesCount++;
         }
     }
 
-    mTextures = new ObjectBaseRef<Allocation>[mTextureCount];
-    mSamplers = new ObjectBaseRef<Sampler>[mTextureCount];
-    mTextureTargets = new RsTextureTarget[mTextureCount];
-    mInputElements = new ObjectBaseRef<Element>[mInputCount];
-    mOutputElements = new ObjectBaseRef<Element>[mOutputCount];
-    mConstantTypes = new ObjectBaseRef<Type>[mConstantCount];
-    mConstants = new ObjectBaseRef<Allocation>[mConstantCount];
+    mHal.state.textures = new ObjectBaseRef<Allocation>[mHal.state.texturesCount];
+    mHal.state.samplers = new ObjectBaseRef<Sampler>[mHal.state.texturesCount];
+    mHal.state.textureTargets = new RsTextureTarget[mHal.state.texturesCount];
+    mHal.state.inputElements = new ObjectBaseRef<Element>[mHal.state.inputElementsCount];
+    mHal.state.constantTypes = new ObjectBaseRef<Type>[mHal.state.constantsCount];
+    mHal.state.constants = new ObjectBaseRef<Allocation>[mHal.state.constantsCount];
 
     uint32_t input = 0;
     uint32_t output = 0;
@@ -63,16 +54,13 @@
     uint32_t texture = 0;
     for (uint32_t ct=0; ct < paramLength; ct+=2) {
         if (params[ct] == RS_PROGRAM_PARAM_INPUT) {
-            mInputElements[input++].set(reinterpret_cast<Element *>(params[ct+1]));
-        }
-        if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) {
-            mOutputElements[output++].set(reinterpret_cast<Element *>(params[ct+1]));
+            mHal.state.inputElements[input++].set(reinterpret_cast<Element *>(params[ct+1]));
         }
         if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) {
-            mConstantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1]));
+            mHal.state.constantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1]));
         }
         if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) {
-            mTextureTargets[texture++] = (RsTextureTarget)params[ct+1];
+            mHal.state.textureTargets[texture++] = (RsTextureTarget)params[ct+1];
         }
     }
     mIsInternal = false;
@@ -84,88 +72,69 @@
         shaderLength -= internalTokenLen;
     }
     mUserShader.setTo(shaderText, shaderLength);
-
-    initAttribAndUniformArray();
 }
 
 Program::~Program() {
-    if (mRSC->props.mLogShaders) {
-        LOGV("Program::~Program with shader id %u", mShaderID);
-    }
 
-    if (mShaderID) {
-        glDeleteShader(mShaderID);
-    }
-
-    for (uint32_t ct=0; ct < mConstantCount; ct++) {
+    for (uint32_t ct=0; ct < mHal.state.constantsCount; ct++) {
         bindAllocation(NULL, NULL, ct);
     }
 
-    for (uint32_t ct=0; ct < mTextureCount; ct++) {
+    for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) {
         bindTexture(NULL, ct, NULL);
         bindSampler(NULL, ct, NULL);
     }
-    delete[] mTextures;
-    delete[] mSamplers;
-    delete[] mTextureTargets;
-    delete[] mInputElements;
-    delete[] mOutputElements;
-    delete[] mConstantTypes;
-    delete[] mConstants;
-    delete[] mAttribNames;
-    delete[] mUniformNames;
-    delete[] mUniformArraySizes;
-    mInputCount = 0;
-    mOutputCount = 0;
-    mConstantCount = 0;
+    delete[] mHal.state.textures;
+    delete[] mHal.state.samplers;
+    delete[] mHal.state.textureTargets;
+    delete[] mHal.state.inputElements;
+    delete[] mHal.state.constantTypes;
+    delete[] mHal.state.constants;
+    mHal.state.inputElementsCount = 0;
+    mHal.state.constantsCount = 0;
+    mHal.state.texturesCount = 0;
 }
 
 void Program::initMemberVars() {
     mDirty = true;
-    mShaderID = 0;
-    mAttribCount = 0;
-    mUniformCount = 0;
-    mTextureCount = 0;
 
-    mTextures = NULL;
-    mSamplers = NULL;
-    mTextureTargets = NULL;
-    mInputElements = NULL;
-    mOutputElements = NULL;
-    mConstantTypes = NULL;
-    mConstants = NULL;
-    mAttribNames = NULL;
-    mUniformNames = NULL;
-    mUniformArraySizes = NULL;
-    mInputCount = 0;
-    mOutputCount = 0;
-    mConstantCount = 0;
-    mIsValid = false;
+    mHal.drv = NULL;
+    mHal.state.textures = NULL;
+    mHal.state.samplers = NULL;
+    mHal.state.textureTargets = NULL;
+    mHal.state.inputElements = NULL;
+    mHal.state.constantTypes = NULL;
+    mHal.state.constants = NULL;
+
+    mHal.state.inputElementsCount = 0;
+    mHal.state.constantsCount = 0;
+    mHal.state.texturesCount = 0;
+
     mIsInternal = false;
 }
 
 void Program::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) {
     if (alloc != NULL) {
-        if (slot >= mConstantCount) {
+        if (slot >= mHal.state.constantsCount) {
             LOGE("Attempt to bind alloc at slot %u, on shader id %u, but const count is %u",
-                 slot, (uint32_t)this, mConstantCount);
+                 slot, (uint32_t)this, mHal.state.constantsCount);
             rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation");
             return;
         }
-        if (!alloc->getType()->isEqual(mConstantTypes[slot].get())) {
+        if (!alloc->getType()->isEqual(mHal.state.constantTypes[slot].get())) {
             LOGE("Attempt to bind alloc at slot %u, on shader id %u, but types mismatch",
                  slot, (uint32_t)this);
             rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation");
             return;
         }
     }
-    if (mConstants[slot].get() == alloc) {
+    if (mHal.state.constants[slot].get() == alloc) {
         return;
     }
-    if (mConstants[slot].get()) {
-        mConstants[slot].get()->removeProgramToDirty(this);
+    if (mHal.state.constants[slot].get()) {
+        mHal.state.constants[slot].get()->removeProgramToDirty(this);
     }
-    mConstants[slot].set(alloc);
+    mHal.state.constants[slot].set(alloc);
     if (alloc) {
         alloc->addProgramToDirty(this);
     }
@@ -173,327 +142,38 @@
 }
 
 void Program::bindTexture(Context *rsc, uint32_t slot, Allocation *a) {
-    if (slot >= mTextureCount) {
-        LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mTextureCount);
+    if (slot >= mHal.state.texturesCount) {
+        LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mHal.state.texturesCount);
         rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind texture");
         return;
     }
 
-    if (a && a->getType()->getDimFaces() && mTextureTargets[slot] != RS_TEXTURE_CUBE) {
+    if (a && a->getType()->getDimFaces() && mHal.state.textureTargets[slot] != RS_TEXTURE_CUBE) {
         LOGE("Attempt to bind cubemap to slot %u but 2d texture needed", slot);
         rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind cubemap to 2d texture slot");
         return;
     }
 
     //LOGE("bindtex %i %p", slot, a);
-    mTextures[slot].set(a);
+    mHal.state.textures[slot].set(a);
     mDirty = true;
 }
 
 void Program::bindSampler(Context *rsc, uint32_t slot, Sampler *s) {
-    if (slot >= mTextureCount) {
-        LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mTextureCount);
+    if (slot >= mHal.state.texturesCount) {
+        LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mHal.state.texturesCount);
         rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind sampler");
         return;
     }
 
-    mSamplers[slot].set(s);
+    mHal.state.samplers[slot].set(s);
     mDirty = true;
 }
 
-String8 Program::getGLSLInputString() const {
-    String8 s;
-    for (uint32_t ct=0; ct < mInputCount; ct++) {
-        const Element *e = mInputElements[ct].get();
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-
-            // Cannot be complex
-            rsAssert(!f->getFieldCount());
-            switch (f->getComponent().getVectorSize()) {
-            case 1: s.append("attribute float ATTRIB_"); break;
-            case 2: s.append("attribute vec2 ATTRIB_"); break;
-            case 3: s.append("attribute vec3 ATTRIB_"); break;
-            case 4: s.append("attribute vec4 ATTRIB_"); break;
-            default:
-                rsAssert(0);
-            }
-
-            s.append(e->getFieldName(field));
-            s.append(";\n");
-        }
-    }
-    return s;
-}
-
-String8 Program::getGLSLOutputString() const {
-    return String8();
-}
-
-String8 Program::getGLSLConstantString() const {
-    return String8();
-}
-
-void Program::createShader() {
-}
-
-bool Program::loadShader(Context *rsc, uint32_t type) {
-    mShaderID = glCreateShader(type);
-    rsAssert(mShaderID);
-
-    if (rsc->props.mLogShaders) {
-        LOGV("Loading shader type %x, ID %i", type, mShaderID);
-        LOGV("%s", 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;
-                rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
-                return false;
-            }
-        }
-    }
-
-    if (rsc->props.mLogShaders) {
-        LOGV("--Shader load result %x ", glGetError());
-    }
-    mIsValid = true;
-    return true;
-}
-
 void Program::setShader(const char *txt, uint32_t len) {
     mUserShader.setTo(txt, len);
 }
 
-void Program::appendUserConstants() {
-    for (uint32_t ct=0; ct < mConstantCount; ct++) {
-        const Element *e = mConstantTypes[ct]->getElement();
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-            const char *fn = e->getFieldName(field);
-
-            if (fn[0] == '#') {
-                continue;
-            }
-
-            // Cannot be complex
-            rsAssert(!f->getFieldCount());
-            if (f->getType() == RS_TYPE_MATRIX_4X4) {
-                mShader.append("uniform mat4 UNI_");
-            } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
-                mShader.append("uniform mat3 UNI_");
-            } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
-                mShader.append("uniform mat2 UNI_");
-            } else {
-                switch (f->getComponent().getVectorSize()) {
-                case 1: mShader.append("uniform float UNI_"); break;
-                case 2: mShader.append("uniform vec2 UNI_"); break;
-                case 3: mShader.append("uniform vec3 UNI_"); break;
-                case 4: mShader.append("uniform vec4 UNI_"); break;
-                default:
-                    rsAssert(0);
-                }
-            }
-
-            mShader.append(fn);
-            if (e->getFieldArraySize(field) > 1) {
-                mShader.appendFormat("[%d]", e->getFieldArraySize(field));
-            }
-            mShader.append(";\n");
-        }
-    }
-}
-
-void Program::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
-    RsDataType dataType = field->getType();
-    uint32_t elementSize = field->getSizeBytes() / sizeof(float);
-    for (uint32_t i = 0; i < arraySize; i ++) {
-        if (arraySize > 1) {
-            LOGV("Array Element [%u]", i);
-        }
-        if (dataType == RS_TYPE_MATRIX_4X4) {
-            LOGV("Matrix4x4");
-            LOGV("{%f, %f, %f, %f",  fd[0], fd[4], fd[8], fd[12]);
-            LOGV(" %f, %f, %f, %f",  fd[1], fd[5], fd[9], fd[13]);
-            LOGV(" %f, %f, %f, %f",  fd[2], fd[6], fd[10], fd[14]);
-            LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]);
-        } else if (dataType == RS_TYPE_MATRIX_3X3) {
-            LOGV("Matrix3x3");
-            LOGV("{%f, %f, %f",  fd[0], fd[3], fd[6]);
-            LOGV(" %f, %f, %f",  fd[1], fd[4], fd[7]);
-            LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]);
-        } else if (dataType == RS_TYPE_MATRIX_2X2) {
-            LOGV("Matrix2x2");
-            LOGV("{%f, %f",  fd[0], fd[2]);
-            LOGV(" %f, %f}", fd[1], fd[3]);
-        } else {
-            switch (field->getComponent().getVectorSize()) {
-            case 1:
-                LOGV("Uniform 1 = %f", fd[0]);
-                break;
-            case 2:
-                LOGV("Uniform 2 = %f %f", fd[0], fd[1]);
-                break;
-            case 3:
-                LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
-                break;
-            case 4:
-                LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
-                break;
-            default:
-                rsAssert(0);
-            }
-        }
-        LOGE("Element size %u data=%p", elementSize, fd);
-        fd += elementSize;
-        LOGE("New data=%p", fd);
-    }
-}
-
-void Program::setUniform(Context *rsc, const Element *field, const float *fd,
-                         int32_t slot, uint32_t arraySize ) {
-    RsDataType dataType = field->getType();
-    if (dataType == RS_TYPE_MATRIX_4X4) {
-        glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
-    } else if (dataType == RS_TYPE_MATRIX_3X3) {
-        glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
-    } else if (dataType == RS_TYPE_MATRIX_2X2) {
-        glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
-    } else {
-        switch (field->getComponent().getVectorSize()) {
-        case 1:
-            glUniform1fv(slot, arraySize, fd);
-            break;
-        case 2:
-            glUniform2fv(slot, arraySize, fd);
-            break;
-        case 3:
-            glUniform3fv(slot, arraySize, fd);
-            break;
-        case 4:
-            glUniform4fv(slot, arraySize, fd);
-            break;
-        default:
-            rsAssert(0);
-        }
-    }
-}
-
-void Program::setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment) {
-    uint32_t uidx = 0;
-    for (uint32_t ct=0; ct < mConstantCount; ct++) {
-        Allocation *alloc = mConstants[ct].get();
-        if (!alloc) {
-            LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
-            rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
-            continue;
-        }
-
-        const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
-        const Element *e = mConstantTypes[ct]->getElement();
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-            const char *fieldName = e->getFieldName(field);
-            // If this field is padding, skip it
-            if (fieldName[0] == '#') {
-                continue;
-            }
-
-            uint32_t offset = e->getFieldOffsetBytes(field);
-            const float *fd = reinterpret_cast<const float *>(&data[offset]);
-
-            int32_t slot = -1;
-            uint32_t arraySize = 1;
-            if (!isFragment) {
-                slot = sc->vtxUniformSlot(uidx);
-                arraySize = sc->vtxUniformSize(uidx);
-            } else {
-                slot = sc->fragUniformSlot(uidx);
-                arraySize = sc->fragUniformSize(uidx);
-            }
-            if (rsc->props.mLogShadersUniforms) {
-                LOGV("Uniform  slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
-            }
-            uidx ++;
-            if (slot < 0) {
-                continue;
-            }
-
-            if (rsc->props.mLogShadersUniforms) {
-                logUniform(f, fd, arraySize);
-            }
-            setUniform(rsc, f, fd, slot, arraySize);
-        }
-    }
-}
-
-void Program::initAttribAndUniformArray() {
-    mAttribCount = 0;
-    for (uint32_t ct=0; ct < mInputCount; ct++) {
-        const Element *elem = mInputElements[ct].get();
-        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
-            if (elem->getFieldName(field)[0] != '#') {
-                mAttribCount ++;
-            }
-        }
-    }
-
-    mUniformCount = 0;
-    for (uint32_t ct=0; ct < mConstantCount; ct++) {
-        const Element *elem = mConstantTypes[ct]->getElement();
-
-        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
-            if (elem->getFieldName(field)[0] != '#') {
-                mUniformCount ++;
-            }
-        }
-    }
-    mUniformCount += mTextureCount;
-
-    if (mAttribCount) {
-        mAttribNames = new String8[mAttribCount];
-    }
-    if (mUniformCount) {
-        mUniformNames = new String8[mUniformCount];
-        mUniformArraySizes = new uint32_t[mUniformCount];
-    }
-}
-
-void Program::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
-    rsAssert(e->getFieldCount());
-    for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
-        const Element *ce = e->getField(ct);
-        if (ce->getFieldCount()) {
-            initAddUserElement(ce, names, arrayLengths, count, prefix);
-        } else if (e->getFieldName(ct)[0] != '#') {
-            String8 tmp(prefix);
-            tmp.append(e->getFieldName(ct));
-            names[*count].setTo(tmp.string());
-            if (arrayLengths) {
-                arrayLengths[*count] = e->getFieldArraySize(ct);
-            }
-            (*count)++;
-        }
-    }
-}
-
 namespace android {
 namespace renderscript {
 
diff --git a/rsProgram.h b/rsProgram.h
index c48464d..bcf5519 100644
--- a/rsProgram.h
+++ b/rsProgram.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@
 // ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
-class ShaderCache;
 
 #define RS_SHADER_INTERNAL "//rs_shader_internal\n"
 #define RS_SHADER_ATTR "ATTRIB_"
@@ -38,75 +37,53 @@
     virtual ~Program();
 
     void bindAllocation(Context *, Allocation *, uint32_t slot);
-    virtual void createShader();
 
     bool isUserProgram() const {return !mIsInternal;}
 
     void bindTexture(Context *, uint32_t slot, Allocation *);
     void bindSampler(Context *, uint32_t slot, Sampler *);
 
-    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];}
-    uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];}
-
-    String8 getGLSLInputString() const;
-    String8 getGLSLOutputString() const;
-    String8 getGLSLConstantString() const;
-
-    bool isValid() const {return mIsValid;}
     void forceDirty() const {mDirty = true;}
 
+    struct Hal {
+        mutable void *drv;
+
+        struct State {
+            // The difference between Textures and Constants is how they are accessed
+            // Texture lookups go though a sampler which in effect converts normalized
+            // coordinates into type specific.  Multiple samples may also be taken
+            // and filtered.
+            //
+            // Constants are strictly accessed by the shader code
+            ObjectBaseRef<Allocation> *textures;
+            RsTextureTarget *textureTargets;
+            uint32_t texturesCount;
+
+            ObjectBaseRef<Sampler> *samplers;
+            uint32_t samplersCount;
+
+            ObjectBaseRef<Allocation> *constants;
+            ObjectBaseRef<Type> *constantTypes;
+            uint32_t constantsCount;
+
+            ObjectBaseRef<Element> *inputElements;
+            uint32_t inputElementsCount;
+        };
+        State state;
+    };
+    Hal mHal;
+
 protected:
-    // Components not listed in "in" will be passed though
-    // unless overwritten by components in out.
-    ObjectBaseRef<Element> *mInputElements;
-    ObjectBaseRef<Element> *mOutputElements;
-    ObjectBaseRef<Type> *mConstantTypes;
-    ObjectBaseRef<Allocation> *mConstants;
-    uint32_t mInputCount;
-    uint32_t mOutputCount;
-    uint32_t mConstantCount;
-    bool mIsValid;
     bool mIsInternal;
 
-    // Applies to vertex and fragment shaders only
-    void appendUserConstants();
-    void setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment);
-    void initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix);
-
-    void initAttribAndUniformArray();
-
     mutable bool mDirty;
-    String8 mShader;
     String8 mUserShader;
-    uint32_t mShaderID;
-
-    uint32_t mTextureCount;
-    uint32_t mAttribCount;
-    uint32_t mUniformCount;
-    String8 *mAttribNames;
-    String8 *mUniformNames;
-    uint32_t *mUniformArraySizes;
 
     void logUniform(const Element *field, const float *fd, uint32_t arraySize );
     void setUniform(Context *rsc, const Element *field, const float *fd, int32_t slot, uint32_t arraySize );
     void initMemberVars();
-
-    // The difference between Textures and Constants is how they are accessed
-    // Texture lookups go though a sampler which in effect converts normalized
-    // coordinates into type specific.  Multiple samples may also be taken
-    // and filtered.
-    //
-    // Constants are strictly accessed by programetic loads.
-    ObjectBaseRef<Allocation> *mTextures;
-    ObjectBaseRef<Sampler> *mSamplers;
-    RsTextureTarget *mTextureTargets;
-    bool loadShader(Context *, uint32_t type);
 };
 
 }
diff --git a/rsProgramFragment.cpp b/rsProgramFragment.cpp
index ff314b7..39887ca 100644
--- a/rsProgramFragment.cpp
+++ b/rsProgramFragment.cpp
@@ -15,13 +15,6 @@
  */
 
 #include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
 #include "rsProgramFragment.h"
 
 using namespace android;
@@ -31,19 +24,16 @@
                                  uint32_t shaderLength, const uint32_t * params,
                                  uint32_t paramLength)
     : Program(rsc, shaderText, shaderLength, params, paramLength) {
-
     mConstantColor[0] = 1.f;
     mConstantColor[1] = 1.f;
     mConstantColor[2] = 1.f;
     mConstantColor[3] = 1.f;
 
-    init(rsc);
+    mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length());
 }
 
 ProgramFragment::~ProgramFragment() {
-    if (mShaderID) {
-        mRSC->mShaderCache.cleanupFragment(mShaderID);
-    }
+    mRSC->mHal.funcs.fragment.destroy(mRSC, this);
 }
 
 void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, float a) {
@@ -52,7 +42,7 @@
         rsc->setError(RS_ERROR_BAD_SHADER, "Cannot  set fixed function emulation color on user program");
         return;
     }
-    if (mConstants[0].get() == NULL) {
+    if (mHal.state.constants[0].get() == NULL) {
         LOGE("Unable to set fixed function emulation color because allocation is missing");
         rsc->setError(RS_ERROR_BAD_SHADER, "Unable to set fixed function emulation color because allocation is missing");
         return;
@@ -61,11 +51,11 @@
     mConstantColor[1] = g;
     mConstantColor[2] = b;
     mConstantColor[3] = a;
-    memcpy(mConstants[0]->getPtr(), mConstantColor, 4*sizeof(float));
+    memcpy(mHal.state.constants[0]->getPtr(), mConstantColor, 4*sizeof(float));
     mDirty = true;
 }
 
-void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, ShaderCache *sc) {
+void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state) {
     //LOGE("sgl2 frag1 %x", glGetError());
     if ((state->mLast.get() == this) && !mDirty) {
         return;
@@ -74,94 +64,16 @@
 
     rsc->checkError("ProgramFragment::setupGL2 start");
 
-    rsc->checkError("ProgramFragment::setupGL2 begin uniforms");
-    setupUserConstants(rsc, sc, true);
-
-    uint32_t numTexturesToBind = mTextureCount;
-    uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures();
-    if (numTexturesToBind >= numTexturesAvailable) {
-        LOGE("Attempting to bind %u textures on shader id %u, but only %u are available",
-             mTextureCount, (uint32_t)this, numTexturesAvailable);
-        rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available");
-        numTexturesToBind = numTexturesAvailable;
-    }
-
-    for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
-        glActiveTexture(GL_TEXTURE0 + ct);
-        if (!mTextures[ct].get()) {
+    for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) {
+        if (!mHal.state.textures[ct].get()) {
             LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct);
             rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound");
             continue;
         }
-
-        mTextures[ct]->uploadCheck(rsc);
-        GLenum target = (GLenum)mTextures[ct]->getGLTarget();
-        if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
-            LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
-            rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
-        }
-        glBindTexture(target, mTextures[ct]->getTextureID());
-        rsc->checkError("ProgramFragment::setupGL2 tex bind");
-        if (mSamplers[ct].get()) {
-            mSamplers[ct]->setupGL(rsc, mTextures[ct].get());
-        } else {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-            glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-            glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-            glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-            rsc->checkError("ProgramFragment::setupGL2 tex env");
-        }
-
-        glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
-        rsc->checkError("ProgramFragment::setupGL2 uniforms");
+        mHal.state.textures[ct]->uploadCheck(rsc);
     }
 
-    glActiveTexture(GL_TEXTURE0);
-    mDirty = false;
-    rsc->checkError("ProgramFragment::setupGL2");
-}
-
-void ProgramFragment::loadShader(Context *rsc) {
-    Program::loadShader(rsc, GL_FRAGMENT_SHADER);
-}
-
-void ProgramFragment::createShader() {
-    if (mUserShader.length() > 1) {
-        mShader.append("precision mediump float;\n");
-        appendUserConstants();
-        char buf[256];
-        for (uint32_t ct=0; ct < mTextureCount; ct++) {
-            if (mTextureTargets[ct] == RS_TEXTURE_2D) {
-                snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
-            } else {
-                snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
-            }
-            mShader.append(buf);
-        }
-        mShader.append(mUserShader);
-    } else {
-        LOGE("ProgramFragment::createShader cannot create program, shader code not defined");
-        rsAssert(0);
-    }
-}
-
-void ProgramFragment::init(Context *rsc) {
-    uint32_t uniformIndex = 0;
-    if (mUserShader.size() > 0) {
-        for (uint32_t ct=0; ct < mConstantCount; ct++) {
-            initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformIndex, RS_SHADER_UNI);
-        }
-    }
-    mTextureUniformIndexStart = uniformIndex;
-    char buf[256];
-    for (uint32_t ct=0; ct < mTextureCount; ct++) {
-        snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
-        mUniformNames[uniformIndex].setTo(buf);
-        mUniformArraySizes[uniformIndex] = 1;
-        uniformIndex++;
-    }
-
-    createShader();
+    rsc->mHal.funcs.fragment.setActive(rsc, this);
 }
 
 void ProgramFragment::serialize(OStream *stream) const {
diff --git a/rsProgramFragment.h b/rsProgramFragment.h
index 3d28946..7520af0 100644
--- a/rsProgramFragment.h
+++ b/rsProgramFragment.h
@@ -32,11 +32,8 @@
                              uint32_t paramLength);
     virtual ~ProgramFragment();
 
-    virtual void setupGL2(Context *, ProgramFragmentState *, ShaderCache *sc);
+    virtual void setupGL2(Context *, ProgramFragmentState *);
 
-    virtual void createShader();
-    virtual void loadShader(Context *rsc);
-    virtual void init(Context *rsc);
     virtual void serialize(OStream *stream) const;
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_FRAGMENT; }
     static ProgramFragment *createFromStream(Context *rsc, IStream *stream);
diff --git a/rsProgramStore.h b/rsProgramStore.h
index bfe276d..88a06a8 100644
--- a/rsProgramStore.h
+++ b/rsProgramStore.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -62,8 +62,6 @@
             RsDepthFunc depthFunc;
         };
         State state;
-
-
     };
     Hal mHal;
 
diff --git a/rsProgramVertex.cpp b/rsProgramVertex.cpp
index e407d3a..dfd732f 100644
--- a/rsProgramVertex.cpp
+++ b/rsProgramVertex.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,13 +15,6 @@
  */
 
 #include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
 #include "rsProgramVertex.h"
 
 using namespace android;
@@ -32,57 +25,14 @@
                              uint32_t shaderLength, const uint32_t * params,
                              uint32_t paramLength)
     : Program(rsc, shaderText, shaderLength, params, paramLength) {
-    init(rsc);
+    mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length());
 }
 
 ProgramVertex::~ProgramVertex() {
-    if (mShaderID) {
-        mRSC->mShaderCache.cleanupVertex(mShaderID);
-    }
+    mRSC->mHal.funcs.vertex.destroy(mRSC, this);
 }
 
-void ProgramVertex::loadShader(Context *rsc) {
-    Program::loadShader(rsc, GL_VERTEX_SHADER);
-}
-
-void ProgramVertex::createShader(Context *rsc) {
-    if (mUserShader.length() > 1) {
-
-        appendUserConstants();
-
-        for (uint32_t ct=0; ct < mInputCount; ct++) {
-            const Element *e = mInputElements[ct].get();
-            for (uint32_t field=0; field < e->getFieldCount(); field++) {
-                const Element *f = e->getField(field);
-                const char *fn = e->getFieldName(field);
-
-                if (fn[0] == '#') {
-                    continue;
-                }
-
-                // Cannot be complex
-                rsAssert(!f->getFieldCount());
-                switch (f->getComponent().getVectorSize()) {
-                case 1: mShader.append("attribute float ATTRIB_"); break;
-                case 2: mShader.append("attribute vec2 ATTRIB_"); break;
-                case 3: mShader.append("attribute vec3 ATTRIB_"); break;
-                case 4: mShader.append("attribute vec4 ATTRIB_"); break;
-                default:
-                    rsAssert(0);
-                }
-
-                mShader.append(fn);
-                mShader.append(";\n");
-            }
-        }
-        mShader.append(mUserShader);
-    } else {
-        rsc->setError(RS_ERROR_FATAL_UNKNOWN,
-                      "ProgramFragment::createShader cannot create program, shader code not defined");
-    }
-}
-
-void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc) {
+void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state) {
     if ((state->mLast.get() == this) && !mDirty) {
         return;
     }
@@ -90,12 +40,12 @@
     rsc->checkError("ProgramVertex::setupGL2 start");
 
     if (!isUserProgram()) {
-        if (mConstants[0].get() == NULL) {
+        if (mHal.state.constants[0].get() == NULL) {
             rsc->setError(RS_ERROR_FATAL_UNKNOWN,
                           "Unable to set fixed function emulation matrices because allocation is missing");
             return;
         }
-        float *f = static_cast<float *>(mConstants[0]->getPtr());
+        float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
         Matrix4x4 mvp;
         mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
         Matrix4x4 t;
@@ -106,10 +56,10 @@
         }
     }
 
-    rsc->checkError("ProgramVertex::setupGL2 begin uniforms");
-    setupUserConstants(rsc, sc, false);
-
     state->mLast.set(this);
+
+    rsc->mHal.funcs.vertex.setActive(rsc, this);
+
     rsc->checkError("ProgramVertex::setupGL2");
 }
 
@@ -119,12 +69,12 @@
                       "Attempting to set fixed function emulation matrix projection on user program");
         return;
     }
-    if (mConstants[0].get() == NULL) {
+    if (mHal.state.constants[0].get() == NULL) {
         rsc->setError(RS_ERROR_FATAL_UNKNOWN,
                       "Unable to set fixed function emulation matrix projection because allocation is missing");
         return;
     }
-    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
     memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
     mDirty = true;
 }
@@ -135,12 +85,12 @@
                       "Attempting to set fixed function emulation matrix modelview on user program");
         return;
     }
-    if (mConstants[0].get() == NULL) {
+    if (mHal.state.constants[0].get() == NULL) {
         rsc->setError(RS_ERROR_FATAL_UNKNOWN,
                       "Unable to set fixed function emulation matrix modelview because allocation is missing");
         return;
     }
-    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
     memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
     mDirty = true;
 }
@@ -151,12 +101,12 @@
                       "Attempting to set fixed function emulation matrix texture on user program");
         return;
     }
-    if (mConstants[0].get() == NULL) {
+    if (mHal.state.constants[0].get() == NULL) {
         rsc->setError(RS_ERROR_FATAL_UNKNOWN,
                       "Unable to set fixed function emulation matrix texture because allocation is missing");
         return;
     }
-    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
     memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
     mDirty = true;
 }
@@ -167,12 +117,12 @@
                       "Attempting to get fixed function emulation matrix projection on user program");
         return;
     }
-    if (mConstants[0].get() == NULL) {
+    if (mHal.state.constants[0].get() == NULL) {
         rsc->setError(RS_ERROR_FATAL_UNKNOWN,
                       "Unable to get fixed function emulation matrix projection because allocation is missing");
         return;
     }
-    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
     memcpy(m, &f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], sizeof(rsc_Matrix));
 }
 
@@ -180,27 +130,13 @@
     if (isUserProgram()) {
         return;
     }
-    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
     Matrix4x4 mvp;
     mvp.loadMultiply((Matrix4x4 *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET],
                      (Matrix4x4 *)&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
     mvp.vectorMultiply(v4out, v3in);
 }
 
-void ProgramVertex::init(Context *rsc) {
-    uint32_t attribCount = 0;
-    uint32_t uniformCount = 0;
-    if (mUserShader.size() > 0) {
-        for (uint32_t ct=0; ct < mInputCount; ct++) {
-            initAddUserElement(mInputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
-        }
-        for (uint32_t ct=0; ct < mConstantCount; ct++) {
-            initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
-        }
-    }
-    createShader(rsc);
-}
-
 void ProgramVertex::serialize(OStream *stream) const {
 }
 
diff --git a/rsProgramVertex.h b/rsProgramVertex.h
index 2a5c863..04224a7 100644
--- a/rsProgramVertex.h
+++ b/rsProgramVertex.h
@@ -31,7 +31,7 @@
                   const uint32_t * params, uint32_t paramLength);
     virtual ~ProgramVertex();
 
-    virtual void setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc);
+    virtual void setupGL2(Context *rsc, ProgramVertexState *state);
 
     void setProjectionMatrix(Context *, const rsc_Matrix *) const;
     void getProjectionMatrix(Context *, rsc_Matrix *) const;
@@ -40,10 +40,6 @@
 
     void transformToScreen(Context *, float *v4out, const float *v3in) const;
 
-    virtual void createShader(Context *);
-    virtual void loadShader(Context *);
-    virtual void init(Context *);
-
     virtual void serialize(OStream *stream) const;
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_VERTEX; }
     static ProgramVertex *createFromStream(Context *rsc, IStream *stream);
diff --git a/rsScriptC_LibGL.cpp b/rsScriptC_LibGL.cpp
index 71f1312..ecda485 100644
--- a/rsScriptC_LibGL.cpp
+++ b/rsScriptC_LibGL.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,9 @@
 #include "rsMatrix2x2.h"
 
 #include "utils/Timers.h"
+#include "driver/rsdVertexArray.h"
+#include "driver/rsdShaderCache.h"
+#include "driver/rsdCore.h"
 
 #define GL_GLEXT_PROTOTYPES
 
@@ -134,6 +137,11 @@
         return;
     }
 
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+    if (!dc->gl.shaderCache->setup(rsc)) {
+        return;
+    }
+
     //LOGE("Quad");
     //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
     //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2);
@@ -143,12 +151,12 @@
     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};
 
-    VertexArray::Attrib attribs[2];
+    RsdVertexArray::Attrib attribs[2];
     attribs[0].set(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position");
     attribs[1].set(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0");
 
-    VertexArray va(attribs, 2);
-    va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
+    RsdVertexArray va(attribs, 2);
+    va.setupGL2(rsc);
 
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 }
diff --git a/rsType.h b/rsType.h
index 90ae039..086db33 100644
--- a/rsType.h
+++ b/rsType.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
 #define ANDROID_STRUCTURED_TYPE_H
 
 #include "rsElement.h"
-#include "rsVertexArray.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
diff --git a/rs_hal.h b/rs_hal.h
index 4283d4a..d2f273b 100644
--- a/rs_hal.h
+++ b/rs_hal.h
@@ -32,6 +32,9 @@
 class ScriptC;
 class ProgramStore;
 class ProgramRaster;
+class ProgramVertex;
+class ProgramFragment;
+class Mesh;
 
 typedef void *(*RsHalSymbolLookupFunc)(void *usrptr, char const *symbolName);
 
@@ -98,6 +101,25 @@
         void (*destroy)(const Context *rsc, const ProgramRaster *ps);
     } raster;
 
+    struct {
+        bool (*init)(const Context *rsc, const ProgramVertex *pv,
+                     const char* shader, uint32_t shaderLen);
+        void (*setActive)(const Context *rsc, const ProgramVertex *pv);
+        void (*destroy)(const Context *rsc, const ProgramVertex *pv);
+    } vertex;
+
+    struct {
+        bool (*init)(const Context *rsc, const ProgramFragment *pf,
+                     const char* shader, uint32_t shaderLen);
+        void (*setActive)(const Context *rsc, const ProgramFragment *pf);
+        void (*destroy)(const Context *rsc, const ProgramFragment *pf);
+    } fragment;
+
+    struct {
+        bool (*init)(const Context *rsc, const Mesh *m);
+        void (*draw)(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len);
+        void (*destroy)(const Context *rsc, const Mesh *m);
+    } mesh;
 
 } RsdHalFunctions;