Add getPointer for USAGE_SHARED allocations.

Change-Id: I13a2af09bbbeec6cc6131b935979ac21c02820be
diff --git a/cpp/Allocation.cpp b/cpp/Allocation.cpp
index 00d207e..de0f229 100644
--- a/cpp/Allocation.cpp
+++ b/cpp/Allocation.cpp
@@ -169,8 +169,26 @@
 #endif
 }
 
-void Allocation::generateMipmaps() {
-    tryDispatch(mRS, RS::dispatch->AllocationGenerateMipmaps(mRS->getContext(), getID()));
+void * Allocation::getPointer(size_t *stride) {
+    void *p = NULL;
+    if (!(mUsage & RS_ALLOCATION_USAGE_SHARED)) {
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Allocation does not support USAGE_SHARED.");
+        return NULL;
+    }
+
+    // FIXME: decide if lack of getPointer should cause compat mode
+    if (RS::dispatch->AllocationGetPointer == NULL) {
+        mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Can't use getPointer on older APIs");
+        return NULL;
+    }
+
+    p = RS::dispatch->AllocationGetPointer(mRS->getContext(), getIDSafe(), 0,
+                                           RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0, stride);
+    if (mRS->getError() != RS_SUCCESS) {
+        mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation lock failed");
+        p = NULL;
+    }
+    return p;
 }
 
 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const void *data) {
diff --git a/cpp/RenderScript.cpp b/cpp/RenderScript.cpp
index 04f1e88..5709f79 100644
--- a/cpp/RenderScript.cpp
+++ b/cpp/RenderScript.cpp
@@ -401,6 +401,11 @@
         ALOGV("Couldn't initialize RS::dispatch->AllocationIoReceive");
         return false;
     }
+    RS::dispatch->AllocationGetPointer = (AllocationGetPointerFnPtr)dlsym(handle, "rsAllocationGetPointer");
+    if (RS::dispatch->AllocationGetPointer == NULL) {
+        ALOGV("Couldn't initialize RS::dispatch->AllocationGetPointer");
+        //return false;
+    }
 
     return true;
 }
diff --git a/cpp/rsCppStructs.h b/cpp/rsCppStructs.h
index 70931be..6c14e8c 100644
--- a/cpp/rsCppStructs.h
+++ b/cpp/rsCppStructs.h
@@ -559,6 +559,13 @@
                                         uint32_t usage = RS_ALLOCATION_USAGE_SCRIPT);
 
 
+    /**
+     * Get the backing pointer for a USAGE_SHARED allocation.
+     * @param[in] stride optional parameter. when non-NULL, will contain
+     *   stride in bytes of a 2D Allocation
+     * @return pointer to data
+     */
+    void * getPointer(size_t *stride = NULL);
 };
 
  /**
diff --git a/cpp/rsDispatch.h b/cpp/rsDispatch.h
index 0bd1283..ca708ad 100644
--- a/cpp/rsDispatch.h
+++ b/cpp/rsDispatch.h
@@ -85,6 +85,7 @@
 typedef void (*ScriptGroupExecuteFnPtr) (RsContext, RsScriptGroup);
 typedef void (*AllocationIoSendFnPtr) (RsContext, RsAllocation);
 typedef void (*AllocationIoReceiveFnPtr) (RsContext, RsAllocation);
+typedef void * (*AllocationGetPointerFnPtr) (RsContext, RsAllocation, uint32_t lod, RsAllocationCubemapFace face, uint32_t z, uint32_t array, size_t *stride);
 
 typedef struct {
     // inserted by hand from rs.h
@@ -156,6 +157,7 @@
     ScriptGroupExecuteFnPtr ScriptGroupExecute;
     AllocationIoSendFnPtr AllocationIoSend;
     AllocationIoReceiveFnPtr AllocationIoReceive;
+    AllocationGetPointerFnPtr AllocationGetPointer;
 } dispatchTable;
 
 #endif
diff --git a/driver/rsdAllocation.cpp b/driver/rsdAllocation.cpp
index 817c9d8..0d85ebe 100644
--- a/driver/rsdAllocation.cpp
+++ b/driver/rsdAllocation.cpp
@@ -599,7 +599,7 @@
         return;
     }
 
-    rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT);
+    rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT || src == RS_ALLOCATION_USAGE_SHARED);
 
     if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
         UploadToTexture(rsc, alloc);
@@ -614,7 +614,13 @@
     }
 
     if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SHARED) {
-        // NOP in CPU driver for now
+
+        if (src == RS_ALLOCATION_USAGE_SHARED) {
+            // just a memory fence for the CPU driver
+            // vendor drivers probably want to flush any dirty cachelines for
+            // this particular Allocation
+            __sync_synchronize();
+        }
     }
 
     drv->uploadDeferred = false;
diff --git a/rs.spec b/rs.spec
index 6ce258a..62a3646 100644
--- a/rs.spec
+++ b/rs.spec
@@ -130,6 +130,15 @@
     param void * data
     }
 
+AllocationGetPointer {
+    param RsAllocation va
+    param uint32_t lod
+    param RsAllocationCubemapFace face
+    param uint32_t z
+    param uint32_t array
+    param size_t *stride
+    ret void *s
+    }
 
 Allocation1DData {
     param RsAllocation va
diff --git a/rsAllocation.cpp b/rsAllocation.cpp
index d4cecd0..fd0a49c 100644
--- a/rsAllocation.cpp
+++ b/rsAllocation.cpp
@@ -94,6 +94,24 @@
     rsc->mHal.funcs.allocation.syncAll(rsc, this, src);
 }
 
+void * Allocation::getPointer(const Context *rsc, uint32_t lod, RsAllocationCubemapFace face,
+                          uint32_t z, uint32_t array, size_t *stride) {
+
+    if ((lod >= mHal.drvState.lodCount) ||
+        (z && (z >= mHal.drvState.lod[lod].dimZ)) ||
+        ((face != RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X) && !mHal.state.hasFaces) ||
+        (array != 0)) {
+        return NULL;
+    }
+
+    size_t s = 0;
+    //void *ptr = mRSC->mHal.funcs.allocation.lock1D(rsc, this);
+    if ((stride != NULL) && mHal.drvState.lod[0].dimY) {
+        *stride = mHal.drvState.lod[lod].stride;
+    }
+    return mHal.drvState.lod[lod].mallocPtr;
+}
+
 void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod,
                          uint32_t count, const void *data, size_t sizeBytes) {
     const size_t eSize = mHal.state.type->getElementSizeBytes();
@@ -716,6 +734,15 @@
     alloc->ioReceive(rsc);
 }
 
+void rsi_AllocationGetPointer(Context *rsc, RsAllocation valloc,
+                          uint32_t lod, RsAllocationCubemapFace face,
+                          uint32_t z, uint32_t array, size_t *stride, size_t strideLen) {
+    Allocation *alloc = static_cast<Allocation *>(valloc);
+    assert(strideLen == sizeof(size_t));
+
+    alloc->getPointer(rsc, lod, face, z, array, stride);
+}
+
 void rsi_Allocation1DRead(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t lod,
                           uint32_t count, void *data, size_t sizeBytes) {
     Allocation *a = static_cast<Allocation *>(va);
diff --git a/rsAllocation.h b/rsAllocation.h
index b0f2f9e..b997f9a 100644
--- a/rsAllocation.h
+++ b/rsAllocation.h
@@ -163,6 +163,9 @@
     void ioSend(const Context *rsc);
     void ioReceive(const Context *rsc);
 
+    void * getPointer(const Context *rsc, uint32_t lod, RsAllocationCubemapFace face,
+                      uint32_t z, uint32_t array, size_t *stride);
+
 protected:
     Vector<const Program *> mToDirtyList;
     ObjectBaseRef<const Type> mType;
diff --git a/tests/cppbasic-getpointer/Android.mk b/tests/cppbasic-getpointer/Android.mk
new file mode 100644
index 0000000..eb4ac34
--- /dev/null
+++ b/tests/cppbasic-getpointer/Android.mk
@@ -0,0 +1,26 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	mono.rs \
+	compute.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libRScpp \
+	libstlport
+
+LOCAL_MODULE:= rstest-compute-getpointer
+
+LOCAL_MODULE_TAGS := tests
+
+intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
+
+LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
+LOCAL_C_INCLUDES += frameworks/rs/cpp
+LOCAL_C_INCLUDES += frameworks/rs
+LOCAL_C_INCLUDES += $(intermediates)
+
+LOCAL_CLANG := true
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/tests/cppbasic-getpointer/compute.cpp b/tests/cppbasic-getpointer/compute.cpp
new file mode 100644
index 0000000..033e7b3
--- /dev/null
+++ b/tests/cppbasic-getpointer/compute.cpp
@@ -0,0 +1,100 @@
+
+#include "RenderScript.h"
+
+#include "ScriptC_mono.h"
+
+#include <stdlib.h>
+
+using namespace android;
+using namespace RSC;
+
+const uint32_t DIMX = 128;
+const uint32_t DIMY = 128;
+
+int test_compute()
+{
+    bool failed = false;
+
+    sp<RS> rs = new RS();
+    printf("New RS %p\n", rs.get());
+
+    // only legitimate because this is a standalone executable
+    bool r = rs->init("/system/bin");
+    printf("Init returned %i\n", r);
+
+    sp<const Element> e = Element::U32(rs);
+    printf("Element %p\n", e.get());
+
+    Type::Builder tb(rs, e);
+    tb.setX(DIMX);
+    tb.setY(DIMY);
+    sp<const Type> t = tb.create();
+    printf("Type %p\n", t.get());
+
+
+    sp<Allocation> a1 = Allocation::createSized(rs, e, 1000);
+    printf("Allocation %p\n", a1.get());
+
+    sp<Allocation> ain = Allocation::createTyped(rs, t, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED);
+    sp<Allocation> aout = Allocation::createTyped(rs, t, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED);
+    printf("Allocation %p %p\n", ain.get(), aout.get());
+
+    size_t inputStride, outputStride;
+
+    uint32_t *input = (uint32_t*)ain->getPointer(&inputStride);
+    uint32_t *output = (uint32_t*)aout->getPointer(&outputStride);
+
+    printf("Input pointer: %p\n", input);
+    printf("Input stride: %u\n", inputStride);
+    printf("Output pointer: %p\n", output);
+    printf("Output stride: %u\n", outputStride);
+
+    inputStride /= sizeof(uint32_t);
+    outputStride /= sizeof(uint32_t);
+
+    for (size_t i = 0; i < DIMY; i++) {
+        for (size_t j = 0; j < DIMX; j++) {
+            input[i * inputStride + j] = rand();
+            output[i * inputStride + j] = 0;
+        }
+    }
+
+    ain->syncAll(RS_ALLOCATION_USAGE_SHARED);
+    aout->syncAll(RS_ALLOCATION_USAGE_SHARED);
+
+    printf("Launching script\n");
+
+    sp<ScriptC_mono> sc = new ScriptC_mono(rs);
+    sc->forEach_copyAndNot(ain, aout);
+    rs->finish();
+
+    printf("Script completed\n");
+
+    ain->syncAll(RS_ALLOCATION_USAGE_SCRIPT);
+    aout->syncAll(RS_ALLOCATION_USAGE_SCRIPT);
+
+    for (size_t i = 0; i < DIMY; i++) {
+        for (size_t j = 0; j < DIMX; j++) {
+            if (input[i * inputStride + j] != ~(output[i * inputStride + j])) {
+                printf("Mismatch at location %u, %u\n", j, i);
+                failed = true;
+                return failed;
+            }
+        }
+    }
+
+
+    return failed;
+}
+
+int main() {
+    bool failed = test_compute();
+
+    if (failed) {
+        printf("TEST FAILED!\n");
+    } else {
+        printf("TEST PASSED!\n");
+    }
+
+    return failed;
+}
diff --git a/tests/cppbasic-getpointer/mono.rs b/tests/cppbasic-getpointer/mono.rs
new file mode 100644
index 0000000..25e60df
--- /dev/null
+++ b/tests/cppbasic-getpointer/mono.rs
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.cppbasic)
+#pragma rs_fp_relaxed
+
+uint32_t __attribute__((kernel)) copyAndNot(uint32_t in) {
+    return ~in;
+}