Implement IO_OUTPUT + SurfaceTexture

Change-Id: Id96fecd6d768196523330c5eda77c4ee86b9bd3c
diff --git a/driver/rsdAllocation.cpp b/driver/rsdAllocation.cpp
index f358f93..324eaf6 100644
--- a/driver/rsdAllocation.cpp
+++ b/driver/rsdAllocation.cpp
@@ -263,6 +263,9 @@
         drv->uploadDeferred = true;
     }
 
+    drv->width = alloc->getType()->getDimX();
+    drv->height = alloc->getType()->getDimY();
+
     drv->readBackFBO = NULL;
 
     return true;
@@ -371,7 +374,8 @@
     if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
         UploadToTexture(rsc, alloc);
     } else {
-        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
+        if ((alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) &&
+                ~(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT)) {
             AllocateRenderTarget(rsc, alloc);
         }
     }
@@ -418,6 +422,7 @@
             GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN,
             bounds, &dst);
     alloc->mHal.drvState.mallocPtr = dst;
+
     return true;
 }
 
@@ -426,6 +431,13 @@
 
     //ALOGE("rsdAllocationSetSurfaceTexture %p  %p", alloc, nw);
 
+    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
+        //TODO finish support for render target + script
+        drv->wnd = nw;
+        return;
+    }
+
+
     // Cleanup old surface if there is one.
     if (alloc->mHal.state.wndSurface) {
         ANativeWindow *old = alloc->mHal.state.wndSurface;
@@ -436,8 +448,15 @@
 
     if (nw != NULL) {
         int32_t r;
-        r = native_window_set_usage(nw, GRALLOC_USAGE_SW_READ_RARELY |
-                                        GRALLOC_USAGE_SW_WRITE_OFTEN);
+        uint32_t flags = 0;
+        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) {
+            flags |= GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
+        }
+        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
+            flags |= GRALLOC_USAGE_HW_RENDER;
+        }
+
+        r = native_window_set_usage(nw, flags);
         if (r) {
             rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer usage.");
             return;
@@ -464,15 +483,23 @@
     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.");
+    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
+        RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+        RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
         return;
     }
 
-    IoGetBuffer(rsc, alloc, nw);
+    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) {
+        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) {
diff --git a/driver/rsdAllocation.h b/driver/rsdAllocation.h
index e3a5126..bd5151b 100644
--- a/driver/rsdAllocation.h
+++ b/driver/rsdAllocation.h
@@ -40,6 +40,8 @@
     uint32_t renderTargetID;
 
     uint8_t * mallocPtr;
+    uint32_t width;
+    uint32_t height;
 
     GLenum glTarget;
     GLenum glType;
@@ -48,6 +50,7 @@
     bool uploadDeferred;
 
     RsdFrameBufferObj * readBackFBO;
+    ANativeWindow *wnd;
     ANativeWindowBuffer *wndBuffer;
 };
 
diff --git a/driver/rsdFrameBufferObj.cpp b/driver/rsdFrameBufferObj.cpp
index 91452b0..afdf9b8 100644
--- a/driver/rsdFrameBufferObj.cpp
+++ b/driver/rsdFrameBufferObj.cpp
@@ -18,6 +18,7 @@
 #include "rsdFrameBufferObj.h"
 #include "rsdAllocation.h"
 #include "rsdGL.h"
+#include "rsdCore.h"
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
@@ -122,23 +123,33 @@
 }
 
 void RsdFrameBufferObj::setActive(const Context *rsc) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
     bool framebuffer = renderToFramebuffer();
-    if (!framebuffer) {
-        if(mFBOId == 0) {
-            RSD_CALL_GL(glGenFramebuffers, 1, &mFBOId);
-        }
-        RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, mFBOId);
 
-        if (mDirty) {
-            setDepthAttachment();
-            setColorAttachment();
-            mDirty = false;
-        }
-
-        RSD_CALL_GL(glViewport, 0, 0, mWidth, mHeight);
-        checkError(rsc);
+    if(mColorTargets[0] && mColorTargets[0]->wnd) {
+        rsdGLSetInternalSurface(rsc, mColorTargets[0]->wnd);
     } else {
-        RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, 0);
-        RSD_CALL_GL(glViewport, 0, 0, rsc->getWidth(), rsc->getHeight());
+        if (!framebuffer) {
+            if(mFBOId == 0) {
+                RSD_CALL_GL(glGenFramebuffers, 1, &mFBOId);
+            }
+            RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, mFBOId);
+
+            if (mDirty) {
+                setDepthAttachment();
+                setColorAttachment();
+                mDirty = false;
+            }
+
+            RSD_CALL_GL(glViewport, 0, 0, mWidth, mHeight);
+            checkError(rsc);
+        } else {
+            if(dc->gl.wndSurface != dc->gl.currentWndSurface) {
+                rsdGLSetInternalSurface(rsc, dc->gl.wndSurface);
+            } else {
+                RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, 0);
+            }
+            RSD_CALL_GL(glViewport, 0, 0, rsc->getWidth(), rsc->getHeight());
+        }
     }
 }
diff --git a/driver/rsdGL.cpp b/driver/rsdGL.cpp
index e308adb..a935e6f 100644
--- a/driver/rsdGL.cpp
+++ b/driver/rsdGL.cpp
@@ -424,13 +424,11 @@
 }
 
 
-bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) {
+bool rsdGLSetInternalSurface(const Context *rsc, RsNativeWindow sur) {
     RsdHal *dc = (RsdHal *)rsc->mHal.drv;
 
     EGLBoolean ret;
-    // WAR: Some drivers fail to handle 0 size surfaces correcntly.
-    // Use the pbuffer to avoid this pitfall.
-    if ((dc->gl.egl.surface != NULL) || (w == 0) || (h == 0)) {
+    if (dc->gl.egl.surface != NULL) {
         rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
         ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
                              dc->gl.egl.surfaceDefault, dc->gl.egl.context);
@@ -441,23 +439,19 @@
         checkEglError("eglDestroySurface", ret);
 
         dc->gl.egl.surface = NULL;
-        dc->gl.width = 1;
-        dc->gl.height = 1;
     }
 
-    if (dc->gl.wndSurface != NULL) {
-        dc->gl.wndSurface->decStrong(NULL);
+    if (dc->gl.currentWndSurface != NULL) {
+        dc->gl.currentWndSurface->decStrong(NULL);
     }
 
-    dc->gl.wndSurface = (ANativeWindow *)sur;
-    if (dc->gl.wndSurface != NULL) {
-        dc->gl.wndSurface->incStrong(NULL);
-        dc->gl.width = w;
-        dc->gl.height = h;
+    dc->gl.currentWndSurface = (ANativeWindow *)sur;
+    if (dc->gl.currentWndSurface != NULL) {
+        dc->gl.currentWndSurface->incStrong(NULL);
 
         rsc->setWatchdogGL("eglCreateWindowSurface", __LINE__, __FILE__);
         dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config,
-                                                    dc->gl.wndSurface, NULL);
+                                                    dc->gl.currentWndSurface, NULL);
         checkEglError("eglCreateWindowSurface");
         if (dc->gl.egl.surface == EGL_NO_SURFACE) {
             ALOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
@@ -472,6 +466,25 @@
     return true;
 }
 
+bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) {
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+    if (dc->gl.wndSurface != NULL) {
+        dc->gl.wndSurface->decStrong(NULL);
+        dc->gl.wndSurface = NULL;
+    }
+    if(w && h) {
+        // WAR: Some drivers fail to handle 0 size surfaces correctly. Use the
+        // pbuffer to avoid this pitfall.
+        dc->gl.wndSurface = (ANativeWindow *)sur;
+        if (dc->gl.wndSurface != NULL) {
+            dc->gl.wndSurface->incStrong(NULL);
+        }
+    }
+
+    return rsdGLSetInternalSurface(rsc, sur);
+}
+
 void rsdGLSwap(const android::renderscript::Context *rsc) {
     RsdHal *dc = (RsdHal *)rsc->mHal.drv;
     RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
diff --git a/driver/rsdGL.h b/driver/rsdGL.h
index 1e5b40f..419c317 100644
--- a/driver/rsdGL.h
+++ b/driver/rsdGL.h
@@ -67,14 +67,15 @@
     } gl;
 
     ANativeWindow *wndSurface;
-    uint32_t width;
-    uint32_t height;
+    ANativeWindow *currentWndSurface;
+
     RsdShaderCache *shaderCache;
     RsdVertexArrayState *vertexArrayState;
     RsdFrameBufferObj *currentFrameBuffer;
 } RsdGL;
 
-
+bool rsdGLSetInternalSurface(const android::renderscript::Context *rsc,
+                             RsNativeWindow sur);
 bool rsdGLInit(const android::renderscript::Context *rsc);
 void rsdGLShutdown(const android::renderscript::Context *rsc);
 bool rsdGLSetSurface(const android::renderscript::Context *rsc,
diff --git a/driver/rsdRuntimeStubs.cpp b/driver/rsdRuntimeStubs.cpp
index aa9f159..779076d 100644
--- a/driver/rsdRuntimeStubs.cpp
+++ b/driver/rsdRuntimeStubs.cpp
@@ -26,6 +26,7 @@
 
 #include "rsdRuntime.h"
 #include "rsdPath.h"
+#include "rsdAllocation.h"
 
 #include <time.h>
 
@@ -80,6 +81,18 @@
                              srcXoff, srcYoff, srcMip, srcFace);
 }
 
+static void SC_AllocationIoSend(Allocation *alloc) {
+    GET_TLS();
+    rsdAllocationIoSend(rsc, alloc);
+}
+
+
+static void SC_AllocationIoReceive(Allocation *alloc) {
+    GET_TLS();
+    rsdAllocationIoReceive(rsc, alloc);
+}
+
+
 
 //////////////////////////////////////////////////////////////////////////////
 // Context
@@ -586,7 +599,8 @@
     { "_Z20rsgAllocationSyncAll13rs_allocationj", (void *)&SC_AllocationSyncAll2, false },
     { "_Z20rsgAllocationSyncAll13rs_allocation24rs_allocation_usage_type", (void *)&SC_AllocationSyncAll2, false },
     { "_Z15rsGetAllocationPKv", (void *)&SC_GetAllocation, true },
-
+    { "_Z18rsAllocationIoSend13rs_allocation", (void *)&SC_AllocationIoSend, false },
+    { "_Z21rsAllocationIoReceive13rs_allocation", (void *)&SC_AllocationIoReceive, false },
     { "_Z23rsAllocationCopy1DRange13rs_allocationjjjS_jj", (void *)&SC_AllocationCopy1DRange, false },
     { "_Z23rsAllocationCopy2DRange13rs_allocationjjj26rs_allocation_cubemap_facejjS_jjjS0_", (void *)&SC_AllocationCopy2DRange, false },
 
diff --git a/driver/rsdShader.cpp b/driver/rsdShader.cpp
index 6d9fa90..d39bdb8 100644
--- a/driver/rsdShader.cpp
+++ b/driver/rsdShader.cpp
@@ -480,23 +480,28 @@
         }
 
         DrvAllocation *drvTex = (DrvAllocation *)mRSProgram->mHal.state.textures[ct]->mHal.drv;
-        if (drvTex->glTarget != GL_TEXTURE_2D &&
-            drvTex->glTarget != GL_TEXTURE_CUBE_MAP &&
-            drvTex->glTarget != GL_TEXTURE_EXTERNAL_OES) {
+
+        if (mCurrentState->mTextureTargets[ct] != GL_TEXTURE_2D &&
+            mCurrentState->mTextureTargets[ct] != GL_TEXTURE_CUBE_MAP &&
+            mCurrentState->mTextureTargets[ct] != GL_TEXTURE_EXTERNAL_OES) {
             ALOGE("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");
         }
-        RSD_CALL_GL(glBindTexture, drvTex->glTarget, drvTex->textureID);
+        RSD_CALL_GL(glBindTexture, mCurrentState->mTextureTargets[ct], drvTex->textureID);
         rsdGLCheckError(rsc, "ProgramFragment::setup tex bind");
         if (mRSProgram->mHal.state.samplers[ct]) {
             setupSampler(rsc, mRSProgram->mHal.state.samplers[ct],
                          mRSProgram->mHal.state.textures[ct]);
         } else {
-            RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-            RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-            RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-            RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+            RSD_CALL_GL(glTexParameteri, mCurrentState->mTextureTargets[ct],
+                GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+            RSD_CALL_GL(glTexParameteri, mCurrentState->mTextureTargets[ct],
+                GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+            RSD_CALL_GL(glTexParameteri, mCurrentState->mTextureTargets[ct],
+                GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+            RSD_CALL_GL(glTexParameteri, mCurrentState->mTextureTargets[ct],
+                GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
             rsdGLCheckError(rsc, "ProgramFragment::setup tex env");
         }
         rsdGLCheckError(rsc, "ProgramFragment::setup uniforms");