Beging IO stream out from allocation to surface texture.

Change-Id: I4d6b7f7740a896d39b811d6fe7532bb00db62373
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 44401c8..37a270e 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -102,7 +102,7 @@
     public static final int USAGE_SCRIPT = 0x0001;
 
     /**
-     * GRAPHICS_TEXTURE The allcation will be used as a texture
+     * GRAPHICS_TEXTURE The allocation will be used as a texture
      * source by one or more graphics programs.
      *
      */
@@ -124,34 +124,34 @@
     public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008;
 
     /**
-     * USAGE_GRAPHICS_RENDER_TARGET The allcation will be used as a
+     * USAGE_GRAPHICS_RENDER_TARGET The allocation will be used as a
      * target for offscreen rendering
      *
      */
     public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010;
 
     /**
-     * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allocation will be
-     * used with a SurfaceTexture object.  This usage will cause the
-     * allocation to be created read only.
+     * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE The allocation
+     * will be used as a SurfaceTexture graphics consumer. This
+     * usage may only be used with USAGE_GRAPHICS_TEXTURE.
      *
      * @hide
      */
     public static final int USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020;
 
     /**
-     * USAGE_IO_INPUT The allocation will be
-     * used with a SurfaceTexture object.  This usage will cause the
-     * allocation to be created read only.
+     * USAGE_IO_INPUT The allocation will be used as SurfaceTexture
+     * consumer.  This usage will cause the allocation to be created
+     * read only.
      *
      * @hide
      */
     public static final int USAGE_IO_INPUT = 0x0040;
 
     /**
-     * USAGE_IO_OUTPUT The allocation will be
-     * used with a SurfaceTexture object.  This usage will cause the
-     * allocation to be created write only.
+     * USAGE_IO_OUTPUT The allocation will be used as a
+     * SurfaceTexture producer.  The dimensions and format of the
+     * SurfaceTexture will be forced to those of the allocation.
      *
      * @hide
      */
@@ -323,6 +323,37 @@
         mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
     }
 
+    /**
+     * Send a buffer to the output stream.  The contents of the
+     * Allocation will be undefined after this operation.
+     *
+     * @hide
+     *
+     */
+    public void ioSendOutput() {
+        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
+            throw new RSIllegalArgumentException(
+                "Can only send buffer if IO_OUTPUT usage specified.");
+        }
+        mRS.validate();
+        mRS.nAllocationIoSend(getID());
+    }
+
+    /**
+     * Receive the latest input into the Allocation.
+     *
+     * @hide
+     *
+     */
+    public void ioGetInput() {
+        if ((mUsage & USAGE_IO_INPUT) == 0) {
+            throw new RSIllegalArgumentException(
+                "Can only send buffer if IO_OUTPUT usage specified.");
+        }
+        mRS.validate();
+        mRS.nAllocationIoReceive(getID());
+    }
+
     public void copyFrom(BaseObj[] d) {
         mRS.validate();
         validateIsObject();
@@ -887,17 +918,37 @@
         updateCacheInfo(mType);
     }
 
-    /*
+    /**
+     * Resize a 2D allocation.  The contents of the allocation are
+     * preserved.  If new elements are allocated objects are created
+     * with null contents and the new region is otherwise undefined.
+     *
+     * If the new region is smaller the references of any objects
+     * outside the new region will be released.
+     *
+     * A new type will be created with the new dimension.
+     *
+     * @hide
+     * @param dimX The new size of the allocation.
+     * @param dimY The new size of the allocation.
+     */
     public void resize(int dimX, int dimY) {
-        if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
-            throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
+        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 RSIllegalStateException("Resize only support for 2D allocations at this time.");
+            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);
     }
-    */
 
 
 
@@ -1090,6 +1141,18 @@
 
     }
 
+    /**
+     * @hide
+     */
+    public void setSurfaceTexture(SurfaceTexture sur) {
+        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
+            throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
+        }
+
+        mRS.validate();
+        mRS.nAllocationSetSurfaceTexture(getID(), sur);
+    }
+
 
     /**
      * Creates a non-mipmapped renderscript allocation to use as a
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index d3c801f2..56303f7 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -274,6 +274,22 @@
         validate();
         return rsnAllocationGetSurfaceTextureID(mContext, alloc);
     }
+    native void rsnAllocationSetSurfaceTexture(int con, int alloc, SurfaceTexture sur);
+    synchronized void nAllocationSetSurfaceTexture(int alloc, SurfaceTexture sur) {
+        validate();
+        rsnAllocationSetSurfaceTexture(mContext, alloc, sur);
+    }
+    native void rsnAllocationIoSend(int con, int alloc);
+    synchronized void nAllocationIoSend(int alloc) {
+        validate();
+        rsnAllocationIoSend(mContext, alloc);
+    }
+    native void rsnAllocationIoReceive(int con, int alloc);
+    synchronized void nAllocationIoReceive(int alloc) {
+        validate();
+        rsnAllocationIoReceive(mContext, alloc);
+    }
+
 
     native void rsnAllocationGenerateMipmaps(int con, int alloc);
     synchronized void nAllocationGenerateMipmaps(int alloc) {
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 94f19b3..4d087b0 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -451,6 +451,37 @@
 }
 
 static void
+nAllocationSetSurfaceTexture(JNIEnv *_env, jobject _this, RsContext con,
+                             RsAllocation alloc, jobject sur)
+{
+    LOG_API("nAllocationSetSurfaceTexture, con(%p), alloc(%p), surface(%p)",
+            con, alloc, (Surface *)sur);
+
+    sp<ANativeWindow> window;
+    if (sur != 0) {
+        sp<SurfaceTexture> st = SurfaceTexture_getSurfaceTexture(_env, sur);
+        window = new SurfaceTextureClient(st);
+    }
+
+    rsAllocationSetSurface(con, alloc, window.get());
+}
+
+static void
+nAllocationIoSend(JNIEnv *_env, jobject _this, RsContext con, RsAllocation alloc)
+{
+    LOG_API("nAllocationIoSend, con(%p), alloc(%p)", con, alloc);
+    rsAllocationIoSend(con, alloc);
+}
+
+static void
+nAllocationIoReceive(JNIEnv *_env, jobject _this, RsContext con, RsAllocation alloc)
+{
+    LOG_API("nAllocationIoReceive, con(%p), alloc(%p)", con, alloc);
+    rsAllocationIoReceive(con, alloc);
+}
+
+
+static void
 nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, RsContext con, jint alloc)
 {
     LOG_API("nAllocationGenerateMipmaps, con(%p), a(%p)", con, (RsAllocation)alloc);
@@ -1277,6 +1308,9 @@
 
 {"rsnAllocationSyncAll",             "(III)V",                                (void*)nAllocationSyncAll },
 {"rsnAllocationGetSurfaceTextureID", "(II)I",                                 (void*)nAllocationGetSurfaceTextureID },
+{"rsnAllocationSetSurfaceTexture",   "(IILandroid/graphics/SurfaceTexture;)V", (void*)nAllocationSetSurfaceTexture },
+{"rsnAllocationIoSend",              "(II)V",                                 (void*)nAllocationIoSend },
+{"rsnAllocationIoReceive",           "(II)V",                                 (void*)nAllocationIoReceive },
 {"rsnAllocationData1D",              "(IIIII[II)V",                           (void*)nAllocationData1D_i },
 {"rsnAllocationData1D",              "(IIIII[SI)V",                           (void*)nAllocationData1D_s },
 {"rsnAllocationData1D",              "(IIIII[BI)V",                           (void*)nAllocationData1D_b },
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index ea92192..b673a0a 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -23,6 +23,11 @@
 
 #include "rsAllocation.h"
 
+#include "system/window.h"
+#include "hardware/gralloc.h"
+#include "ui/Rect.h"
+#include "ui/GraphicBufferMapper.h"
+
 #include <GLES/gl.h>
 #include <GLES2/gl2.h>
 #include <GLES/glext.h>
@@ -220,7 +225,8 @@
     }
 
     void * ptr = alloc->mHal.state.usrPtr;
-    if (!ptr) {
+    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT) {
+    } else {
         ptr = malloc(alloc->mHal.state.type->getSizeBytes());
         if (!ptr) {
             free(drv);
@@ -248,7 +254,7 @@
     alloc->mHal.drvState.mallocPtr = ptr;
     drv->mallocPtr = (uint8_t *)ptr;
     alloc->mHal.drv = drv;
-    if (forceZero) {
+    if (forceZero && ptr) {
         memset(ptr, 0, alloc->mHal.state.type->getSizeBytes());
     }
 
@@ -386,6 +392,93 @@
     return drv->textureID;
 }
 
+static bool IoGetBuffer(const Context *rsc, Allocation *alloc, ANativeWindow *nw) {
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+
+    int32_t r = nw->dequeueBuffer(nw, &drv->wndBuffer);
+    if (r) {
+        rsc->setError(RS_ERROR_DRIVER, "Error getting next IO output buffer.");
+        return false;
+    }
+
+    // This lock is implicitly released by the queue buffer in IoSend
+    r = nw->lockBuffer(nw, drv->wndBuffer);
+    if (r) {
+        rsc->setError(RS_ERROR_DRIVER, "Error locking next IO output buffer.");
+        return false;
+    }
+
+    // Must lock the whole surface
+    GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+    Rect bounds(drv->wndBuffer->width, drv->wndBuffer->height);
+
+    void *dst = NULL;
+    mapper.lock(drv->wndBuffer->handle,
+            GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN,
+            bounds, &dst);
+    alloc->mHal.drvState.mallocPtr = dst;
+    return true;
+}
+
+void rsdAllocationSetSurfaceTexture(const Context *rsc, Allocation *alloc, ANativeWindow *nw) {
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+
+    //ALOGE("rsdAllocationSetSurfaceTexture %p  %p", alloc, nw);
+
+    // Cleanup old surface if there is one.
+    if (alloc->mHal.state.wndSurface) {
+        ANativeWindow *old = alloc->mHal.state.wndSurface;
+        GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+        mapper.unlock(drv->wndBuffer->handle);
+        old->queueBuffer(old, drv->wndBuffer);
+    }
+
+    if (nw != NULL) {
+        int32_t r;
+        r = native_window_set_usage(nw, GRALLOC_USAGE_SW_READ_RARELY |
+                                        GRALLOC_USAGE_SW_WRITE_OFTEN);
+        if (r) {
+            rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer usage.");
+            return;
+        }
+
+        r = native_window_set_buffers_dimensions(nw, alloc->mHal.state.dimensionX,
+                                                 alloc->mHal.state.dimensionY);
+        if (r) {
+            rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer dimensions.");
+            return;
+        }
+
+        r = native_window_set_buffer_count(nw, 3);
+        if (r) {
+            rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer count.");
+            return;
+        }
+
+        IoGetBuffer(rsc, alloc, nw);
+    }
+}
+
+void rsdAllocationIoSend(const Context *rsc, Allocation *alloc) {
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+    ANativeWindow *nw = alloc->mHal.state.wndSurface;
+
+    GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+    mapper.unlock(drv->wndBuffer->handle);
+    int32_t r = nw->queueBuffer(nw, drv->wndBuffer);
+    if (r) {
+        rsc->setError(RS_ERROR_DRIVER, "Error sending IO output buffer.");
+        return;
+    }
+
+    IoGetBuffer(rsc, alloc, nw);
+}
+
+void rsdAllocationIoReceive(const Context *rsc, Allocation *alloc) {
+    ALOGE("not implemented");
+}
+
+
 void rsdAllocationData1D(const Context *rsc, const Allocation *alloc,
                          uint32_t xoff, uint32_t lod, uint32_t count,
                          const void *data, uint32_t sizeBytes) {
diff --git a/libs/rs/driver/rsdAllocation.h b/libs/rs/driver/rsdAllocation.h
index 230804b..e3a5126 100644
--- a/libs/rs/driver/rsdAllocation.h
+++ b/libs/rs/driver/rsdAllocation.h
@@ -24,6 +24,7 @@
 #include <GLES2/gl2.h>
 
 class RsdFrameBufferObj;
+struct ANativeWindowBuffer;
 
 struct DrvAllocation {
     // Is this a legal structure to be used as a texture source.
@@ -47,6 +48,7 @@
     bool uploadDeferred;
 
     RsdFrameBufferObj * readBackFBO;
+    ANativeWindowBuffer *wndBuffer;
 };
 
 GLenum rsdTypeToGLType(RsDataType t);
@@ -69,6 +71,12 @@
                             const android::renderscript::Allocation *alloc);
 int32_t rsdAllocationInitSurfaceTexture(const android::renderscript::Context *rsc,
                                         const android::renderscript::Allocation *alloc);
+void rsdAllocationSetSurfaceTexture(const android::renderscript::Context *rsc,
+                                    android::renderscript::Allocation *alloc, ANativeWindow *nw);
+void rsdAllocationIoSend(const android::renderscript::Context *rsc,
+                         android::renderscript::Allocation *alloc);
+void rsdAllocationIoReceive(const android::renderscript::Context *rsc,
+                            android::renderscript::Allocation *alloc);
 
 void rsdAllocationData1D(const android::renderscript::Context *rsc,
                          const android::renderscript::Allocation *alloc,
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index e011955..bf2b62a 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -74,6 +74,9 @@
         rsdAllocationSyncAll,
         rsdAllocationMarkDirty,
         rsdAllocationInitSurfaceTexture,
+        rsdAllocationSetSurfaceTexture,
+        rsdAllocationIoSend,
+        rsdAllocationIoReceive,
         rsdAllocationData1D,
         rsdAllocationData2D,
         rsdAllocationData3D,
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 6759bc7..491474e 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -69,6 +69,21 @@
     ret int32_t
 }
 
+AllocationSetSurface {
+    param RsAllocation alloc
+    param RsNativeWindow sur
+    sync
+    }
+
+AllocationIoSend {
+    param RsAllocation alloc
+    }
+
+AllocationIoReceive {
+    param RsAllocation alloc
+    }
+
+
 ContextFinish {
 	sync
 	}
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 02c6809..83c88fd 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -17,6 +17,7 @@
 #include "rsContext.h"
 #include "rs_hal.h"
 
+#include "system/window.h"
 
 using namespace android;
 using namespace android::renderscript;
@@ -44,6 +45,7 @@
         delete a;
         return NULL;
     }
+
     return a;
 }
 
@@ -420,6 +422,28 @@
     return id;
 }
 
+void Allocation::setSurface(const Context *rsc, RsNativeWindow sur) {
+    ANativeWindow *nw = (ANativeWindow *)sur;
+    ANativeWindow *old = mHal.state.wndSurface;
+    if (nw) {
+        nw->incStrong(NULL);
+    }
+    rsc->mHal.funcs.allocation.setSurfaceTexture(rsc, this, nw);
+    mHal.state.wndSurface = nw;
+    if (old) {
+        old->decStrong(NULL);
+    }
+}
+
+void Allocation::ioSend(const Context *rsc) {
+    rsc->mHal.funcs.allocation.ioSend(rsc, this);
+}
+
+void Allocation::ioReceive(const Context *rsc) {
+    rsc->mHal.funcs.allocation.ioReceive(rsc, this);
+}
+
+
 /////////////////
 //
 
@@ -670,6 +694,21 @@
     return alloc->getSurfaceTextureID(rsc);
 }
 
+void rsi_AllocationSetSurface(Context *rsc, RsAllocation valloc, RsNativeWindow sur) {
+    Allocation *alloc = static_cast<Allocation *>(valloc);
+    alloc->setSurface(rsc, sur);
+}
+
+void rsi_AllocationIoSend(Context *rsc, RsAllocation valloc) {
+    Allocation *alloc = static_cast<Allocation *>(valloc);
+    alloc->ioSend(rsc);
+}
+
+void rsi_AllocationIoReceive(Context *rsc, RsAllocation valloc) {
+    Allocation *alloc = static_cast<Allocation *>(valloc);
+    alloc->ioReceive(rsc);
+}
+
 }
 }
 
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 58a582b..58a6fca 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -19,6 +19,8 @@
 
 #include "rsType.h"
 
+struct ANativeWindow;
+
 // ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
@@ -57,6 +59,7 @@
             bool hasReferences;
             void * usrPtr;
             int32_t surfaceTextureID;
+            ANativeWindow *wndSurface;
         };
         State state;
 
@@ -127,6 +130,9 @@
     }
 
     int32_t getSurfaceTextureID(const Context *rsc);
+    void setSurface(const Context *rsc, RsNativeWindow sur);
+    void ioSend(const Context *rsc);
+    void ioReceive(const Context *rsc);
 
 protected:
     Vector<const Program *> mToDirtyList;
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 1e222e1..e48aa16 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -19,6 +19,8 @@
 
 #include <RenderScriptDefines.h>
 
+struct ANativeWindow;
+
 namespace android {
 namespace renderscript {
 
@@ -115,7 +117,11 @@
                        bool zeroNew);
         void (*syncAll)(const Context *rsc, const Allocation *alloc, RsAllocationUsageType src);
         void (*markDirty)(const Context *rsc, const Allocation *alloc);
+
         int32_t (*initSurfaceTexture)(const Context *rsc, const Allocation *alloc);
+        void (*setSurfaceTexture)(const Context *rsc, Allocation *alloc, ANativeWindow *sur);
+        void (*ioSend)(const Context *rsc, Allocation *alloc);
+        void (*ioReceive)(const Context *rsc, Allocation *alloc);
 
         void (*data1D)(const Context *rsc, const Allocation *alloc,
                        uint32_t xoff, uint32_t lod, uint32_t count,