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

Change-Id: I2a53acb4cd1fa8f4c6e67668f6ee969f3d7f7aa1
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 5b80439..d5d23c7 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/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/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 26e1bdf..48690d5 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/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/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 246931f..351b2d5 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/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/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp
new file mode 100644
index 0000000..eb62ddb
--- /dev/null
+++ b/libs/rs/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/libs/rs/driver/rsdMesh.h b/libs/rs/driver/rsdMesh.h
new file mode 100644
index 0000000..d2714fd
--- /dev/null
+++ b/libs/rs/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/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
new file mode 100644
index 0000000..6bb33f7
--- /dev/null
+++ b/libs/rs/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/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h
new file mode 100644
index 0000000..8b1271b
--- /dev/null
+++ b/libs/rs/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/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp
new file mode 100644
index 0000000..502c5ee
--- /dev/null
+++ b/libs/rs/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/libs/rs/driver/rsdProgramFragment.h b/libs/rs/driver/rsdProgramFragment.h
new file mode 100644
index 0000000..366cb40
--- /dev/null
+++ b/libs/rs/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/libs/rs/driver/rsdProgramVertex.h b/libs/rs/driver/rsdProgramVertex.h
new file mode 100644
index 0000000..e998572
--- /dev/null
+++ b/libs/rs/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/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp
index 093e311..acb990d 100644
--- a/libs/rs/driver/rsdRuntimeMath.cpp
+++ b/libs/rs/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/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp
index b70a123..9cbff95 100644
--- a/libs/rs/driver/rsdRuntimeStubs.cpp
+++ b/libs/rs/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/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
new file mode 100644
index 0000000..fc623d6
--- /dev/null
+++ b/libs/rs/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/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h
new file mode 100644
index 0000000..37b1c3d
--- /dev/null
+++ b/libs/rs/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/libs/rs/driver/rsdShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp
new file mode 100644
index 0000000..18a8225
--- /dev/null
+++ b/libs/rs/driver/rsdShaderCache.cpp
@@ -0,0 +1,282 @@
+/*
+ * 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 "rsdShader.h"
+#include "rsdShaderCache.h"
+
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+RsdShaderCache::RsdShaderCache() {
+    mEntries.setCapacity(16);
+    mVertexDirty = true;
+    mFragmentDirty = true;
+}
+
+RsdShaderCache::~RsdShaderCache() {
+    cleanupAll();
+}
+
+void RsdShaderCache::updateUniformArrayData(const Context *rsc, RsdShader *prog, uint32_t linkedID,
+                                         UniformData *data, const char* logTag,
+                                         UniformQueryData **uniformList, uint32_t uniListSize) {
+
+    for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) {
+        if (data[ct].slot >= 0 && data[ct].arraySize > 1) {
+            //Iterate over the list of active GL uniforms and find highest array index
+            for (uint32_t ui = 0; ui < uniListSize; ui ++) {
+                if (prog->getUniformName(ct) == uniformList[ui]->name) {
+                    data[ct].arraySize = (uint32_t)uniformList[ui]->arraySize;
+                    break;
+                }
+            }
+        }
+
+        if (rsc->props.mLogShaders) {
+             LOGV("%s U, %s = %d, arraySize = %d\n", logTag,
+                  prog->getUniformName(ct).string(), data[ct].slot, data[ct].arraySize);
+        }
+    }
+}
+
+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 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) {
+            return true;
+        }
+    }
+    data = mCurrent->fragUniforms;
+    for (uint32_t ct=0; ct < frag->getUniformCount(); ct++) {
+        if (data[ct].slot >= 0 && data[ct].arraySize > 1) {
+            return true;
+        }
+    }
+    return false;
+}
+
+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);
+    }
+    if (!frag->getShaderID()) {
+        frag->loadShader(rsc);
+    }
+
+    // Don't try to cache if shaders failed to load
+    if (!vtx->getShaderID() || !frag->getShaderID()) {
+        return false;
+    }
+    //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()) &&
+            (mEntries[ct]->frag == frag->getShaderID())) {
+
+            //LOGV("SC using program %i", mEntries[ct]->program);
+            glUseProgram(mEntries[ct]->program);
+            mCurrent = mEntries[ct];
+            //LOGV("RsdShaderCache hit, using %i", ct);
+            rsc->checkError("RsdShaderCache::link (hit)");
+            return true;
+        }
+    }
+
+    //LOGV("RsdShaderCache miss");
+    //LOGE("e0 %x", glGetError());
+    ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(),
+                                       vtx->getUniformCount(),
+                                       frag->getUniformCount());
+    mEntries.push(e);
+    mCurrent = e;
+    e->vtx = vtx->getShaderID();
+    e->frag = frag->getShaderID();
+    e->program = glCreateProgram();
+    if (e->program) {
+        GLuint pgm = e->program;
+        glAttachShader(pgm, vtx->getShaderID());
+        //LOGE("e1 %x", glGetError());
+        glAttachShader(pgm, frag->getShaderID());
+
+        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);
+        //LOGE("e3 %x", glGetError());
+        GLint linkStatus = GL_FALSE;
+        glGetProgramiv(pgm, GL_LINK_STATUS, &linkStatus);
+        if (linkStatus != GL_TRUE) {
+            GLint bufLength = 0;
+            glGetProgramiv(pgm, GL_INFO_LOG_LENGTH, &bufLength);
+            if (bufLength) {
+                char* buf = (char*) malloc(bufLength);
+                if (buf) {
+                    glGetProgramInfoLog(pgm, bufLength, NULL, buf);
+                    LOGE("Could not link program:\n%s\n", buf);
+                    free(buf);
+                }
+            }
+            glDeleteProgram(pgm);
+            rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, "Error linking GL Programs");
+            return false;
+        }
+
+        for (uint32_t ct=0; ct < e->vtxAttrCount; ct++) {
+            e->vtxAttrs[ct].slot = glGetAttribLocation(pgm, vtx->getAttribName(ct));
+            e->vtxAttrs[ct].name = vtx->getAttribName(ct).string();
+            if (rsc->props.mLogShaders) {
+                LOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->vtxAttrs[ct].slot);
+            }
+        }
+
+        populateUniformData(vtx, pgm, e->vtxUniforms);
+        populateUniformData(frag, pgm, e->fragUniforms);
+
+        // Only populate this list if we have arrays in our uniforms
+        UniformQueryData **uniformList = NULL;
+        GLint numUniforms = 0;
+        bool hasArrays = hasArrayUniforms(vtx, frag);
+        if (hasArrays) {
+            // Get the number of active uniforms and the length of the longest name
+            glGetProgramiv(pgm, GL_ACTIVE_UNIFORMS, &numUniforms);
+            GLint maxNameLength = 0;
+            glGetProgramiv(pgm, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
+            if (numUniforms > 0 && maxNameLength > 0) {
+                uniformList = new UniformQueryData*[numUniforms];
+                // Iterate over all the uniforms and build the list we
+                // can later use to match our uniforms to
+                for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) {
+                    uniformList[ct] = new UniformQueryData(maxNameLength);
+                    glGetActiveUniform(pgm, ct, maxNameLength, &uniformList[ct]->writtenLength,
+                                       &uniformList[ct]->arraySize, &uniformList[ct]->type,
+                                       uniformList[ct]->name);
+                    //LOGE("GL UNI idx=%u, arraySize=%u, name=%s", ct,
+                    //     uniformList[ct]->arraySize, uniformList[ct]->name);
+                }
+            }
+        }
+
+        // We now know the highest index of all of the array uniforms
+        // and we need to update our cache to reflect that
+        // we may have declared [n], but only m < n elements are used
+        updateUniformArrayData(rsc, vtx, pgm, e->vtxUniforms, "vtx",
+                               uniformList, (uint32_t)numUniforms);
+        updateUniformArrayData(rsc, frag, pgm, e->fragUniforms, "frag",
+                               uniformList, (uint32_t)numUniforms);
+
+        // Clean up the uniform data from GL
+        if (uniformList != NULL) {
+            for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) {
+                delete uniformList[ct];
+            }
+            delete[] uniformList;
+            uniformList = NULL;
+        }
+    }
+
+    //LOGV("SC made program %i", e->program);
+    glUseProgram(e->program);
+    rsc->checkError("RsdShaderCache::link (miss)");
+
+    return true;
+}
+
+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;
+        }
+    }
+    return -1;
+}
+
+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) {
+            glDeleteProgram(mEntries[ct]->program);
+
+            delete mEntries[ct];
+            mEntries.removeAt(ct);
+            numEntries = (int32_t)mEntries.size();
+            ct --;
+        }
+    }
+}
+
+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) {
+            glDeleteProgram(mEntries[ct]->program);
+
+            delete mEntries[ct];
+            mEntries.removeAt(ct);
+            numEntries = (int32_t)mEntries.size();
+            ct --;
+        }
+    }
+}
+
+void RsdShaderCache::cleanupAll() {
+    for (uint32_t ct=0; ct < mEntries.size(); ct++) {
+        glDeleteProgram(mEntries[ct]->program);
+        free(mEntries[ct]);
+    }
+    mEntries.clear();
+}
+
diff --git a/libs/rs/driver/rsdShaderCache.h b/libs/rs/driver/rsdShaderCache.h
new file mode 100644
index 0000000..17ee3e8
--- /dev/null
+++ b/libs/rs/driver/rsdShaderCache.h
@@ -0,0 +1,151 @@
+/*
+ * 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_CACHE_H
+#define ANDROID_RSD_SHADER_CACHE_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 RsdShaderCache {
+public:
+    RsdShaderCache();
+    virtual ~RsdShaderCache();
+
+    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 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;
+        int32_t writtenLength;
+        int32_t arraySize;
+        uint32_t type;
+        UniformQueryData(uint32_t maxName) {
+            name = NULL;
+            nameLength = maxName;
+            if (nameLength > 0 ) {
+                name = new char[nameLength];
+            }
+        }
+        ~UniformQueryData() {
+            if (name != NULL) {
+                delete[] name;
+                name = NULL;
+            }
+        }
+    };
+    struct UniformData {
+        int32_t slot;
+        uint32_t arraySize;
+    };
+    struct AttrData {
+        int32_t slot;
+        const char* name;
+    };
+    struct ProgramEntry {
+        ProgramEntry(uint32_t numVtxAttr, uint32_t numVtxUnis,
+                     uint32_t numFragUnis) : vtx(0), frag(0), program(0), vtxAttrCount(0),
+                                             vtxAttrs(0), vtxUniforms(0), fragUniforms(0) {
+            vtxAttrCount = numVtxAttr;
+            if (numVtxAttr) {
+                vtxAttrs = new AttrData[numVtxAttr];
+            }
+            if (numVtxUnis) {
+                vtxUniforms = new UniformData[numVtxUnis];
+            }
+            if (numFragUnis) {
+                fragUniforms = new UniformData[numFragUnis];
+            }
+        }
+        ~ProgramEntry() {
+            if (vtxAttrs) {
+                delete[] vtxAttrs;
+                vtxAttrs = NULL;
+            }
+            if (vtxUniforms) {
+                delete[] vtxUniforms;
+                vtxUniforms = NULL;
+            }
+            if (fragUniforms) {
+                delete[] fragUniforms;
+                fragUniforms = NULL;
+            }
+        }
+        uint32_t vtx;
+        uint32_t frag;
+        uint32_t program;
+        uint32_t vtxAttrCount;
+        AttrData *vtxAttrs;
+        UniformData *vtxUniforms;
+        UniformData *fragUniforms;
+    };
+    android::Vector<ProgramEntry*> mEntries;
+    ProgramEntry *mCurrent;
+
+    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_RSD_SHADER_CACHE_H
+
+
+
+
diff --git a/libs/rs/driver/rsdVertexArray.cpp b/libs/rs/driver/rsdVertexArray.cpp
new file mode 100644
index 0000000..d0a5a54
--- /dev/null
+++ b/libs/rs/driver/rsdVertexArray.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 <GLES/gl.h>
+#include <GLES2/gl2.h>
+
+#include "rsdCore.h"
+#include "rsdVertexArray.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+RsdVertexArray::RsdVertexArray(const Attrib *attribs, uint32_t numAttribs) {
+    mAttribs = attribs;
+    mCount = numAttribs;
+}
+
+RsdVertexArray::~RsdVertexArray() {
+}
+
+RsdVertexArray::Attrib::Attrib() {
+    clear();
+}
+
+void RsdVertexArray::Attrib::clear() {
+    buffer = 0;
+    offset = 0;
+    type = 0;
+    size = 0;
+    stride = 0;
+    ptr = NULL;
+    normalized = false;
+    name.setTo("");
+}
+
+void RsdVertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride,
+                              bool normalized, uint32_t offset,
+                              const char *name) {
+    clear();
+    this->type = type;
+    this->size = size;
+    this->offset = offset;
+    this->normalized = normalized;
+    this->stride = stride;
+    this->name.setTo(name);
+}
+
+void RsdVertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
+    if (idx == 0) {
+        LOGV("Starting vertex attribute binding");
+    }
+    LOGV("va %i: slot=%i name=%s buf=%i ptr=%p size=%i  type=0x%x  stride=0x%x  norm=%i  offset=0x%x",
+         idx, slot,
+         mAttribs[idx].name.string(),
+         mAttribs[idx].buffer,
+         mAttribs[idx].ptr,
+         mAttribs[idx].size,
+         mAttribs[idx].type,
+         mAttribs[idx].stride,
+         mAttribs[idx].normalized,
+         mAttribs[idx].offset);
+}
+
+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);
+            state->mAttrsEnabled[ct] = false;
+        }
+    }
+
+    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) {
+            logAttrib(ct, slot);
+        }
+        if (slot < 0 || slot >= (int32_t)maxAttrs) {
+            continue;
+        }
+        glEnableVertexAttribArray(slot);
+        state->mAttrsEnabled[slot] = true;
+        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
+        glVertexAttribPointer(slot,
+                              mAttribs[ct].size,
+                              mAttribs[ct].type,
+                              mAttribs[ct].normalized,
+                              mAttribs[ct].stride,
+                              mAttribs[ct].ptr + mAttribs[ct].offset);
+    }
+    rsc->checkError("RsdVertexArray::setupGL2 done");
+}
+////////////////////////////////////////////
+RsdVertexArrayState::RsdVertexArrayState() {
+    mAttrsEnabled = NULL;
+    mAttrsEnabledSize = 0;
+}
+
+RsdVertexArrayState::~RsdVertexArrayState() {
+    if (mAttrsEnabled) {
+        delete[] mAttrsEnabled;
+        mAttrsEnabled = NULL;
+    }
+}
+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/libs/rs/driver/rsdVertexArray.h b/libs/rs/driver/rsdVertexArray.h
new file mode 100644
index 0000000..925a6ae
--- /dev/null
+++ b/libs/rs/driver/rsdVertexArray.h
@@ -0,0 +1,79 @@
+/*
+ * 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_VERTEX_ARRAY_H
+#define ANDROID_RSD_VERTEX_ARRAY_H
+
+namespace android {
+namespace renderscript {
+
+class Context;
+
+}
+}
+
+#include <utils/String8.h>
+
+// An element is a group of Components that occupies one cell in a structure.
+class RsdVertexArray {
+public:
+    class Attrib {
+    public:
+        uint32_t buffer;
+        const uint8_t * ptr;
+        uint32_t offset;
+        uint32_t type;
+        uint32_t size;
+        uint32_t stride;
+        bool normalized;
+        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);
+    };
+
+    RsdVertexArray(const Attrib *attribs, uint32_t numAttribs);
+    virtual ~RsdVertexArray();
+
+    void setupGL2(const android::renderscript::Context *rsc) const;
+    void logAttrib(uint32_t idx, uint32_t slot) const;
+
+protected:
+    void clear(uint32_t index);
+    uint32_t mActiveBuffer;
+    const uint8_t * mActivePointer;
+    uint32_t mCount;
+
+    const Attrib *mAttribs;
+};
+
+
+class RsdVertexArrayState {
+public:
+    RsdVertexArrayState();
+    ~RsdVertexArrayState();
+    void init(uint32_t maxAttrs);
+
+    bool *mAttrsEnabled;
+    uint32_t mAttrsEnabledSize;
+};
+
+
+#endif //ANDROID_RSD_VERTEX_ARRAY_H
+
+
+