Refactor hal to remove cpuConsumer from drivers

This CL should minimize build breaks due to
BufferQueue changes in the future.

Change-Id: I565a6eae5cc25603741fef32f2cfcb31a32eb757
diff --git a/Android.mk b/Android.mk
index 6d8956b..0f8bc99 100644
--- a/Android.mk
+++ b/Android.mk
@@ -125,6 +125,7 @@
 	rsFifoSocket.cpp \
 	rsFileA3D.cpp \
 	rsFont.cpp \
+	rsGrallocConsumer.cpp \
 	rsObjectBase.cpp \
 	rsMatrix2x2.cpp \
 	rsMatrix3x3.cpp \
diff --git a/cpu_ref/rsCpuScript.cpp b/cpu_ref/rsCpuScript.cpp
index 05c9a91..0d34d96 100644
--- a/cpu_ref/rsCpuScript.cpp
+++ b/cpu_ref/rsCpuScript.cpp
@@ -729,11 +729,11 @@
 
     // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
     if (ain && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) {
-        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
+        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null in allocations");
         return;
     }
     if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) {
-        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
+        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null out allocations");
         return;
     }
 
diff --git a/driver/rsdAllocation.cpp b/driver/rsdAllocation.cpp
index 1d34f08..19b080f 100644
--- a/driver/rsdAllocation.cpp
+++ b/driver/rsdAllocation.cpp
@@ -617,35 +617,6 @@
 }
 
 #ifndef RS_COMPATIBILITY_LIB
-void DrvAllocation::NewBufferListener::onFrameAvailable() {
-    intptr_t ip = (intptr_t)alloc;
-    rsc->sendMessageToClient(NULL, RS_MESSAGE_TO_CLIENT_NEW_BUFFER, ip, 0, true);
-}
-#endif
-
-void* rsdAllocationGetSurface(const Context *rsc, const Allocation *alloc) {
-#ifndef RS_COMPATIBILITY_LIB
-    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
-
-    // Configure CpuConsumer to be in asynchronous mode
-    sp<BufferQueue> bq = new BufferQueue();
-    drv->cpuConsumer = new CpuConsumer(bq, 2, false);
-    sp<IGraphicBufferProducer> bp = bq;
-    bp->incStrong(NULL);
-
-    drv->mBufferListener = new DrvAllocation::NewBufferListener();
-    drv->mBufferListener->rsc = rsc;
-    drv->mBufferListener->alloc = alloc;
-
-    drv->cpuConsumer->setFrameAvailableListener(drv->mBufferListener);
-
-    return bp.get();
-#else
-    return NULL;
-#endif
-}
-
-#ifndef RS_COMPATIBILITY_LIB
 static bool IoGetBuffer(const Context *rsc, Allocation *alloc, ANativeWindow *nw) {
     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
 
@@ -780,33 +751,9 @@
 void rsdAllocationIoReceive(const Context *rsc, Allocation *alloc) {
 #ifndef RS_COMPATIBILITY_LIB
     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
-
-    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) {
-        CpuConsumer::LockedBuffer lb;
-        status_t ret = drv->cpuConsumer->lockNextBuffer(&lb);
-        if (ret == OK) {
-            if (drv->lb.data != NULL) {
-                drv->cpuConsumer->unlockBuffer(drv->lb);
-            }
-            drv->lb = lb;
-            alloc->mHal.drvState.lod[0].mallocPtr = drv->lb.data;
-            alloc->mHal.drvState.lod[0].stride = drv->lb.stride *
-                    alloc->mHal.state.elementSizeBytes;
-
-            if (alloc->mHal.state.yuv) {
-                DeriveYUVLayout(alloc->mHal.state.yuv, &alloc->mHal.drvState);
-            }
-        } else if (ret == BAD_VALUE) {
-            // No new frame, don't do anything
-        } else {
-            rsc->setError(RS_ERROR_DRIVER, "Error receiving IO input buffer.");
-        }
-
-    } else {
+    if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
         drv->surfaceTexture->updateTexImage();
     }
-
-
 #endif
 }
 
@@ -1200,3 +1147,10 @@
         }
     }
 }
+
+uint32_t rsdAllocationGrallocBits(const android::renderscript::Context *rsc,
+                                  android::renderscript::Allocation *alloc)
+{
+    return 0;
+}
+
diff --git a/driver/rsdAllocation.h b/driver/rsdAllocation.h
index 35999d3..ff47f03 100644
--- a/driver/rsdAllocation.h
+++ b/driver/rsdAllocation.h
@@ -29,7 +29,6 @@
 #endif
 
 #if !defined(RS_SERVER) && !defined(RS_COMPATIBILITY_LIB)
-#include "gui/CpuConsumer.h"
 #include "gui/GLConsumer.h"
 #endif
 
@@ -51,16 +50,6 @@
     uint32_t renderTargetID;
 
 #ifndef RS_COMPATIBILITY_LIB
-    class NewBufferListener : public android::ConsumerBase::FrameAvailableListener {
-    public:
-        const android::renderscript::Context *rsc;
-        const android::renderscript::Allocation *alloc;
-
-        virtual void onFrameAvailable();
-    };
-    android::sp<NewBufferListener> mBufferListener;
-
-
     GLenum glTarget;
     GLenum glType;
     GLenum glFormat;
@@ -79,11 +68,6 @@
     RsdFrameBufferObj * readBackFBO;
     ANativeWindow *wnd;
     ANativeWindowBuffer *wndBuffer;
-
-#if !defined(RS_SERVER) && !defined(RS_COMPATIBILITY_LIB)
-    android::sp< android::CpuConsumer > cpuConsumer;
-    android::CpuConsumer::LockedBuffer lb;
-#endif
 };
 
 #ifndef RS_COMPATIBILITY_LIB
@@ -92,6 +76,8 @@
 #endif
 
 
+uint32_t rsdAllocationGrallocBits(const android::renderscript::Context *rsc,
+                                  android::renderscript::Allocation *alloc);
 bool rsdAllocationInit(const android::renderscript::Context *rsc,
                        android::renderscript::Allocation *alloc,
                        bool forceZero);
@@ -106,8 +92,6 @@
                           RsAllocationUsageType src);
 void rsdAllocationMarkDirty(const android::renderscript::Context *rsc,
                             const android::renderscript::Allocation *alloc);
-void* rsdAllocationGetSurface(const android::renderscript::Context *rsc,
-                              const android::renderscript::Allocation *alloc);
 void rsdAllocationSetSurface(const android::renderscript::Context *rsc,
                             android::renderscript::Allocation *alloc, ANativeWindow *nw);
 void rsdAllocationIoSend(const android::renderscript::Context *rsc,
diff --git a/driver/rsdCore.cpp b/driver/rsdCore.cpp
index 4aad52a..2b473c4 100644
--- a/driver/rsdCore.cpp
+++ b/driver/rsdCore.cpp
@@ -89,10 +89,10 @@
     {
         rsdAllocationInit,
         rsdAllocationDestroy,
+        rsdAllocationGrallocBits,
         rsdAllocationResize,
         rsdAllocationSyncAll,
         rsdAllocationMarkDirty,
-        NATIVE_FUNC(rsdAllocationGetSurface),
         NATIVE_FUNC(rsdAllocationSetSurface),
         NATIVE_FUNC(rsdAllocationIoSend),
         NATIVE_FUNC(rsdAllocationIoReceive),
diff --git a/driver/rsdRuntimeStubs.cpp b/driver/rsdRuntimeStubs.cpp
index cb3a5b4..ac80ba3 100644
--- a/driver/rsdRuntimeStubs.cpp
+++ b/driver/rsdRuntimeStubs.cpp
@@ -141,13 +141,13 @@
 #ifndef RS_COMPATIBILITY_LIB
 static void SC_AllocationIoSend(Allocation *alloc) {
     Context *rsc = RsdCpuReference::getTlsContext();
-    rsdAllocationIoSend(rsc, alloc);
+    rsrAllocationIoSend(rsc, alloc);
 }
 
 
 static void SC_AllocationIoReceive(Allocation *alloc) {
     Context *rsc = RsdCpuReference::getTlsContext();
-    rsdAllocationIoReceive(rsc, alloc);
+    rsrAllocationIoReceive(rsc, alloc);
 }
 
 
diff --git a/driver/runtime/rs_structs.h b/driver/runtime/rs_structs.h
index 6db4279..204717c 100644
--- a/driver/runtime/rs_structs.h
+++ b/driver/runtime/rs_structs.h
@@ -39,8 +39,8 @@
             bool hasReferences;
             void * usrPtr;
             int32_t surfaceTextureID;
-            void * wndSurface;
-            void * surfaceTexture;
+            void * nativeBuffer;
+            int64_t timestamp;
         } state;
 
         struct DrvState {
diff --git a/rsAllocation.cpp b/rsAllocation.cpp
index c861d09..9bf8709 100644
--- a/rsAllocation.cpp
+++ b/rsAllocation.cpp
@@ -79,6 +79,13 @@
 }
 
 Allocation::~Allocation() {
+#if !defined(RS_SERVER) && !defined(RS_COMPATIBILITY_LIB)
+    if (mGrallocConsumer.get()) {
+        mGrallocConsumer->unlockBuffer();
+        mGrallocConsumer = NULL;
+    }
+#endif
+
     freeChildrenUnlocked();
     mRSC->mHal.funcs.allocation.destroy(mRSC, this);
 }
@@ -451,8 +458,31 @@
     ALOGE("not implemented");
 }
 
+#ifndef RS_COMPATIBILITY_LIB
+void Allocation::NewBufferListener::onFrameAvailable() {
+    intptr_t ip = (intptr_t)alloc;
+    rsc->sendMessageToClient(NULL, RS_MESSAGE_TO_CLIENT_NEW_BUFFER, ip, 0, true);
+}
+#endif
+
 void * Allocation::getSurface(const Context *rsc) {
-    return rsc->mHal.funcs.allocation.getSurface(rsc, this);
+#ifndef RS_COMPATIBILITY_LIB
+    // Configure GrallocConsumer to be in asynchronous mode
+    sp<BufferQueue> bq = new BufferQueue();
+    mGrallocConsumer = new GrallocConsumer(this, bq);
+    sp<IGraphicBufferProducer> bp = bq;
+    bp->incStrong(NULL);
+
+    mBufferListener = new NewBufferListener();
+    mBufferListener->rsc = rsc;
+    mBufferListener->alloc = this;
+
+    mGrallocConsumer->setFrameAvailableListener(mBufferListener);
+    return bp.get();
+#else
+    return NULL;
+#endif
+    //return rsc->mHal.funcs.allocation.getSurface(rsc, this);
 }
 
 void Allocation::setSurface(const Context *rsc, RsNativeWindow sur) {
@@ -465,7 +495,22 @@
 }
 
 void Allocation::ioReceive(const Context *rsc) {
-    rsc->mHal.funcs.allocation.ioReceive(rsc, this);
+    void *ptr = NULL;
+    size_t stride = 0;
+#ifndef RS_COMPATIBILITY_LIB
+    if (mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) {
+        status_t ret = mGrallocConsumer->lockNextBuffer();
+
+        if (ret == OK) {
+            rsc->mHal.funcs.allocation.ioReceive(rsc, this);
+        } else if (ret == BAD_VALUE) {
+            // No new frame, don't do anything
+        } else {
+            rsc->setError(RS_ERROR_DRIVER, "Error receiving IO input buffer.");
+        }
+
+    }
+#endif
 }
 
 
diff --git a/rsAllocation.h b/rsAllocation.h
index dffa440..440246e 100644
--- a/rsAllocation.h
+++ b/rsAllocation.h
@@ -19,6 +19,14 @@
 
 #include "rsType.h"
 
+#include <ui/GraphicBuffer.h>
+
+#if !defined(RS_SERVER) && !defined(RS_COMPATIBILITY_LIB)
+#include "rsGrallocConsumer.h"
+#include "gui/CpuConsumer.h"
+#include "gui/GLConsumer.h"
+#endif
+
 // ---------------------------------------------------------------------------
 namespace android {
 
@@ -58,8 +66,8 @@
             bool hasReferences;
             void * userProvidedPtr;
             int32_t surfaceTextureID;
-            void *deprecated01;
-            void *deprecated02;
+            ANativeWindowBuffer *nativeBuffer;
+            int64_t timestamp;
         };
         State state;
 
@@ -157,6 +165,20 @@
         mHal.state.type = t;
     }
 
+#if !defined(RS_SERVER) && !defined(RS_COMPATIBILITY_LIB)
+    class NewBufferListener : public android::ConsumerBase::FrameAvailableListener {
+    public:
+        const android::renderscript::Context *rsc;
+        const android::renderscript::Allocation *alloc;
+
+        virtual void onFrameAvailable();
+    };
+
+    sp<NewBufferListener> mBufferListener;
+    sp< GrallocConsumer > mGrallocConsumer;
+#endif
+
+
 private:
     void freeChildrenUnlocked();
     Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc, void *ptr);
diff --git a/rsGrallocConsumer.cpp b/rsGrallocConsumer.cpp
new file mode 100644
index 0000000..e3bd9d4
--- /dev/null
+++ b/rsGrallocConsumer.cpp
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_RS
+
+#include "rsContext.h"
+#include "rsAllocation.h"
+#include "rsAdapter.h"
+#include "rs_hal.h"
+
+#include <cutils/compiler.h>
+#include <utils/Log.h>
+#include "rsGrallocConsumer.h"
+#include <ui/GraphicBuffer.h>
+
+
+namespace android {
+namespace renderscript {
+
+GrallocConsumer::GrallocConsumer(Allocation *a, const sp<IGraphicBufferConsumer>& bq) :
+    ConsumerBase(bq, true)
+{
+    mAlloc = a;
+    mConsumer->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
+    mConsumer->setMaxAcquiredBufferCount(2);
+
+    uint32_t y = a->mHal.drvState.lod[0].dimY;
+    if (y < 1) y = 1;
+    mConsumer->setDefaultBufferSize(a->mHal.drvState.lod[0].dimX, y);
+
+    //mBufferQueue->setDefaultBufferFormat(defaultFormat);
+    //mBufferQueue->setConsumerName(name);
+}
+
+GrallocConsumer::~GrallocConsumer() {
+    // ConsumerBase destructor does all the work.
+}
+
+
+
+status_t GrallocConsumer::lockNextBuffer() {
+    Mutex::Autolock _l(mMutex);
+    status_t err;
+
+    if (mAcquiredBuffer.mSlot != BufferQueue::INVALID_BUFFER_SLOT) {
+        err = releaseAcquiredBufferLocked();
+        if (err) {
+            return err;
+        }
+    }
+
+    BufferQueue::BufferItem b;
+
+    err = acquireBufferLocked(&b, 0);
+    if (err != OK) {
+        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+            return BAD_VALUE;
+        } else {
+            ALOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
+            return err;
+        }
+    }
+
+    int buf = b.mBuf;
+
+    if (b.mFence.get()) {
+        err = b.mFence->waitForever("GrallocConsumer::lockNextBuffer");
+        if (err != OK) {
+            ALOGE("Failed to wait for fence of acquired buffer: %s (%d)",
+                    strerror(-err), err);
+            return err;
+        }
+    }
+
+    void *bufferPointer = NULL;
+    android_ycbcr ycbcr = android_ycbcr();
+
+    if (mSlots[buf].mGraphicBuffer->getPixelFormat() ==
+            HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        err = mSlots[buf].mGraphicBuffer->lockYCbCr(
+            GraphicBuffer::USAGE_SW_READ_OFTEN,
+            b.mCrop,
+            &ycbcr);
+
+        if (err != OK) {
+            ALOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)",
+                    strerror(-err), err);
+            return err;
+        }
+        bufferPointer = ycbcr.y;
+    } else {
+        err = mSlots[buf].mGraphicBuffer->lock(
+            GraphicBuffer::USAGE_SW_READ_OFTEN,
+            b.mCrop,
+            &bufferPointer);
+
+        if (err != OK) {
+            ALOGE("Unable to lock buffer for CPU reading: %s (%d)",
+                    strerror(-err), err);
+            return err;
+        }
+    }
+
+    size_t lockedIdx = 0;
+    assert(mAcquiredBuffer.mSlot == BufferQueue::INVALID_BUFFER_SLOT);
+
+    mAcquiredBuffer.mSlot = buf;
+    mAcquiredBuffer.mBufferPointer = bufferPointer;
+    mAcquiredBuffer.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+
+    mAlloc->mHal.drvState.lod[0].mallocPtr = reinterpret_cast<uint8_t*>(bufferPointer);
+    mAlloc->mHal.drvState.lod[0].stride = mSlots[buf].mGraphicBuffer->getStride() *
+            mAlloc->mHal.state.type->getElementSizeBytes();
+    mAlloc->mHal.state.nativeBuffer = mAcquiredBuffer.mGraphicBuffer->getNativeBuffer();
+    mAlloc->mHal.state.timestamp = b.mTimestamp;
+
+    assert(mAlloc->mHal.drvState.lod[0].dimX ==
+           mSlots[buf].mGraphicBuffer->getWidth());
+    assert(mAlloc->mHal.drvState.lod[0].dimY ==
+           mSlots[buf].mGraphicBuffer->getHeight());
+
+    //mAlloc->format = mSlots[buf].mGraphicBuffer->getPixelFormat();
+
+    //mAlloc->crop        = b.mCrop;
+    //mAlloc->transform   = b.mTransform;
+    //mAlloc->scalingMode = b.mScalingMode;
+    //mAlloc->frameNumber = b.mFrameNumber;
+
+    if (mAlloc->mHal.state.yuv) {
+        mAlloc->mHal.drvState.lod[1].mallocPtr = ycbcr.cb;
+        mAlloc->mHal.drvState.lod[2].mallocPtr = ycbcr.cr;
+
+        mAlloc->mHal.drvState.lod[0].stride = ycbcr.ystride;
+        mAlloc->mHal.drvState.lod[1].stride = ycbcr.cstride;
+        mAlloc->mHal.drvState.lod[2].stride = ycbcr.cstride;
+    }
+
+    return OK;
+}
+
+status_t GrallocConsumer::unlockBuffer() {
+    Mutex::Autolock _l(mMutex);
+    return releaseAcquiredBufferLocked();
+}
+
+status_t GrallocConsumer::releaseAcquiredBufferLocked() {
+    status_t err;
+
+    err = mAcquiredBuffer.mGraphicBuffer->unlock();
+    if (err != OK) {
+        ALOGE("%s: Unable to unlock graphic buffer", __FUNCTION__);
+        return err;
+    }
+    int buf = mAcquiredBuffer.mSlot;
+
+    // release the buffer if it hasn't already been freed by the BufferQueue.
+    // This can happen, for example, when the producer of this buffer
+    // disconnected after this buffer was acquired.
+    if (CC_LIKELY(mAcquiredBuffer.mGraphicBuffer ==
+            mSlots[buf].mGraphicBuffer)) {
+        releaseBufferLocked(
+                buf, mAcquiredBuffer.mGraphicBuffer,
+                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+    }
+
+    mAcquiredBuffer.mSlot = BufferQueue::INVALID_BUFFER_SLOT;
+    mAcquiredBuffer.mBufferPointer = NULL;
+    mAcquiredBuffer.mGraphicBuffer.clear();
+    return OK;
+}
+
+} // namespace renderscript
+} // namespace android
+
diff --git a/rsGrallocConsumer.h b/rsGrallocConsumer.h
new file mode 100644
index 0000000..9e4fc58
--- /dev/null
+++ b/rsGrallocConsumer.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ * 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_RS_GRALLOC_CONSUMER_H
+#define ANDROID_RS_GRALLOC_CONSUMER_H
+
+#include <gui/ConsumerBase.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Allocation;
+
+/**
+ * CpuConsumer is a BufferQueue consumer endpoint that allows direct CPU
+ * access to the underlying gralloc buffers provided by BufferQueue. Multiple
+ * buffers may be acquired by it at once, to be used concurrently by the
+ * CpuConsumer owner. Sets gralloc usage flags to be software-read-only.
+ * This queue is synchronous by default.
+ */
+class GrallocConsumer : public ConsumerBase
+{
+  public:
+    typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
+
+    GrallocConsumer(Allocation *, const sp<IGraphicBufferConsumer>& bq);
+
+    virtual ~GrallocConsumer();
+    status_t lockNextBuffer();
+    status_t unlockBuffer();
+
+  private:
+    status_t releaseAcquiredBufferLocked();
+    Allocation *mAlloc;
+
+    // Tracking for buffers acquired by the user
+    struct AcquiredBuffer {
+        // Need to track the original mSlot index and the buffer itself because
+        // the mSlot entry may be freed/reused before the acquired buffer is
+        // released.
+        int mSlot;
+        sp<GraphicBuffer> mGraphicBuffer;
+        void *mBufferPointer;
+
+        AcquiredBuffer() :
+                mSlot(BufferQueue::INVALID_BUFFER_SLOT),
+                mBufferPointer(NULL) {
+        }
+    };
+    AcquiredBuffer mAcquiredBuffer;
+};
+
+} // namespace renderscript
+} // namespace android
+
+#endif // ANDROID_RS_GRALLOC_CONSUMER_H
+
diff --git a/rsRuntime.h b/rsRuntime.h
index 2939176..1d81ffb 100644
--- a/rsRuntime.h
+++ b/rsRuntime.h
@@ -108,6 +108,10 @@
                     int32_t *left, int32_t *right, int32_t *top, int32_t *bottom);
 void rsrBindFont(Context *, Font *);
 void rsrFontColor(Context *, float r, float g, float b, float a);
+
+void rsrAllocationIoSend(Context *, Allocation *);
+void rsrAllocationIoReceive(Context *, Allocation *);
+
 #endif
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/rsScriptC_Lib.cpp b/rsScriptC_Lib.cpp
index 123b8b3..842d8d2 100644
--- a/rsScriptC_Lib.cpp
+++ b/rsScriptC_Lib.cpp
@@ -171,6 +171,13 @@
     return rsc->sendMessageToClient(data, RS_MESSAGE_TO_CLIENT_USER, cmdID, len, true);
 }
 
+void rsrAllocationIoSend(Context *rsc, Allocation *src) {
+    src->ioSend(rsc);
+}
+
+void rsrAllocationIoReceive(Context *rsc, Allocation *src) {
+    src->ioReceive(rsc);
+}
 
 void rsrForEach(Context *rsc,
                 Script *target,
diff --git a/rs_hal.h b/rs_hal.h
index 1ed26dc..16bd890 100644
--- a/rs_hal.h
+++ b/rs_hal.h
@@ -145,15 +145,23 @@
     struct {
         bool (*init)(const Context *rsc, Allocation *alloc, bool forceZero);
         void (*destroy)(const Context *rsc, Allocation *alloc);
+        uint32_t (*grallocBits)(const Context *rsc, Allocation *alloc);
 
         void (*resize)(const Context *rsc, const Allocation *alloc, const Type *newType,
                        bool zeroNew);
         void (*syncAll)(const Context *rsc, const Allocation *alloc, RsAllocationUsageType src);
         void (*markDirty)(const Context *rsc, const Allocation *alloc);
 
-        void * (*getSurface)(const Context *rsc, const Allocation *alloc);
         void (*setSurface)(const Context *rsc, Allocation *alloc, ANativeWindow *sur);
         void (*ioSend)(const Context *rsc, Allocation *alloc);
+
+        /**
+         * A new gralloc buffer is in use. The pointers and strides in
+         * mHal.drvState.lod[0-2] will be updated with the new values.
+         *
+         * The new gralloc handle is provided in mHal.state.nativeBuffer
+         *
+         */
         void (*ioReceive)(const Context *rsc, Allocation *alloc);
 
         void (*data1D)(const Context *rsc, const Allocation *alloc,