Merge "New Script Group API for support library."
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java b/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java
index fb28eb0..7f87265 100644
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java
+++ b/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java
@@ -1211,6 +1211,11 @@
         if (type.getID(rs) == 0) {
             throw new RSInvalidStateException("Bad Type");
         }
+
+        if(!rs.usingIO() && (usage & (USAGE_IO_INPUT | USAGE_IO_INPUT)) != 0) {
+            throw new RSRuntimeException("USAGE_IO not supported, Allocation creation failed.");
+        }
+
         int id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
         if (id == 0) {
             throw new RSRuntimeException("Allocation creation failed.");
@@ -1366,6 +1371,20 @@
     }
 
     /**
+     * Associate a {@link android.view.Surface} with this Allocation. This
+     * operation is only valid for Allocations with {@link #USAGE_IO_OUTPUT}.
+     *
+     * @param sur Surface to associate with allocation
+     */
+    public void setSurface(Surface sur) {
+        mRS.validate();
+        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
+            throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
+        }
+        mRS.nAllocationSetSurface(getID(mRS), sur);
+    }
+
+    /**
      * Creates an Allocation from a {@link android.graphics.Bitmap}.
      *
      * <p>This Allocation will be created with {@link #USAGE_SHARED}, and
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java b/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
index f42022e..8cf9861 100644
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
+++ b/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
@@ -65,6 +65,7 @@
 
     // Non-threadsafe functions.
     native boolean nLoadSO(boolean useNative);
+    native boolean nLoadIOSO();
     native int  nDeviceCreate();
     native void nDeviceDestroy(int dev);
     native void nDeviceSetConfig(int dev, int param, int value);
@@ -76,6 +77,7 @@
 
     static private int sNative = -1;
     static private int sSdkVersion = -1;
+    static private boolean useIOlib = false;
 
     /**
      * Determines whether or not we should be thunking into the native
@@ -336,6 +338,13 @@
         validate();
         rsnAllocationSyncAll(mContext, alloc, src);
     }
+
+    native void rsnAllocationSetSurface(int con, int alloc, Surface sur);
+    synchronized void nAllocationSetSurface(int alloc, Surface sur) {
+        validate();
+        rsnAllocationSetSurface(mContext, alloc, sur);
+    }
+
     native void rsnAllocationIoSend(int con, int alloc);
     synchronized void nAllocationIoSend(int alloc) {
         validate();
@@ -839,7 +848,12 @@
         }
     }
 
-
+    /**
+     * check if IO support lib is available.
+     */
+    boolean usingIO() {
+        return useIOlib;
+    }
     /**
      * Change the priority of the worker threads for this context.
      *
@@ -998,7 +1012,11 @@
         } else {
             android.util.Log.v(LOG_TAG, "RS compat mode");
         }
-        if (!useNative || !rs.nLoadSO(useNative)) {
+
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            useIOlib = true;
+        }
+        if (!rs.nLoadSO(useNative)) {
             if (useNative) {
                 android.util.Log.v(LOG_TAG, "Unable to load libRS.so, falling back to compat mode");
             }
@@ -1013,6 +1031,13 @@
             }
         }
 
+        if (useIOlib) {
+            System.loadLibrary("RSSupportIO");
+            if (!rs.nLoadIOSO()) {
+                android.util.Log.v(LOG_TAG, "Unable to load libRSSupportIO.so, USAGE_IO not supported");
+                useIOlib = false;
+            }
+        }
         rs.mDev = rs.nDeviceCreate();
         rs.mContext = rs.nContextCreate(rs.mDev, 0, sdkVersion, ct.mID);
         if (rs.mContext == 0) {
diff --git a/v8/renderscript/jni/Android.mk b/v8/renderscript/jni/Android.mk
index aa08c9d..8c3e35e 100644
--- a/v8/renderscript/jni/Android.mk
+++ b/v8/renderscript/jni/Android.mk
@@ -2,6 +2,32 @@
 include $(CLEAR_VARS)
 
 LOCAL_CLANG := true
+LOCAL_SDK_VERSION := 14
+
+LOCAL_SRC_FILES:= \
+    android_rscompat_usage_io.cpp \
+    android_rscompat_usage_io_driver.cpp
+
+LOCAL_C_INCLUDES += \
+	$(JNI_H_INCLUDE) \
+	frameworks/rs \
+	frameworks/rs/cpp \
+	frameworks/rs/driver
+
+LOCAL_CFLAGS += -Wno-unused-parameter -U_FORTIFY_SOURCE
+LOCAL_CFLAGS += -DRS_COMPATIBILITY_LIB -std=c++11
+
+LOCAL_MODULE:= libRSSupportIO
+LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_LDLIBS += -landroid
+LOCAL_NDK_STL_VARIANT := stlport_static
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
 LOCAL_SDK_VERSION := 8
 
 LOCAL_SRC_FILES:= \
diff --git a/v8/renderscript/jni/android_renderscript_RenderScript.cpp b/v8/renderscript/jni/android_renderscript_RenderScript.cpp
index b62ffe5..536cbcb 100644
--- a/v8/renderscript/jni/android_renderscript_RenderScript.cpp
+++ b/v8/renderscript/jni/android_renderscript_RenderScript.cpp
@@ -23,9 +23,8 @@
 #include <math.h>
 #include <android/bitmap.h>
 #include <android/log.h>
-#include "jni.h"
-#include <rsEnv.h>
 
+#include <rsEnv.h>
 #include "rsDispatch.h"
 #include <dlfcn.h>
 
@@ -113,6 +112,20 @@
     return true;
 }
 
+static ioSuppDT ioDispatch;
+static jboolean nLoadIOSO(JNIEnv *_env, jobject _this) {
+    void* handleIO = NULL;
+    handleIO = dlopen("libRSSupportIO.so", RTLD_LAZY | RTLD_LOCAL);
+    if (handleIO == NULL) {
+        LOG_API("Couldn't load libRSSupportIO.so");
+        return false;
+    }
+    if (loadIOSuppSyms(handleIO, ioDispatch) == false) {
+        LOG_API("libRSSupportIO init failed!");
+        return false;
+    }
+    return true;
+}
 // ---------------------------------------------------------------------------
 
 static void
@@ -438,6 +451,18 @@
 }
 
 static void
+nAllocationSetSurface(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jobject sur)
+{
+    ioDispatch.sAllocationSetSurface(_env, _this, con, (RsAllocation)alloc, sur, dispatchTab);
+}
+
+static void
+nAllocationIoSend(JNIEnv *_env, jobject _this, RsContext con, jint alloc)
+{
+    dispatchTab.AllocationIoSend(con, (RsAllocation)alloc);
+}
+
+static void
 nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, RsContext con, jint alloc)
 {
     LOG_API("nAllocationGenerateMipmaps, con(%p), a(%p)", con, (RsAllocation)alloc);
@@ -1096,7 +1121,8 @@
 static const char *classPathName = "android/support/v8/renderscript/RenderScript";
 
 static JNINativeMethod methods[] = {
-{"nLoadSO",                        "(Z)Z",                                    (bool*)nLoadSO },
+{"nLoadSO",                        "(Z)Z",                                   (bool*)nLoadSO },
+{"nLoadIOSO",                      "()Z",                                     (bool*)nLoadIOSO },
 {"nDeviceCreate",                  "()I",                                     (void*)nDeviceCreate },
 {"nDeviceDestroy",                 "(I)V",                                    (void*)nDeviceDestroy },
 {"nDeviceSetConfig",               "(III)V",                                  (void*)nDeviceSetConfig },
@@ -1135,6 +1161,8 @@
 {"rsnAllocationCopyToBitmap",        "(IILandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyToBitmap },
 
 {"rsnAllocationSyncAll",             "(III)V",                                (void*)nAllocationSyncAll },
+{"rsnAllocationSetSurface",          "(IILandroid/view/Surface;)V",           (void*)nAllocationSetSurface },
+{"rsnAllocationIoSend",              "(II)V",                                 (void*)nAllocationIoSend },
 {"rsnAllocationData1D",              "(IIIII[II)V",                           (void*)nAllocationData1D_i },
 {"rsnAllocationData1D",              "(IIIII[SI)V",                           (void*)nAllocationData1D_s },
 {"rsnAllocationData1D",              "(IIIII[BI)V",                           (void*)nAllocationData1D_b },
diff --git a/v8/renderscript/jni/android_rscompat_usage_io.cpp b/v8/renderscript/jni/android_rscompat_usage_io.cpp
new file mode 100644
index 0000000..e29be1a
--- /dev/null
+++ b/v8/renderscript/jni/android_rscompat_usage_io.cpp
@@ -0,0 +1,20 @@
+#include <android/log.h>
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+
+#include <rsEnv.h>
+#include "rsDispatch.h"
+#define LOG_API(...)
+
+extern "C" void AllocationSetSurface(JNIEnv *_env, jobject _this, RsContext con, RsAllocation alloc, jobject sur, dispatchTable dispatchTab)
+{
+    LOG_API("nAllocationSetSurface, con(%p), alloc(%p), surface(%p)",
+            con, alloc, sur);
+
+    ANativeWindow* s = NULL;
+    if (sur != 0) {
+        s = ANativeWindow_fromSurface(_env, sur);
+    }
+    dispatchTab.AllocationSetSurface(con, alloc, s);
+}
+
diff --git a/v8/renderscript/jni/android_rscompat_usage_io_driver.cpp b/v8/renderscript/jni/android_rscompat_usage_io_driver.cpp
new file mode 100644
index 0000000..96eb19a
--- /dev/null
+++ b/v8/renderscript/jni/android_rscompat_usage_io_driver.cpp
@@ -0,0 +1,113 @@
+#include <android/native_window.h>
+#include <android/log.h>
+
+#include "rsCompatibilityLib.h"
+
+#include "rsdCore.h"
+#include "rsdAllocation.h"
+#include "rsAllocation.h"
+
+#define LOG_API(...)
+
+using namespace android;
+using namespace android::renderscript;
+
+static bool IoGetBuffer(const Context *rsc, Allocation *alloc, ANativeWindow *nw) {
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+    // Must lock the whole surface
+    if(drv->wndBuffer == NULL) {
+        drv->wndBuffer = new ANativeWindow_Buffer;
+    }
+    int32_t r = ANativeWindow_lock(nw, drv->wndBuffer, NULL);
+    if (r) {
+        LOG_API("Error Locking IO output buffer.");
+        return false;
+    }
+
+    void *dst = drv->wndBuffer->bits;
+    alloc->mHal.drvState.lod[0].mallocPtr = dst;
+    alloc->mHal.drvState.lod[0].stride = drv->wndBuffer->stride * alloc->mHal.state.elementSizeBytes;
+    return true;
+}
+
+extern "C" void rscAllocationSetSurface(RsContext rscR, RsAllocation allocR, ANativeWindow *nw) {
+    Context *rsc = (Context *)rscR;
+    Allocation *alloc = (Allocation *)allocR;
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+
+    // Cleanup old surface if there is one.
+    if (drv->wndSurface) {
+        ANativeWindow *old = drv->wndSurface;
+        ANativeWindow_unlockAndPost(old);
+        drv->wndSurface = NULL;
+        ANativeWindow_release(old);
+        old = NULL;
+    }
+
+    if (nw != NULL) {
+        int32_t r;
+        r = ANativeWindow_setBuffersGeometry(nw, alloc->mHal.drvState.lod[0].dimX,
+                                                 alloc->mHal.drvState.lod[0].dimY,
+                                                 WINDOW_FORMAT_RGBA_8888);
+        if (r) {
+            LOG_API("Error setting IO output buffer geometry.");
+            goto errorcmp;
+        }
+
+        IoGetBuffer(rsc, alloc, nw);
+        drv->wndSurface = nw;
+    }
+
+    return;
+
+ errorcmp:
+
+    if (nw) {
+        nw = NULL;
+    }
+
+}
+
+extern "C" void rscAllocationDestroy(const Context *rsc, Allocation *alloc) {
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+    if (alloc->mHal.drvState.lod[0].mallocPtr) {
+        // don't free user-allocated ptrs or IO_OUTPUT buffers
+        if (!(drv->useUserProvidedPtr) &&
+            !(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_INPUT) &&
+            !(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT)) {
+                free(alloc->mHal.drvState.lod[0].mallocPtr);
+        }
+        alloc->mHal.drvState.lod[0].mallocPtr = NULL;
+    }
+
+    if ((alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT) &&
+        (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
+        ANativeWindow *nw = drv->wndSurface;
+        if (nw) {
+            //If we have an attached surface, need to release it.
+            ANativeWindow_unlockAndPost(nw);
+            drv->wndSurface = NULL;
+            ANativeWindow_release(nw);
+            nw = NULL;
+        }
+    }
+}
+
+extern "C" void rscAllocationIoSend(const Context *rsc, Allocation *alloc) {
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+    ANativeWindow *nw = drv->wndSurface;
+    if (nw) {
+        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) {
+            int32_t r = ANativeWindow_unlockAndPost(nw);
+            if (r) {
+                LOG_API("Error sending IO output buffer.");
+                return;
+            }
+            IoGetBuffer(rsc, alloc, nw);
+        }
+    } else {
+        LOG_API("Sent IO buffer with no attached surface.");
+        return;
+    }
+}
+