Move C++ API over to function tables rather than linking libRS directly.

Change-Id: I7841df768d5bd10fa941b3655673fd73496a8137
diff --git a/cpp/Allocation.cpp b/cpp/Allocation.cpp
index 7755f74..a613e45 100644
--- a/cpp/Allocation.cpp
+++ b/cpp/Allocation.cpp
@@ -121,7 +121,7 @@
 void Allocation::updateFromNative() {
     BaseObj::updateFromNative();
 
-    const void *typeID = rsaAllocationGetType(mRS->getContext(), getID());
+    const void *typeID = RS::dispatch->AllocationGetType(mRS->getContext(), getID());
     if(typeID != NULL) {
         sp<const Type> old = mType;
         sp<Type> t = new Type((void *)typeID, mRS);
@@ -141,7 +141,7 @@
     default:
         ALOGE("Source must be exactly one usage type.");
     }
-    rsAllocationSyncAll(mRS->getContext(), getIDSafe(), srcLocation);
+    RS::dispatch->AllocationSyncAll(mRS->getContext(), getIDSafe(), srcLocation);
 }
 
 void Allocation::ioSendOutput() {
@@ -149,7 +149,7 @@
     if ((mUsage & RS_ALLOCATION_USAGE_IO_OUTPUT) == 0) {
         ALOGE("Can only send buffer if IO_OUTPUT usage specified.");
     }
-    rsAllocationIoSend(mRS->getContext(), getID());
+    RS::dispatch->AllocationIoSend(mRS->getContext(), getID());
 #endif
 }
 
@@ -158,12 +158,12 @@
     if ((mUsage & RS_ALLOCATION_USAGE_IO_INPUT) == 0) {
         ALOGE("Can only send buffer if IO_OUTPUT usage specified.");
     }
-    rsAllocationIoReceive(mRS->getContext(), getID());
+    RS::dispatch->AllocationIoReceive(mRS->getContext(), getID());
 #endif
 }
 
 void Allocation::generateMipmaps() {
-    rsAllocationGenerateMipmaps(mRS->getContext(), getID());
+    RS::dispatch->AllocationGenerateMipmaps(mRS->getContext(), getID());
 }
 
 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const void *data) {
@@ -177,7 +177,7 @@
         return;
     }
 
-    rsAllocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD, count, data,
+    RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD, count, data,
                        count * mType->getElement()->getSizeBytes());
 }
 
@@ -191,14 +191,14 @@
         return;
     }
 
-    rsAllocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD, count, data,
+    RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD, count, data,
                        count * mType->getElement()->getSizeBytes());
 }
 
 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, sp<const Allocation> data,
                                  uint32_t dataOff) {
 
-    rsAllocationCopy2DRange(mRS->getContext(), getIDSafe(), off, 0,
+    RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), off, 0,
                             mSelectedLOD, mSelectedFace,
                             count, 1, data->getIDSafe(), dataOff, 0,
                             data->mSelectedLOD, data->mSelectedFace);
@@ -226,14 +226,14 @@
 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
                                  const void *data) {
     validate2DRange(xoff, yoff, w, h);
-    rsAllocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
+    RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
                        w, h, data, w * h * mType->getElement()->getSizeBytes(), w * mType->getElement()->getSizeBytes());
 }
 
 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
                                  sp<const Allocation> data, uint32_t dataXoff, uint32_t dataYoff) {
     validate2DRange(xoff, yoff, w, h);
-    rsAllocationCopy2DRange(mRS->getContext(), getIDSafe(), xoff, yoff,
+    RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), xoff, yoff,
                             mSelectedLOD, mSelectedFace,
                             w, h, data->getIDSafe(), dataXoff, dataYoff,
                             data->mSelectedLOD, data->mSelectedFace);
@@ -242,14 +242,14 @@
 void Allocation::copy2DRangeTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
                                void* data) {
     validate2DRange(xoff, yoff, w, h);
-    rsAllocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
+    RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
                        w, h, data, w * h * mType->getElement()->getSizeBytes(), w * mType->getElement()->getSizeBytes());
 }
 
 void Allocation::copy2DStridedFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
                                    const void *data, size_t stride) {
     validate2DRange(xoff, yoff, w, h);
-    rsAllocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
+    RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
                        w, h, data, w * h * mType->getElement()->getSizeBytes(), stride);
 }
 
@@ -260,7 +260,7 @@
 void Allocation::copy2DStridedTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
                                  void *data, size_t stride) {
     validate2DRange(xoff, yoff, w, h);
-    rsAllocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
+    RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
                        w, h, data, w * h * mType->getElement()->getSizeBytes(), stride);
 }
 
@@ -268,44 +268,9 @@
     copy2DStridedTo(0, 0, mCurrentDimX, mCurrentDimY, data, stride);
 }
 
-
-/*
-void resize(int dimX) {
-    if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
-        throw new RSInvalidStateException("Resize only support for 1D allocations at this time.");
-    }
-    mRS.nAllocationResize1D(getID(), dimX);
-    mRS.finish();  // Necessary because resize is fifoed and update is async.
-
-    int typeID = mRS.nAllocationGetType(getID());
-    mType = new Type(typeID, mRS);
-    mType.updateFromNative();
-    updateCacheInfo(mType);
-}
-
-void resize(int dimX, int dimY) {
-    if ((mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
-        throw new RSInvalidStateException(
-            "Resize only support for 2D allocations at this time.");
-    }
-    if (mType.getY() == 0) {
-        throw new RSInvalidStateException(
-            "Resize only support for 2D allocations at this time.");
-    }
-    mRS.nAllocationResize2D(getID(), dimX, dimY);
-    mRS.finish();  // Necessary because resize is fifoed and update is async.
-
-    int typeID = mRS.nAllocationGetType(getID());
-    mType = new Type(typeID, mRS);
-    mType.updateFromNative();
-    updateCacheInfo(mType);
-}
-*/
-
-
 android::sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type,
                                                 RsAllocationMipmapControl mips, uint32_t usage) {
-    void *id = rsAllocationCreateTyped(rs->getContext(), type->getID(), mips, usage, 0);
+    void *id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mips, usage, 0);
     if (id == 0) {
         ALOGE("Allocation creation failed.");
         return NULL;
@@ -316,7 +281,7 @@
 android::sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type,
                                                 RsAllocationMipmapControl mips, uint32_t usage,
                                                 void *pointer) {
-    void *id = rsAllocationCreateTyped(rs->getContext(), type->getID(), mips, usage,
+    void *id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mips, usage,
                                        (uintptr_t)pointer);
     if (id == 0) {
         ALOGE("Allocation creation failed.");
diff --git a/cpp/Android.mk b/cpp/Android.mk
index 145f487..689b2fa 100644
--- a/cpp/Android.mk
+++ b/cpp/Android.mk
@@ -28,7 +28,8 @@
 	libz \
 	libcutils \
 	libutils \
-	liblog
+	liblog \
+	libdl
 
 LOCAL_MODULE:= libRScpp
 
diff --git a/cpp/BaseObj.cpp b/cpp/BaseObj.cpp
index 828bd87..fa7d73c 100644
--- a/cpp/BaseObj.cpp
+++ b/cpp/BaseObj.cpp
@@ -44,7 +44,7 @@
 }
 
 BaseObj::~BaseObj() {
-    rsObjDestroy(mRS->getContext(), mID);
+    RS::dispatch->ObjDestroy(mRS->getContext(), mID);
     mRS = NULL;
     mID = NULL;
 }
diff --git a/cpp/Element.cpp b/cpp/Element.cpp
index 51a96cd..7c58516 100644
--- a/cpp/Element.cpp
+++ b/cpp/Element.cpp
@@ -250,7 +250,7 @@
 }
 
 sp<const Element> Element::createUser(sp<RS> rs, RsDataType dt) {
-    void * id = rsElementCreate(rs->getContext(), dt, RS_KIND_USER, false, 1);
+    void * id = RS::dispatch->ElementCreate(rs->getContext(), dt, RS_KIND_USER, false, 1);
     return new Element(id, rs, dt, RS_KIND_USER, false, 1);
 }
 
@@ -258,7 +258,7 @@
     if (size < 2 || size > 4) {
         rs->throwError("Vector size out of range 2-4.");
     }
-    void *id = rsElementCreate(rs->getContext(), dt, RS_KIND_USER, false, size);
+    void *id = RS::dispatch->ElementCreate(rs->getContext(), dt, RS_KIND_USER, false, size);
     return new Element(id, rs, dt, RS_KIND_USER, false, size);
 }
 
@@ -309,7 +309,7 @@
         break;
     }
 
-    void * id = rsElementCreate(rs->getContext(), dt, dk, true, size);
+    void * id = RS::dispatch->ElementCreate(rs->getContext(), dt, dk, true, size);
     return new Element(id, rs, dt, dk, true, size);
 }
 
@@ -371,7 +371,7 @@
         sizeArray[ct] = mElementNames[ct].length();
     }
 
-    void *id = rsElementCreate2(mRS->getContext(),
+    void *id = RS::dispatch->ElementCreate2(mRS->getContext(),
                                 (RsElement *)elementArray, fieldCount,
                                 nameArray, fieldCount * sizeof(size_t),  sizeArray,
                                 (const uint32_t *)mArraySizes.array(), fieldCount);
diff --git a/cpp/RenderScript.cpp b/cpp/RenderScript.cpp
index 134d34b..613d4aa 100644
--- a/cpp/RenderScript.cpp
+++ b/cpp/RenderScript.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 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,11 +21,20 @@
 #include "RenderScript.h"
 #include "rs.h"
 
+#include <dlfcn.h>
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "rsC++"
+
 using namespace android;
 using namespace RSC;
 
 bool RS::gInitialized = false;
 pthread_mutex_t RS::gInitMutex = PTHREAD_MUTEX_INITIALIZER;
+void* RS::librs = NULL;
+dispatchTable* RS::dispatch = NULL;
+
+static int gInitError = 0;
 
 RS::RS() {
     mDev = NULL;
@@ -33,36 +42,395 @@
     mErrorFunc = NULL;
     mMessageFunc = NULL;
     mMessageRun = false;
+    mInit = false;
 
     memset(&mElements, 0, sizeof(mElements));
 }
 
 RS::~RS() {
-    mMessageRun = false;
+    if (mInit == true) {
+        mMessageRun = false;
 
-    rsContextDeinitToClient(mContext);
+        RS::dispatch->ContextDeinitToClient(mContext);
 
-    void *res = NULL;
-    int status = pthread_join(mMessageThreadId, &res);
+        void *res = NULL;
+        int status = pthread_join(mMessageThreadId, &res);
 
-    rsContextDestroy(mContext);
-    mContext = NULL;
-    rsDeviceDestroy(mDev);
-    mDev = NULL;
+        RS::dispatch->ContextDestroy(mContext);
+        mContext = NULL;
+        RS::dispatch->DeviceDestroy(mDev);
+        mDev = NULL;
+    }
 }
 
 bool RS::init(bool forceCpu, bool synchronous) {
     return RS::init(RS_VERSION, forceCpu, synchronous);
 }
 
+bool RS::initDispatch(int targetApi) {
+
+    pthread_mutex_lock(&gInitMutex);
+    if (gInitError) {
+        goto error;
+    } else if (gInitialized) {
+        return true;
+    }
+    // pick appropriate lib at some point
+    RS::librs = dlopen("libRS.so", RTLD_LAZY | RTLD_LOCAL);
+    if (RS::librs == 0) {
+        ALOGE("couldn't dlopen libRS, %s", dlerror());
+        goto error;
+    }
+    ALOGE("libRS initialized successfully");
+
+    RS::dispatch = new dispatchTable;
+
+
+    RS::dispatch->AllocationGetType = (AllocationGetTypeFnPtr)dlsym(RS::librs, "rsaAllocationGetType");
+    if (RS::dispatch->AllocationGetType == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationGetType");
+        goto error;
+    }
+    RS::dispatch->TypeGetNativeData = (TypeGetNativeDataFnPtr)dlsym(RS::librs, "rsaTypeGetNativeData");
+    if (RS::dispatch->TypeGetNativeData == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->TypeGetNativeData");
+        goto error;
+    }
+    RS::dispatch->ElementGetNativeData = (ElementGetNativeDataFnPtr)dlsym(RS::librs, "rsaElementGetNativeData");
+    if (RS::dispatch->ElementGetNativeData == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ElementGetNativeData");
+        goto error;
+    }
+    RS::dispatch->ElementGetSubElements = (ElementGetSubElementsFnPtr)dlsym(RS::librs, "rsaElementGetSubElements");
+    if (RS::dispatch->ElementGetSubElements == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ElementGetSubElements");
+        goto error;
+    }
+    RS::dispatch->DeviceCreate = (DeviceCreateFnPtr)dlsym(RS::librs, "rsDeviceCreate");
+    if (RS::dispatch->DeviceCreate == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->DeviceCreate");
+        goto error;
+    }
+    RS::dispatch->DeviceDestroy = (DeviceDestroyFnPtr)dlsym(RS::librs, "rsDeviceDestroy");
+    if (RS::dispatch->DeviceDestroy == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->DeviceDestroy");
+        goto error;
+    }
+    RS::dispatch->DeviceSetConfig = (DeviceSetConfigFnPtr)dlsym(RS::librs, "rsDeviceSetConfig");
+    if (RS::dispatch->DeviceSetConfig == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->DeviceSetConfig");
+        goto error;
+    }
+    RS::dispatch->ContextCreate = (ContextCreateFnPtr)dlsym(RS::librs, "rsContextCreate");;
+    if (RS::dispatch->ContextCreate == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ContextCreate");
+        goto error;
+    }
+    RS::dispatch->ContextDestroy = (ContextDestroyFnPtr)dlsym(RS::librs, "rsContextDestroy");
+    if (RS::dispatch->ContextDestroy == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ContextDestroy");
+        goto error;
+    }
+    RS::dispatch->ContextGetMessage = (ContextGetMessageFnPtr)dlsym(RS::librs, "rsContextGetMessage");
+    if (RS::dispatch->ContextGetMessage == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ContextGetMessage");
+        goto error;
+    }
+    RS::dispatch->ContextPeekMessage = (ContextPeekMessageFnPtr)dlsym(RS::librs, "rsContextPeekMessage");
+    if (RS::dispatch->ContextPeekMessage == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ContextPeekMessage");
+        goto error;
+    }
+    RS::dispatch->ContextSendMessage = (ContextSendMessageFnPtr)dlsym(RS::librs, "rsContextSendMessage");
+    if (RS::dispatch->ContextSendMessage == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ContextSendMessage");
+        goto error;
+    }
+    RS::dispatch->ContextInitToClient = (ContextInitToClientFnPtr)dlsym(RS::librs, "rsContextInitToClient");
+    if (RS::dispatch->ContextInitToClient == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ContextInitToClient");
+        goto error;
+    }
+    RS::dispatch->ContextDeinitToClient = (ContextDeinitToClientFnPtr)dlsym(RS::librs, "rsContextDeinitToClient");
+    if (RS::dispatch->ContextDeinitToClient == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ContextDeinitToClient");
+        goto error;
+    }
+    RS::dispatch->TypeCreate = (TypeCreateFnPtr)dlsym(RS::librs, "rsTypeCreate");
+    if (RS::dispatch->TypeCreate == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->TypeCreate");
+        goto error;
+    }
+    RS::dispatch->AllocationCreateTyped = (AllocationCreateTypedFnPtr)dlsym(RS::librs, "rsAllocationCreateTyped");
+    if (RS::dispatch->AllocationCreateTyped == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationCreateTyped");
+        goto error;
+    }
+    RS::dispatch->AllocationCreateFromBitmap = (AllocationCreateFromBitmapFnPtr)dlsym(RS::librs, "rsAllocationCreateFromBitmap");
+    if (RS::dispatch->AllocationCreateFromBitmap == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationCreateFromBitmap");
+        goto error;
+    }
+    RS::dispatch->AllocationCubeCreateFromBitmap = (AllocationCubeCreateFromBitmapFnPtr)dlsym(RS::librs, "rsAllocationCubeCreateFromBitmap");
+    if (RS::dispatch->AllocationCubeCreateFromBitmap == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationCubeCreateFromBitmap");
+        goto error;
+    }
+    RS::dispatch->AllocationGetSurface = (AllocationGetSurfaceFnPtr)dlsym(RS::librs, "rsAllocationGetSurface");
+    if (RS::dispatch->AllocationGetSurface == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationGetSurface");
+        goto error;
+    }
+    RS::dispatch->AllocationSetSurface = (AllocationSetSurfaceFnPtr)dlsym(RS::librs, "rsAllocationSetSurface");
+    if (RS::dispatch->AllocationSetSurface == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationSetSurface");
+        goto error;
+    }
+    RS::dispatch->ContextFinish = (ContextFinishFnPtr)dlsym(RS::librs, "rsContextFinish");
+    if (RS::dispatch->ContextFinish == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ContextFinish");
+        goto error;
+    }
+    RS::dispatch->ContextDump = (ContextDumpFnPtr)dlsym(RS::librs, "rsContextDump");
+    if (RS::dispatch->ContextDump == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ContextDump");
+        goto error;
+    }
+    RS::dispatch->ContextSetPriority = (ContextSetPriorityFnPtr)dlsym(RS::librs, "rsContextSetPriority");
+    if (RS::dispatch->ContextSetPriority == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ContextSetPriority");
+        goto error;
+    }
+    RS::dispatch->AssignName = (AssignNameFnPtr)dlsym(RS::librs, "rsAssignName");
+    if (RS::dispatch->AssignName == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AssignName");
+        goto error;
+    }
+    RS::dispatch->ObjDestroy = (ObjDestroyFnPtr)dlsym(RS::librs, "rsObjDestroy");
+    if (RS::dispatch->ObjDestroy == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ObjDestroy");
+        goto error;
+    }
+    RS::dispatch->ElementCreate = (ElementCreateFnPtr)dlsym(RS::librs, "rsElementCreate");
+    if (RS::dispatch->ElementCreate == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ElementCreate");
+        goto error;
+    }
+    RS::dispatch->ElementCreate2 = (ElementCreate2FnPtr)dlsym(RS::librs, "rsElementCreate2");
+    if (RS::dispatch->ElementCreate2 == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ElementCreate2");
+        goto error;
+    }
+    RS::dispatch->AllocationCopyToBitmap = (AllocationCopyToBitmapFnPtr)dlsym(RS::librs, "rsAllocationCopyToBitmap");
+    if (RS::dispatch->AllocationCopyToBitmap == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationCopyToBitmap");
+        goto error;
+    }
+    RS::dispatch->Allocation1DData = (Allocation1DDataFnPtr)dlsym(RS::librs, "rsAllocation1DData");
+    if (RS::dispatch->Allocation1DData == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->Allocation1DData");
+        goto error;
+    }
+    RS::dispatch->Allocation1DElementData = (Allocation1DElementDataFnPtr)dlsym(RS::librs, "rsAllocation1DElementData");
+    if (RS::dispatch->Allocation1DElementData == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->Allocation1DElementData");
+        goto error;
+    }
+    RS::dispatch->Allocation2DData = (Allocation2DDataFnPtr)dlsym(RS::librs, "rsAllocation2DData");
+    if (RS::dispatch->Allocation2DData == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->Allocation2DData");
+        goto error;
+    }
+    RS::dispatch->Allocation3DData = (Allocation3DDataFnPtr)dlsym(RS::librs, "rsAllocation3DData");
+    if (RS::dispatch->Allocation3DData == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->Allocation3DData");
+        goto error;
+    }
+    RS::dispatch->AllocationGenerateMipmaps = (AllocationGenerateMipmapsFnPtr)dlsym(RS::librs, "rsAllocationGenerateMipmaps");
+    if (RS::dispatch->AllocationGenerateMipmaps == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationGenerateMipmaps");
+        goto error;
+    }
+    RS::dispatch->AllocationRead = (AllocationReadFnPtr)dlsym(RS::librs, "rsAllocationRead");
+    if (RS::dispatch->AllocationRead == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationRead");
+        goto error;
+    }
+    RS::dispatch->Allocation1DRead = (Allocation1DReadFnPtr)dlsym(RS::librs, "rsAllocation1DRead");
+    if (RS::dispatch->Allocation1DRead == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->Allocation1DRead");
+        goto error;
+    }
+    RS::dispatch->Allocation2DRead = (Allocation2DReadFnPtr)dlsym(RS::librs, "rsAllocation2DRead");
+    if (RS::dispatch->Allocation2DRead == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->Allocation2DRead");
+        goto error;
+    }
+    RS::dispatch->AllocationSyncAll = (AllocationSyncAllFnPtr)dlsym(RS::librs, "rsAllocationSyncAll");
+    if (RS::dispatch->AllocationSyncAll == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationSyncAll");
+        goto error;
+    }
+    RS::dispatch->AllocationResize1D = (AllocationResize1DFnPtr)dlsym(RS::librs, "rsAllocationResize1D");
+    if (RS::dispatch->AllocationResize1D == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationResize1D");
+        goto error;
+    }
+    RS::dispatch->AllocationCopy2DRange = (AllocationCopy2DRangeFnPtr)dlsym(RS::librs, "rsAllocationCopy2DRange");
+    if (RS::dispatch->AllocationCopy2DRange == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationCopy2DRange");
+        goto error;
+    }
+    RS::dispatch->AllocationCopy3DRange = (AllocationCopy3DRangeFnPtr)dlsym(RS::librs, "rsAllocationCopy3DRange");
+    if (RS::dispatch->AllocationCopy3DRange == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationCopy3DRange");
+        goto error;
+    }
+    RS::dispatch->SamplerCreate = (SamplerCreateFnPtr)dlsym(RS::librs, "rsSamplerCreate");
+    if (RS::dispatch->SamplerCreate == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->SamplerCreate");
+        goto error;
+    }
+    RS::dispatch->ScriptBindAllocation = (ScriptBindAllocationFnPtr)dlsym(RS::librs, "rsScriptBindAllocation");
+    if (RS::dispatch->ScriptBindAllocation == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptBindAllocation");
+        goto error;
+    }
+    RS::dispatch->ScriptSetTimeZone = (ScriptSetTimeZoneFnPtr)dlsym(RS::librs, "rsScriptSetTimeZone");
+    if (RS::dispatch->ScriptSetTimeZone == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptSetTimeZone");
+        goto error;
+    }
+    RS::dispatch->ScriptInvoke = (ScriptInvokeFnPtr)dlsym(RS::librs, "rsScriptInvoke");
+    if (RS::dispatch->ScriptInvoke == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptInvoke");
+        goto error;
+    }
+    RS::dispatch->ScriptInvokeV = (ScriptInvokeVFnPtr)dlsym(RS::librs, "rsScriptInvokeV");
+    if (RS::dispatch->ScriptInvokeV == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptInvokeV");
+        goto error;
+    }
+    RS::dispatch->ScriptForEach = (ScriptForEachFnPtr)dlsym(RS::librs, "rsScriptForEach");
+    if (RS::dispatch->ScriptForEach == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptForEach");
+        goto error;
+    }
+    RS::dispatch->ScriptSetVarI = (ScriptSetVarIFnPtr)dlsym(RS::librs, "rsScriptSetVarI");
+    if (RS::dispatch->ScriptSetVarI == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptSetVarI");
+        goto error;
+    }
+    RS::dispatch->ScriptSetVarObj = (ScriptSetVarObjFnPtr)dlsym(RS::librs, "rsScriptSetVarObj");
+    if (RS::dispatch->ScriptSetVarObj == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptSetVarObj");
+        goto error;
+    }
+    RS::dispatch->ScriptSetVarJ = (ScriptSetVarJFnPtr)dlsym(RS::librs, "rsScriptSetVarJ");
+    if (RS::dispatch->ScriptSetVarJ == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptSetVarJ");
+        goto error;
+    }
+    RS::dispatch->ScriptSetVarF = (ScriptSetVarFFnPtr)dlsym(RS::librs, "rsScriptSetVarF");
+    if (RS::dispatch->ScriptSetVarF == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptSetVarF");
+        goto error;
+    }
+    RS::dispatch->ScriptSetVarD = (ScriptSetVarDFnPtr)dlsym(RS::librs, "rsScriptSetVarD");
+    if (RS::dispatch->ScriptSetVarD == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptSetVarD");
+        goto error;
+    }
+    RS::dispatch->ScriptSetVarV = (ScriptSetVarVFnPtr)dlsym(RS::librs, "rsScriptSetVarV");
+    if (RS::dispatch->ScriptSetVarV == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptSetVarV");
+        goto error;
+    }
+    RS::dispatch->ScriptGetVarV = (ScriptGetVarVFnPtr)dlsym(RS::librs, "rsScriptGetVarV");
+    if (RS::dispatch->ScriptGetVarV == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptGetVarV");
+        goto error;
+    }
+    RS::dispatch->ScriptSetVarVE = (ScriptSetVarVEFnPtr)dlsym(RS::librs, "rsScriptSetVarVE");
+    if (RS::dispatch->ScriptSetVarVE == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptSetVarVE");
+        goto error;
+    }
+    RS::dispatch->ScriptCCreate = (ScriptCCreateFnPtr)dlsym(RS::librs, "rsScriptCCreate");
+    if (RS::dispatch->ScriptCCreate == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptCCreate");
+        goto error;
+    }
+    RS::dispatch->ScriptIntrinsicCreate = (ScriptIntrinsicCreateFnPtr)dlsym(RS::librs, "rsScriptIntrinsicCreate");
+    if (RS::dispatch->ScriptIntrinsicCreate == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptIntrinsicCreate");
+        goto error;
+    }
+    RS::dispatch->ScriptKernelIDCreate = (ScriptKernelIDCreateFnPtr)dlsym(RS::librs, "rsScriptKernelIDCreate");
+    if (RS::dispatch->ScriptKernelIDCreate == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptKernelIDCreate");
+        goto error;
+    }
+    RS::dispatch->ScriptFieldIDCreate = (ScriptFieldIDCreateFnPtr)dlsym(RS::librs, "rsScriptFieldIDCreate");
+    if (RS::dispatch->ScriptFieldIDCreate == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptFieldIDCreate");
+        goto error;
+    }
+    RS::dispatch->ScriptGroupCreate = (ScriptGroupCreateFnPtr)dlsym(RS::librs, "rsScriptGroupCreate");
+    if (RS::dispatch->ScriptGroupCreate == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptGroupCreate");
+        goto error;
+    }
+    RS::dispatch->ScriptGroupSetOutput = (ScriptGroupSetOutputFnPtr)dlsym(RS::librs, "rsScriptGroupSetOutput");
+    if (RS::dispatch->ScriptGroupSetOutput == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptGroupSetOutput");
+        goto error;
+    }
+    RS::dispatch->ScriptGroupSetInput = (ScriptGroupSetInputFnPtr)dlsym(RS::librs, "rsScriptGroupSetInput");
+    if (RS::dispatch->ScriptGroupSetInput == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptGroupSetInput");
+        goto error;
+    }
+    RS::dispatch->ScriptGroupExecute = (ScriptGroupExecuteFnPtr)dlsym(RS::librs, "rsScriptGroupExecute");
+    if (RS::dispatch->ScriptGroupExecute == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->ScriptGroupExecute");
+        goto error;
+    }
+    RS::dispatch->AllocationIoSend = (AllocationIoSendFnPtr)dlsym(RS::librs, "rsAllocationIoSend");
+    if (RS::dispatch->AllocationIoSend == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationIoSend");
+        goto error;
+    }
+    RS::dispatch->AllocationIoReceive = (AllocationIoReceiveFnPtr)dlsym(RS::librs, "rsAllocationIoReceive");
+    if (RS::dispatch->AllocationIoReceive == NULL) {
+        ALOGE("Couldn't initialize RS::dispatch->AllocationIoReceive");
+        goto error;
+    }
+
+    gInitialized = true;
+
+    pthread_mutex_unlock(&gInitMutex);
+    return true;
+
+ error:
+    gInitError = 1;
+    pthread_mutex_unlock(&gInitMutex);
+    return false;
+}
+
 bool RS::init(int targetApi, bool forceCpu, bool synchronous) {
-    mDev = rsDeviceCreate();
+    if (initDispatch(targetApi) == false) {
+        ALOGE("Couldn't initialize dispatch table");
+        return false;
+    }
+
+    mDev = RS::dispatch->DeviceCreate();
     if (mDev == 0) {
         ALOGE("Device creation failed");
         return false;
     }
 
-    mContext = rsContextCreate(mDev, 0, targetApi, RS_CONTEXT_TYPE_NORMAL, forceCpu, synchronous);
+    mContext = RS::dispatch->ContextCreate(mDev, 0, targetApi, RS_CONTEXT_TYPE_NORMAL, forceCpu, synchronous);
     if (mContext == 0) {
         ALOGE("Context creation failed");
         return false;
@@ -80,6 +448,8 @@
         usleep(1000);
     }
 
+    mInit = true;
+
     return true;
 }
 
@@ -95,16 +465,16 @@
     size_t rbuf_size = 256;
     void * rbuf = malloc(rbuf_size);
 
-    rsContextInitToClient(rs->mContext);
+    RS::dispatch->ContextInitToClient(rs->mContext);
     rs->mMessageRun = true;
 
     while (rs->mMessageRun) {
         size_t receiveLen = 0;
         uint32_t usrID = 0;
         uint32_t subID = 0;
-        RsMessageToClientType r = rsContextPeekMessage(rs->mContext,
-                                                       &receiveLen, sizeof(receiveLen),
-                                                       &usrID, sizeof(usrID));
+        RsMessageToClientType r = RS::dispatch->ContextPeekMessage(rs->mContext,
+                                                                   &receiveLen, sizeof(receiveLen),
+                                                                   &usrID, sizeof(usrID));
 
         if (receiveLen >= rbuf_size) {
             rbuf_size = receiveLen + 32;
@@ -114,7 +484,7 @@
             ALOGE("RS::message handler realloc error %zu", rbuf_size);
             // No clean way to recover now?
         }
-        rsContextGetMessage(rs->mContext, rbuf, rbuf_size, &receiveLen, sizeof(receiveLen),
+        RS::dispatch->ContextGetMessage(rs->mContext, rbuf, rbuf_size, &receiveLen, sizeof(receiveLen),
                             &subID, sizeof(subID));
 
         switch(r) {
@@ -163,5 +533,5 @@
 }
 
 void RS::finish() {
-    rsContextFinish(mContext);
+    RS::dispatch->ContextFinish(mContext);
 }
diff --git a/cpp/Script.cpp b/cpp/Script.cpp
index 54a571a..70754d0 100644
--- a/cpp/Script.cpp
+++ b/cpp/Script.cpp
@@ -23,7 +23,7 @@
 using namespace RSC;
 
 void Script::invoke(uint32_t slot, const void *v, size_t len) const {
-    rsScriptInvokeV(mRS->getContext(), getID(), slot, v, len);
+    RS::dispatch->ScriptInvokeV(mRS->getContext(), getID(), slot, v, len);
 }
 
 void Script::forEach(uint32_t slot, sp<const Allocation> ain, sp<const Allocation> aout,
@@ -33,7 +33,7 @@
     }
     void *in_id = BaseObj::getObjID(ain);
     void *out_id = BaseObj::getObjID(aout);
-    rsScriptForEach(mRS->getContext(), getID(), slot, in_id, out_id, usr, usrLen, NULL, 0);
+    RS::dispatch->ScriptForEach(mRS->getContext(), getID(), slot, in_id, out_id, usr, usrLen, NULL, 0);
 }
 
 
@@ -42,16 +42,16 @@
 
 
 void Script::bindAllocation(sp<Allocation> va, uint32_t slot) const {
-    rsScriptBindAllocation(mRS->getContext(), getID(), BaseObj::getObjID(va), slot);
+    RS::dispatch->ScriptBindAllocation(mRS->getContext(), getID(), BaseObj::getObjID(va), slot);
 }
 
 
 void Script::setVar(uint32_t index, sp<const BaseObj> o) const {
-    rsScriptSetVarObj(mRS->getContext(), getID(), index, (o == NULL) ? 0 : o->getID());
+    RS::dispatch->ScriptSetVarObj(mRS->getContext(), getID(), index, (o == NULL) ? 0 : o->getID());
 }
 
 void Script::setVar(uint32_t index, const void *v, size_t len) const {
-    rsScriptSetVarV(mRS->getContext(), getID(), index, v, len);
+    RS::dispatch->ScriptSetVarV(mRS->getContext(), getID(), index, v, len);
 }
 
 void Script::FieldBase::init(sp<RS> rs, uint32_t dimx, uint32_t usages) {
diff --git a/cpp/ScriptC.cpp b/cpp/ScriptC.cpp
index f66e0ec..30aa380 100644
--- a/cpp/ScriptC.cpp
+++ b/cpp/ScriptC.cpp
@@ -27,7 +27,7 @@
                  const char *cachedName, size_t cachedNameLength,
                  const char *cacheDir, size_t cacheDirLength)
 : Script(NULL, rs) {
-    mID = rsScriptCCreate(rs->getContext(), cachedName, cachedNameLength,
-                          cacheDir, cacheDirLength, (const char *)codeTxt, codeLength);
+    mID = RS::dispatch->ScriptCCreate(rs->getContext(), cachedName, cachedNameLength,
+                                      cacheDir, cacheDirLength, (const char *)codeTxt, codeLength);
 }
 
diff --git a/cpp/ScriptIntrinsics.cpp b/cpp/ScriptIntrinsics.cpp
index 44e8760..44c5bb6 100644
--- a/cpp/ScriptIntrinsics.cpp
+++ b/cpp/ScriptIntrinsics.cpp
@@ -25,7 +25,7 @@
 
 ScriptIntrinsic::ScriptIntrinsic(sp<RS> rs, int id, sp<const Element> e)
     : Script(NULL, rs) {
-    mID = rsScriptIntrinsicCreate(rs->getContext(), id, e->getID());
+    mID = RS::dispatch->ScriptIntrinsicCreate(rs->getContext(), id, e->getID());
 }
 
 ScriptIntrinsicBlend::ScriptIntrinsicBlend(sp<RS> rs, sp<const Element> e)
diff --git a/cpp/Type.cpp b/cpp/Type.cpp
index 312020a..a8acde4 100644
--- a/cpp/Type.cpp
+++ b/cpp/Type.cpp
@@ -93,7 +93,7 @@
 }
 
 sp<const Type> Type::create(sp<RS> rs, sp<const Element> e, uint32_t dimX, uint32_t dimY, uint32_t dimZ) {
-    void * id = rsTypeCreate(rs->getContext(), e->getID(), dimX, dimY, dimZ, false, false, 0);
+    void * id = RS::dispatch->TypeCreate(rs->getContext(), e->getID(), dimX, dimY, dimZ, false, false, 0);
     Type *t = new Type(id, rs);
 
     t->mElement = e;
@@ -160,8 +160,8 @@
         }
     }
 
-    void * id = rsTypeCreate(mRS->getContext(), mElement->getID(), mDimX, mDimY, mDimZ,
-            mDimMipmaps, mDimFaces, 0);
+    void * id = RS::dispatch->TypeCreate(mRS->getContext(), mElement->getID(), mDimX, mDimY, mDimZ,
+                                         mDimMipmaps, mDimFaces, 0);
     Type *t = new Type(id, mRS);
     t->mElement = mElement;
     t->mDimX = mDimX;
diff --git a/cpp/rsCppStructs.h b/cpp/rsCppStructs.h
index be011aa..fcc5fc5 100644
--- a/cpp/rsCppStructs.h
+++ b/cpp/rsCppStructs.h
@@ -24,6 +24,8 @@
 #include "RefBase.h"
 #endif
 
+#include "rsDispatch.h"
+
 // Every row in an RS allocation is guaranteed to be aligned by this amount
 // Every row in a user-backed allocation must be aligned by this amount
 #define RS_CPU_ALLOCATION_ALIGNMENT 16
@@ -62,7 +64,13 @@
 
     void finish();
 
+    static dispatchTable* dispatch;
+
  private:
+    static void* librs;
+
+    static bool initDispatch(int targetApi);
+
     bool init(int targetApi, bool forceCpu, bool synchronous);
     static void * threadProc(void *);
 
@@ -78,6 +86,7 @@
 
     ErrorHandlerFunc_t mErrorFunc;
     MessageHandlerFunc_t mMessageFunc;
+    bool mInit;
 
     struct {
         Element *U8;
diff --git a/cpp/rsDispatch.h b/cpp/rsDispatch.h
new file mode 100644
index 0000000..133572e
--- /dev/null
+++ b/cpp/rsDispatch.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RSDISPATCH_H
+#define ANDROID_RSDISPATCH_H
+
+#include "rsDefines.h"
+
+typedef const void* (*AllocationGetTypeFnPtr)(RsContext con, RsAllocation va);
+typedef void (*TypeGetNativeDataFnPtr)(RsContext, RsType, uint32_t *typeData, uint32_t typeDataSize);
+typedef void (*ElementGetNativeDataFnPtr)(RsContext, RsElement, uint32_t *elemData, uint32_t elemDataSize);
+typedef void (*ElementGetSubElementsFnPtr)(RsContext, RsElement, uint32_t *ids, const char **names, uint32_t *arraySizes, uint32_t dataSize);
+typedef RsDevice (*DeviceCreateFnPtr) ();
+typedef void (*DeviceDestroyFnPtr) (RsDevice dev);
+typedef void (*DeviceSetConfigFnPtr) (RsDevice dev, RsDeviceParam p, int32_t value);
+typedef RsContext (*ContextCreateFnPtr)(RsDevice vdev, uint32_t version, uint32_t sdkVersion, RsContextType ct, bool forceCpu, bool synchronous);
+typedef void (*ContextDestroyFnPtr) (RsContext);
+typedef RsMessageToClientType (*ContextGetMessageFnPtr) (RsContext, void*, size_t, size_t*, size_t, uint32_t*, size_t);
+typedef RsMessageToClientType (*ContextPeekMessageFnPtr) (RsContext, size_t*, size_t, uint32_t*, size_t);
+typedef void (*ContextSendMessageFnPtr) (RsContext, uint32_t, const uint8_t*, size_t);
+typedef void (*ContextInitToClientFnPtr) (RsContext);
+typedef void (*ContextDeinitToClientFnPtr) (RsContext);
+typedef RsType (*TypeCreateFnPtr) (RsContext, RsElement, uint32_t, uint32_t, uint32_t, bool, bool, uint32_t);
+typedef RsAllocation (*AllocationCreateTypedFnPtr) (RsContext, RsType, RsAllocationMipmapControl, uint32_t, uintptr_t);
+typedef RsAllocation (*AllocationCreateFromBitmapFnPtr) (RsContext, RsType, RsAllocationMipmapControl, const void*, size_t, uint32_t);
+typedef RsAllocation (*AllocationCubeCreateFromBitmapFnPtr) (RsContext, RsType, RsAllocationMipmapControl, const void*, size_t, uint32_t);
+typedef RsNativeWindow (*AllocationGetSurfaceFnPtr) (RsContext, RsAllocation);
+typedef void (*AllocationSetSurfaceFnPtr) (RsContext, RsAllocation, RsNativeWindow);
+typedef void (*ContextFinishFnPtr) (RsContext);
+typedef void (*ContextDumpFnPtr) (RsContext, int32_t);
+typedef void (*ContextSetPriorityFnPtr) (RsContext, int32_t);
+typedef void (*AssignNameFnPtr) (RsContext, RsObjectBase, const char*, size_t);
+typedef void (*ObjDestroyFnPtr) (RsContext, RsAsyncVoidPtr);
+typedef RsElement (*ElementCreateFnPtr) (RsContext, RsDataType, RsDataKind, bool, uint32_t);
+typedef RsElement (*ElementCreate2FnPtr) (RsContext, const RsElement*, size_t, const char**, size_t, const size_t*, const uint32_t*, size_t);
+typedef void (*AllocationCopyToBitmapFnPtr) (RsContext, RsAllocation, void*, size_t);
+typedef void (*Allocation1DDataFnPtr) (RsContext, RsAllocation, uint32_t, uint32_t, uint32_t, const void*, size_t);
+typedef void (*Allocation1DElementDataFnPtr) (RsContext, RsAllocation, uint32_t, uint32_t, const void*, size_t, size_t);
+typedef void (*Allocation2DDataFnPtr) (RsContext, RsAllocation, uint32_t, uint32_t, uint32_t, RsAllocationCubemapFace, uint32_t, uint32_t, const void*, size_t, size_t);
+typedef void (*Allocation3DDataFnPtr) (RsContext, RsAllocation, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, const void*, size_t, size_t);
+typedef void (*AllocationGenerateMipmapsFnPtr) (RsContext, RsAllocation);
+typedef void (*AllocationReadFnPtr) (RsContext, RsAllocation, void*, size_t);
+typedef void (*Allocation1DReadFnPtr) (RsContext, RsAllocation, uint32_t, uint32_t, uint32_t, void*, size_t);
+typedef void (*Allocation2DReadFnPtr) (RsContext, RsAllocation, uint32_t, uint32_t, uint32_t, RsAllocationCubemapFace, uint32_t, uint32_t, void*, size_t, size_t);
+typedef void (*AllocationSyncAllFnPtr) (RsContext, RsAllocation, RsAllocationUsageType);
+typedef void (*AllocationResize1DFnPtr) (RsContext, RsAllocation, uint32_t);
+typedef void (*AllocationCopy2DRangeFnPtr) (RsContext, RsAllocation, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, RsAllocation, uint32_t, uint32_t, uint32_t, uint32_t);
+typedef void (*AllocationCopy3DRangeFnPtr) (RsContext, RsAllocation, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, RsAllocation, uint32_t, uint32_t, uint32_t, uint32_t);
+typedef RsSampler (*SamplerCreateFnPtr) (RsContext, RsSamplerValue, RsSamplerValue, RsSamplerValue, RsSamplerValue, RsSamplerValue, float);
+typedef void (*ScriptBindAllocationFnPtr) (RsContext, RsScript, RsAllocation, uint32_t);
+typedef void (*ScriptSetTimeZoneFnPtr) (RsContext, RsScript, const char*, size_t);
+typedef void (*ScriptInvokeFnPtr) (RsContext, RsScript, uint32_t);
+typedef void (*ScriptInvokeVFnPtr) (RsContext, RsScript, uint32_t, const void*, size_t);
+typedef void (*ScriptForEachFnPtr) (RsContext, RsScript, uint32_t, RsAllocation, RsAllocation, const void*, size_t, const RsScriptCall*, size_t);
+typedef void (*ScriptSetVarIFnPtr) (RsContext, RsScript, uint32_t, int);
+typedef void (*ScriptSetVarObjFnPtr) (RsContext, RsScript, uint32_t, RsObjectBase);
+typedef void (*ScriptSetVarJFnPtr) (RsContext, RsScript, uint32_t, int64_t);
+typedef void (*ScriptSetVarFFnPtr) (RsContext, RsScript, uint32_t, float);
+typedef void (*ScriptSetVarDFnPtr) (RsContext, RsScript, uint32_t, double);
+typedef void (*ScriptSetVarVFnPtr) (RsContext, RsScript, uint32_t, const void*, size_t);
+typedef void (*ScriptGetVarVFnPtr) (RsContext, RsScript, uint32_t, void*, size_t);
+typedef void (*ScriptSetVarVEFnPtr) (RsContext, RsScript, uint32_t, const void*, size_t, RsElement, const size_t*, size_t);
+typedef RsScript (*ScriptCCreateFnPtr) (RsContext, const char*, size_t, const char*, size_t, const char*, size_t);
+typedef RsScript (*ScriptIntrinsicCreateFnPtr) (RsContext, uint32_t id, RsElement);
+typedef RsScriptKernelID (*ScriptKernelIDCreateFnPtr) (RsContext, RsScript, int, int);
+typedef RsScriptFieldID (*ScriptFieldIDCreateFnPtr) (RsContext, RsScript, int);
+typedef RsScriptGroup (*ScriptGroupCreateFnPtr) (RsContext, RsScriptKernelID*, size_t, RsScriptKernelID*, size_t, RsScriptKernelID*, size_t, RsScriptFieldID*, size_t, const RsType*, size_t);
+typedef void (*ScriptGroupSetOutputFnPtr) (RsContext, RsScriptGroup, RsScriptKernelID, RsAllocation);
+typedef void (*ScriptGroupSetInputFnPtr) (RsContext, RsScriptGroup, RsScriptKernelID, RsAllocation);
+typedef void (*ScriptGroupExecuteFnPtr) (RsContext, RsScriptGroup);
+typedef void (*AllocationIoSendFnPtr) (RsContext, RsAllocation);
+typedef void (*AllocationIoReceiveFnPtr) (RsContext, RsAllocation);
+
+typedef struct {
+    // inserted by hand from rs.h
+    AllocationGetTypeFnPtr AllocationGetType;
+    TypeGetNativeDataFnPtr TypeGetNativeData;
+    ElementGetNativeDataFnPtr ElementGetNativeData;
+    ElementGetSubElementsFnPtr ElementGetSubElements;
+
+
+    DeviceCreateFnPtr DeviceCreate;
+    DeviceDestroyFnPtr DeviceDestroy;
+    DeviceSetConfigFnPtr DeviceSetConfig;
+    ContextCreateFnPtr ContextCreate;
+
+    // generated from rs.spec
+    ContextDestroyFnPtr ContextDestroy;
+    ContextGetMessageFnPtr ContextGetMessage;
+    ContextPeekMessageFnPtr ContextPeekMessage;
+    ContextSendMessageFnPtr ContextSendMessage;
+    ContextInitToClientFnPtr ContextInitToClient;
+    ContextDeinitToClientFnPtr ContextDeinitToClient;
+    TypeCreateFnPtr TypeCreate;
+    AllocationCreateTypedFnPtr AllocationCreateTyped;
+    AllocationCreateFromBitmapFnPtr AllocationCreateFromBitmap;
+    AllocationCubeCreateFromBitmapFnPtr AllocationCubeCreateFromBitmap;
+    AllocationGetSurfaceFnPtr AllocationGetSurface;
+    AllocationSetSurfaceFnPtr AllocationSetSurface;
+    ContextFinishFnPtr ContextFinish;
+    ContextDumpFnPtr ContextDump;
+    ContextSetPriorityFnPtr ContextSetPriority;
+    AssignNameFnPtr AssignName;
+    ObjDestroyFnPtr ObjDestroy;
+    ElementCreateFnPtr ElementCreate;
+    ElementCreate2FnPtr ElementCreate2;
+    AllocationCopyToBitmapFnPtr AllocationCopyToBitmap;
+    Allocation1DDataFnPtr Allocation1DData;
+    Allocation1DElementDataFnPtr Allocation1DElementData;
+    Allocation2DDataFnPtr Allocation2DData;
+    Allocation3DDataFnPtr Allocation3DData;
+    AllocationGenerateMipmapsFnPtr AllocationGenerateMipmaps;
+    AllocationReadFnPtr AllocationRead;
+    Allocation1DReadFnPtr Allocation1DRead;
+    Allocation2DReadFnPtr Allocation2DRead;
+    AllocationSyncAllFnPtr AllocationSyncAll;
+    AllocationResize1DFnPtr AllocationResize1D;
+    AllocationCopy2DRangeFnPtr AllocationCopy2DRange;
+    AllocationCopy3DRangeFnPtr AllocationCopy3DRange;
+    SamplerCreateFnPtr SamplerCreate;
+    ScriptBindAllocationFnPtr ScriptBindAllocation;
+    ScriptSetTimeZoneFnPtr ScriptSetTimeZone;
+    ScriptInvokeFnPtr ScriptInvoke;
+    ScriptInvokeVFnPtr ScriptInvokeV;
+    ScriptForEachFnPtr ScriptForEach;
+    ScriptSetVarIFnPtr ScriptSetVarI;
+    ScriptSetVarObjFnPtr ScriptSetVarObj;
+    ScriptSetVarJFnPtr ScriptSetVarJ;
+    ScriptSetVarFFnPtr ScriptSetVarF;
+    ScriptSetVarDFnPtr ScriptSetVarD;
+    ScriptSetVarVFnPtr ScriptSetVarV;
+    ScriptGetVarVFnPtr ScriptGetVarV;
+    ScriptSetVarVEFnPtr ScriptSetVarVE;
+    ScriptCCreateFnPtr ScriptCCreate;
+    ScriptIntrinsicCreateFnPtr ScriptIntrinsicCreate;
+    ScriptKernelIDCreateFnPtr ScriptKernelIDCreate;
+    ScriptFieldIDCreateFnPtr ScriptFieldIDCreate;
+    ScriptGroupCreateFnPtr ScriptGroupCreate;
+    ScriptGroupSetOutputFnPtr ScriptGroupSetOutput;
+    ScriptGroupSetInputFnPtr ScriptGroupSetInput;
+    ScriptGroupExecuteFnPtr ScriptGroupExecute;
+    AllocationIoSendFnPtr AllocationIoSend;
+    AllocationIoReceiveFnPtr AllocationIoReceive;
+} dispatchTable;
+
+#endif