Support running ForEach on non-root functions.

BUG=6000538

Change-Id: Ie2b16893b150cc5955ee4b9d028c988f69a82744
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index bec6ffff..dd78684 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 #include "rsdCore.h"
 #include "rsdBcc.h"
 #include "rsdRuntime.h"
@@ -30,7 +29,6 @@
 #include "libdex/ZipArchive.h"
 }
 
-
 using namespace android;
 using namespace android::renderscript;
 
@@ -45,6 +43,7 @@
     bcinfo::MetadataExtractor *ME;
 
     InvokeFunc_t *mInvokeFunctions;
+    ForEachFunc_t *mForEachFunctions;
     void ** mFieldAddress;
     bool * mFieldIsObject;
     const uint32_t *mExportForEachSignatureList;
@@ -162,8 +161,16 @@
     }
 
     exportForEachSignatureCount = drv->ME->getExportForEachSignatureCount();
-    rsAssert(exportForEachSignatureCount <= 1);
     drv->mExportForEachSignatureList = drv->ME->getExportForEachSignatureList();
+    if (exportForEachSignatureCount > 0) {
+        drv->mForEachFunctions =
+            (ForEachFunc_t*) calloc(exportForEachSignatureCount,
+                                    sizeof(ForEachFunc_t));
+        bccGetExportForEachList(drv->mBccScript, exportForEachSignatureCount,
+                                (void **) drv->mForEachFunctions);
+    } else {
+        drv->mForEachFunctions = NULL;
+    }
 
     // Copy info over to runtime
     script->mHal.info.exportedFunctionCount = drv->ME->getExportFuncCount();
@@ -196,6 +203,7 @@
 typedef struct {
     Context *rsc;
     Script *script;
+    ForEachFunc_t kernel;
     uint32_t sig;
     const Allocation * ain;
     Allocation * aout;
@@ -235,7 +243,7 @@
     RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
     uint32_t sig = mtls->sig;
 
-    outer_foreach_t fn = (outer_foreach_t) mtls->script->mHal.info.root;
+    outer_foreach_t fn = (outer_foreach_t) mtls->kernel;
     while (1) {
         uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
         uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
@@ -265,7 +273,7 @@
     RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
     uint32_t sig = mtls->sig;
 
-    outer_foreach_t fn = (outer_foreach_t) mtls->script->mHal.info.root;
+    outer_foreach_t fn = (outer_foreach_t) mtls->kernel;
     while (1) {
         uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
         uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
@@ -299,8 +307,8 @@
     memset(&mtls, 0, sizeof(mtls));
 
     DrvScript *drv = (DrvScript *)s->mHal.drv;
-    // We only support slot 0 (root) at this point in time.
-    rsAssert(slot == 0);
+    mtls.kernel = drv->mForEachFunctions[slot];
+    rsAssert(mtls.kernel != NULL);
     mtls.sig = 0x1f;  // temp fix for old apps, full table in slang_rs_export_foreach.cpp
     if (drv->mExportForEachSignatureList) {
         mtls.sig = drv->mExportForEachSignatureList[slot];
@@ -391,7 +399,7 @@
         uint32_t sig = mtls.sig;
 
         //ALOGE("launch 3");
-        outer_foreach_t fn = (outer_foreach_t) mtls.script->mHal.info.root;
+        outer_foreach_t fn = (outer_foreach_t) mtls.kernel;
         for (p.ar[0] = mtls.arrayStart; p.ar[0] < mtls.arrayEnd; p.ar[0]++) {
             for (p.z = mtls.zStart; p.z < mtls.zEnd; p.z++) {
                 for (p.y = mtls.yStart; p.y < mtls.yEnd; p.y++) {
@@ -517,6 +525,11 @@
         drv->mInvokeFunctions = NULL;
     }
 
+    if (drv->mForEachFunctions) {
+        free(drv->mForEachFunctions);
+        drv->mForEachFunctions = NULL;
+    }
+
     delete drv->ME;
     drv->ME = NULL;
 
diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h
index 168bdf3..05ca13b 100644
--- a/libs/rs/driver/rsdCore.h
+++ b/libs/rs/driver/rsdCore.h
@@ -25,6 +25,7 @@
 #include "rsdGL.h"
 
 typedef void (* InvokeFunc_t)(void);
+typedef void (* ForEachFunc_t)(void);
 typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
 
 typedef struct RsdSymbolTableRec {
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index 357dbe3..6a3bd4b 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-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.
@@ -113,7 +113,7 @@
                        RsAllocation vain, RsAllocation vaout,
                        const void *params, size_t paramLen) {
     Script *s = static_cast<Script *>(vs);
-    s->runForEach(rsc,
+    s->runForEach(rsc, slot,
                   static_cast<const Allocation *>(vain), static_cast<Allocation *>(vaout),
                   params, paramLen);
 
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index 99dceaf..7879ea6 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-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.
@@ -74,6 +74,7 @@
     virtual bool freeChildren();
 
     virtual void runForEach(Context *rsc,
+                            uint32_t slot,
                             const Allocation * ain,
                             Allocation * aout,
                             const void * usr,
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index b4eb995..79725b97 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-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.
@@ -128,6 +128,7 @@
 
 
 void ScriptC::runForEach(Context *rsc,
+                         uint32_t slot,
                          const Allocation * ain,
                          Allocation * aout,
                          const void * usr,
@@ -138,7 +139,7 @@
 
     setupGLState(rsc);
     setupScript(rsc);
-    rsc->mHal.funcs.script.invokeForEach(rsc, this, 0, ain, aout, usr, usrBytes, sc);
+    rsc->mHal.funcs.script.invokeForEach(rsc, this, slot, ain, aout, usr, usrBytes, sc);
 }
 
 void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) {
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index c65a5bf..c89d9b1 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-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.
@@ -47,6 +47,7 @@
     virtual uint32_t run(Context *);
 
     virtual void runForEach(Context *rsc,
+                            uint32_t slot,
                             const Allocation * ain,
                             Allocation * aout,
                             const void * usr,
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 183e207..a5a0fae 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-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.
@@ -157,7 +157,7 @@
                 Allocation *in, Allocation *out,
                 const void *usr, uint32_t usrBytes,
                 const RsScriptCall *call) {
-    target->runForEach(rsc, in, out, usr, usrBytes, call);
+    target->runForEach(rsc, /* root slot */ 0, in, out, usr, usrBytes, call);
 }
 
 void rsrAllocationSyncAll(Context *rsc, Script *sc, Allocation *a, RsAllocationUsageType usage) {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index c7bd809..6f56223 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -64,11 +64,6 @@
 
         unitTests = new ArrayList<UnitTest>();
 
-        unitTests.add(new UT_mesh(this, mRes, mCtx));
-        unitTests.add(new UT_element(this, mRes, mCtx));
-        unitTests.add(new UT_sampler(this, mRes, mCtx));
-        unitTests.add(new UT_program_store(this, mRes, mCtx));
-        unitTests.add(new UT_program_raster(this, mRes, mCtx));
         unitTests.add(new UT_primitives(this, mRes, mCtx));
         unitTests.add(new UT_constant(this, mRes, mCtx));
         unitTests.add(new UT_vector(this, mRes, mCtx));
@@ -79,10 +74,17 @@
         unitTests.add(new UT_alloc(this, mRes, mCtx));
         unitTests.add(new UT_refcount(this, mRes, mCtx));
         unitTests.add(new UT_foreach(this, mRes, mCtx));
+        unitTests.add(new UT_noroot(this, mRes, mCtx));
         unitTests.add(new UT_atomic(this, mRes, mCtx));
         unitTests.add(new UT_struct(this, mRes, mCtx));
         unitTests.add(new UT_math(this, mRes, mCtx));
+        unitTests.add(new UT_mesh(this, mRes, mCtx));
+        unitTests.add(new UT_element(this, mRes, mCtx));
+        unitTests.add(new UT_sampler(this, mRes, mCtx));
+        unitTests.add(new UT_program_store(this, mRes, mCtx));
+        unitTests.add(new UT_program_raster(this, mRes, mCtx));
         unitTests.add(new UT_fp_mad(this, mRes, mCtx));
+
         /*
         unitTests.add(new UnitTest(null, "<Pass>", 1));
         unitTests.add(new UnitTest());
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
index 1d2555e..04e9270 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-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.
@@ -48,6 +48,9 @@
         pRS.setMessageHandler(mRsMessage);
         initializeGlobals(pRS, s);
         s.forEach_root(A);
+        s.invoke_verify_root();
+        s.forEach_foo(A, A);
+        s.invoke_verify_foo();
         s.invoke_foreach_test();
         pRS.finish();
         waitForMessage();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java
new file mode 100644
index 0000000..c660fc5
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011-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.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_noroot extends UnitTest {
+    private Resources mRes;
+    private Allocation A;
+
+    protected UT_noroot(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "ForEach (no root)", ctx);
+        mRes = res;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_noroot s) {
+        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
+        int X = 5;
+        int Y = 7;
+        s.set_dimX(X);
+        s.set_dimY(Y);
+        typeBuilder.setX(X).setY(Y);
+        A = Allocation.createTyped(RS, typeBuilder.create());
+        s.bind_a(A);
+
+        return;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_noroot s = new ScriptC_noroot(pRS, mRes, R.raw.noroot);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.forEach_foo(A, A);
+        s.invoke_verify_foo();
+        s.invoke_noroot_test();
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
index 3ba3eef..ac527b5 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
@@ -3,12 +3,19 @@
 int *a;
 int dimX;
 int dimY;
+static bool failed = false;
 
 void root(int *out, uint32_t x, uint32_t y) {
     *out = x + y * dimX;
 }
 
-static bool test_foreach_output() {
+void foo(const int *in, int *out, uint32_t x, uint32_t y) {
+    _RS_ASSERT(*in == (x + y * dimX));
+    *out = 99 + x + y * dimX;
+    _RS_ASSERT(*out == (99 + x + y * dimX));
+}
+
+static bool test_root_output() {
     bool failed = false;
     int i, j;
 
@@ -19,19 +26,44 @@
     }
 
     if (failed) {
-        rsDebug("test_foreach_output FAILED", 0);
+        rsDebug("test_root_output FAILED", 0);
     }
     else {
-        rsDebug("test_foreach_output PASSED", 0);
+        rsDebug("test_root_output PASSED", 0);
     }
 
     return failed;
 }
 
-void foreach_test() {
+static bool test_foo_output() {
     bool failed = false;
-    failed |= test_foreach_output();
+    int i, j;
 
+    for (j = 0; j < dimY; j++) {
+        for (i = 0; i < dimX; i++) {
+            _RS_ASSERT(a[i + j * dimX] == (99 + i + j * dimX));
+        }
+    }
+
+    if (failed) {
+        rsDebug("test_foo_output FAILED", 0);
+    }
+    else {
+        rsDebug("test_foo_output PASSED", 0);
+    }
+
+    return failed;
+}
+
+void verify_root() {
+    failed |= test_root_output();
+}
+
+void verify_foo() {
+    failed |= test_foo_output();
+}
+
+void foreach_test() {
     if (failed) {
         rsSendToClientBlocking(RS_MSG_TEST_FAILED);
     }
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs
new file mode 100644
index 0000000..33944aa
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs
@@ -0,0 +1,44 @@
+#include "shared.rsh"
+
+int *a;
+int dimX;
+int dimY;
+static bool failed = false;
+
+void foo(const int *in, int *out, uint32_t x, uint32_t y) {
+    *out = 99 + x + y * dimX;
+}
+
+static bool test_foo_output() {
+    bool failed = false;
+    int i, j;
+
+    for (j = 0; j < dimY; j++) {
+        for (i = 0; i < dimX; i++) {
+            _RS_ASSERT(a[i + j * dimX] == (99 + i + j * dimX));
+        }
+    }
+
+    if (failed) {
+        rsDebug("test_foo_output FAILED", 0);
+    }
+    else {
+        rsDebug("test_foo_output PASSED", 0);
+    }
+
+    return failed;
+}
+
+void verify_foo() {
+    failed |= test_foo_output();
+}
+
+void noroot_test() {
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+