Home | History | Annotate | Download | only in cpu_ref
      1 /*
      2  * Copyright (C) 2011-2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "rsCpuCore.h"
     18 #include "rsCpuScript.h"
     19 
     20 #ifdef RS_COMPATIBILITY_LIB
     21     #include <set>
     22     #include <string>
     23     #include <dlfcn.h>
     24     #include <stdio.h>
     25     #include <stdlib.h>
     26     #include <string.h>
     27     #include <unistd.h>
     28 #else
     29     #include <bcc/BCCContext.h>
     30     #include <bcc/Renderscript/RSCompilerDriver.h>
     31     #include <bcc/Renderscript/RSExecutable.h>
     32     #include <bcc/Renderscript/RSInfo.h>
     33     #include <bcinfo/MetadataExtractor.h>
     34     #include <cutils/properties.h>
     35 
     36     #include <sys/types.h>
     37     #include <sys/wait.h>
     38     #include <unistd.h>
     39 #endif
     40 
     41 namespace {
     42 #ifdef RS_COMPATIBILITY_LIB
     43 
     44 // Create a len length string containing random characters from [A-Za-z0-9].
     45 static std::string getRandomString(size_t len) {
     46     char buf[len + 1];
     47     for (size_t i = 0; i < len; i++) {
     48         uint32_t r = arc4random() & 0xffff;
     49         r %= 62;
     50         if (r < 26) {
     51             // lowercase
     52             buf[i] = 'a' + r;
     53         } else if (r < 52) {
     54             // uppercase
     55             buf[i] = 'A' + (r - 26);
     56         } else {
     57             // Use a number
     58             buf[i] = '0' + (r - 52);
     59         }
     60     }
     61     buf[len] = '\0';
     62     return std::string(buf);
     63 }
     64 
     65 // Attempt to load the shared library from origName, but then fall back to
     66 // creating the symlinked shared library if necessary (to ensure instancing).
     67 // This function returns the dlopen()-ed handle if successful.
     68 static void *loadSOHelper(const char *origName, const char *cacheDir,
     69                           const char *resName) {
     70     // Keep track of which .so libraries have been loaded. Once a library is
     71     // in the set (per-process granularity), we must instead make a symlink to
     72     // the original shared object (randomly named .so file) and load that one
     73     // instead. If we don't do this, we end up aliasing global data between
     74     // the various Script instances (which are supposed to be completely
     75     // independent).
     76     static std::set<std::string> LoadedLibraries;
     77 
     78     void *loaded = NULL;
     79 
     80     // Skip everything if we don't even have the original library available.
     81     if (access(origName, F_OK) != 0) {
     82         return NULL;
     83     }
     84 
     85     // Common path is that we have not loaded this Script/library before.
     86     if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
     87         loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
     88         if (loaded) {
     89             LoadedLibraries.insert(origName);
     90         }
     91         return loaded;
     92     }
     93 
     94     // Construct an appropriately randomized filename for the symlink.
     95     std::string newName(cacheDir);
     96     newName.append("/com.android.renderscript.cache/librs.");
     97     newName.append(resName);
     98     newName.append("#");
     99     newName.append(getRandomString(6));  // 62^6 potential filename variants.
    100     newName.append(".so");
    101 
    102     int r = symlink(origName, newName.c_str());
    103     if (r != 0) {
    104         ALOGE("Could not create symlink %s -> %s", newName.c_str(), origName);
    105         return NULL;
    106     }
    107     loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
    108     r = unlink(newName.c_str());
    109     if (r != 0) {
    110         ALOGE("Could not unlink symlink %s", newName.c_str());
    111     }
    112     if (loaded) {
    113         LoadedLibraries.insert(newName.c_str());
    114     }
    115 
    116     return loaded;
    117 }
    118 
    119 // Load the shared library referred to by cacheDir and resName. If we have
    120 // already loaded this library, we instead create a new symlink (in the
    121 // cache dir) and then load that. We then immediately destroy the symlink.
    122 // This is required behavior to implement script instancing for the support
    123 // library, since shared objects are loaded and de-duped by name only.
    124 static void *loadSharedLibrary(const char *cacheDir, const char *resName) {
    125     void *loaded = NULL;
    126     //arc4random_stir();
    127 #ifndef RS_SERVER
    128     std::string scriptSOName(cacheDir);
    129     size_t cutPos = scriptSOName.rfind("cache");
    130     if (cutPos != std::string::npos) {
    131         scriptSOName.erase(cutPos);
    132     } else {
    133         ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir);
    134     }
    135     scriptSOName.append("/lib/librs.");
    136 #else
    137     std::string scriptSOName("lib");
    138 #endif
    139     scriptSOName.append(resName);
    140     scriptSOName.append(".so");
    141 
    142     // We should check if we can load the library from the standard app
    143     // location for shared libraries first.
    144     loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName);
    145 
    146     if (loaded == NULL) {
    147         ALOGE("Unable to open shared library (%s): %s",
    148               scriptSOName.c_str(), dlerror());
    149 
    150         // One final attempt to find the library in "/system/lib".
    151         // We do this to allow bundled applications to use the compatibility
    152         // library fallback path. Those applications don't have a private
    153         // library path, so they need to install to the system directly.
    154         // Note that this is really just a testing path.
    155         android::String8 scriptSONameSystem("/system/lib/librs.");
    156         scriptSONameSystem.append(resName);
    157         scriptSONameSystem.append(".so");
    158         loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir,
    159                               resName);
    160         if (loaded == NULL) {
    161             ALOGE("Unable to open system shared library (%s): %s",
    162                   scriptSONameSystem.c_str(), dlerror());
    163         }
    164     }
    165 
    166     return loaded;
    167 }
    168 
    169 
    170 #else
    171 static bool is_force_recompile() {
    172 #ifdef RS_SERVER
    173   return false;
    174 #else
    175   char buf[PROPERTY_VALUE_MAX];
    176 
    177   // Re-compile if floating point precision has been overridden.
    178   property_get("debug.rs.precision", buf, "");
    179   if (buf[0] != '\0') {
    180     return true;
    181   }
    182 
    183   // Re-compile if debug.rs.forcerecompile is set.
    184   property_get("debug.rs.forcerecompile", buf, "0");
    185   if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
    186     return true;
    187   } else {
    188     return false;
    189   }
    190 #endif  // RS_SERVER
    191 }
    192 
    193 //#define EXTERNAL_BCC_COMPILER 1
    194 #ifdef EXTERNAL_BCC_COMPILER
    195 const static char *BCC_EXE_PATH = "/system/bin/bcc";
    196 
    197 static bool compileBitcode(const char *cacheDir,
    198                            const char *resName,
    199                            const char *bitcode,
    200                            size_t bitcodeSize,
    201                            const char *core_lib) {
    202     rsAssert(cacheDir && resName && bitcode && bitcodeSize && core_lib);
    203 
    204     android::String8 bcFilename(cacheDir);
    205     bcFilename.append("/");
    206     bcFilename.append(resName);
    207     bcFilename.append(".bc");
    208     FILE *bcfile = fopen(bcFilename.string(), "w");
    209     if (!bcfile) {
    210         ALOGE("Could not write to %s", bcFilename.string());
    211         return false;
    212     }
    213     size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile);
    214     fclose(bcfile);
    215     if (nwritten != bitcodeSize) {
    216         ALOGE("Could not write %zu bytes to %s", bitcodeSize,
    217               bcFilename.string());
    218         return false;
    219     }
    220 
    221     pid_t pid = fork();
    222     switch (pid) {
    223     case -1: {  // Error occurred (we attempt no recovery)
    224         ALOGE("Couldn't fork for bcc compiler execution");
    225         return false;
    226     }
    227     case 0: {  // Child process
    228         // Execute the bcc compiler.
    229         execl(BCC_EXE_PATH,
    230               BCC_EXE_PATH,
    231               "-o", resName,
    232               "-output_path", cacheDir,
    233               "-bclib", core_lib,
    234               bcFilename.string(),
    235               (char *) NULL);
    236         ALOGE("execl() failed: %s", strerror(errno));
    237         abort();
    238         return false;
    239     }
    240     default: {  // Parent process (actual driver)
    241         // Wait on child process to finish compiling the source.
    242         int status = 0;
    243         pid_t w = waitpid(pid, &status, 0);
    244         if (w == -1) {
    245             ALOGE("Could not wait for bcc compiler");
    246             return false;
    247         }
    248 
    249         if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
    250             return true;
    251         }
    252 
    253         ALOGE("bcc compiler terminated unexpectedly");
    254         return false;
    255     }
    256     }
    257 }
    258 #endif  // EXTERNAL_BCC_COMPILER
    259 
    260 #endif  // !defined(RS_COMPATIBILITY_LIB)
    261 }  // namespace
    262 
    263 namespace android {
    264 namespace renderscript {
    265 
    266 
    267 #ifdef RS_COMPATIBILITY_LIB
    268 #define MAXLINE 500
    269 #define MAKE_STR_HELPER(S) #S
    270 #define MAKE_STR(S) MAKE_STR_HELPER(S)
    271 #define EXPORT_VAR_STR "exportVarCount: "
    272 #define EXPORT_VAR_STR_LEN strlen(EXPORT_VAR_STR)
    273 #define EXPORT_FUNC_STR "exportFuncCount: "
    274 #define EXPORT_FUNC_STR_LEN strlen(EXPORT_FUNC_STR)
    275 #define EXPORT_FOREACH_STR "exportForEachCount: "
    276 #define EXPORT_FOREACH_STR_LEN strlen(EXPORT_FOREACH_STR)
    277 #define OBJECT_SLOT_STR "objectSlotCount: "
    278 #define OBJECT_SLOT_STR_LEN strlen(OBJECT_SLOT_STR)
    279 
    280 // Copy up to a newline or size chars from str -> s, updating str
    281 // Returns s when successful and NULL when '\0' is finally reached.
    282 static char* strgets(char *s, int size, const char **ppstr) {
    283     if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
    284         return NULL;
    285     }
    286 
    287     int i;
    288     for (i = 0; i < (size - 1); i++) {
    289         s[i] = **ppstr;
    290         (*ppstr)++;
    291         if (s[i] == '\0') {
    292             return s;
    293         } else if (s[i] == '\n') {
    294             s[i+1] = '\0';
    295             return s;
    296         }
    297     }
    298 
    299     // size has been exceeded.
    300     s[i] = '\0';
    301 
    302     return s;
    303 }
    304 #endif
    305 
    306 RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
    307     mCtx = ctx;
    308     mScript = s;
    309 
    310 #ifdef RS_COMPATIBILITY_LIB
    311     mScriptSO = NULL;
    312     mInvokeFunctions = NULL;
    313     mForEachFunctions = NULL;
    314     mFieldAddress = NULL;
    315     mFieldIsObject = NULL;
    316     mForEachSignatures = NULL;
    317 #else
    318     mCompilerContext = NULL;
    319     mCompilerDriver = NULL;
    320     mExecutable = NULL;
    321 #endif
    322 
    323     mRoot = NULL;
    324     mRootExpand = NULL;
    325     mInit = NULL;
    326     mFreeChildren = NULL;
    327 
    328 
    329     mBoundAllocs = NULL;
    330     mIntrinsicData = NULL;
    331     mIsThreadable = true;
    332 }
    333 
    334 
    335 bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
    336                             uint8_t const *bitcode, size_t bitcodeSize,
    337                             uint32_t flags) {
    338     //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
    339     //ALOGE("rsdScriptInit %p %p", rsc, script);
    340 
    341     mCtx->lockMutex();
    342 
    343 #ifndef RS_COMPATIBILITY_LIB
    344     bcc::RSExecutable *exec = NULL;
    345 
    346     mCompilerContext = NULL;
    347     mCompilerDriver = NULL;
    348     mExecutable = NULL;
    349 
    350     mCompilerContext = new bcc::BCCContext();
    351     if (mCompilerContext == NULL) {
    352         ALOGE("bcc: FAILS to create compiler context (out of memory)");
    353         mCtx->unlockMutex();
    354         return false;
    355     }
    356 
    357     mCompilerDriver = new bcc::RSCompilerDriver();
    358     if (mCompilerDriver == NULL) {
    359         ALOGE("bcc: FAILS to create compiler driver (out of memory)");
    360         mCtx->unlockMutex();
    361         return false;
    362     }
    363 
    364     mCompilerDriver->setRSRuntimeLookupFunction(lookupRuntimeStub);
    365     mCompilerDriver->setRSRuntimeLookupContext(this);
    366 
    367     // Run any compiler setup functions we have been provided with.
    368     RSSetupCompilerCallback setupCompilerCallback =
    369             mCtx->getSetupCompilerCallback();
    370     if (setupCompilerCallback != NULL) {
    371         setupCompilerCallback(mCompilerDriver);
    372     }
    373 
    374     const char *core_lib = bcc::RSInfo::LibCLCorePath;
    375 
    376     bcinfo::MetadataExtractor ME((const char *) bitcode, bitcodeSize);
    377     if (!ME.extract()) {
    378         ALOGE("Could not extract metadata from bitcode");
    379         return false;
    380     }
    381 
    382     enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision();
    383     switch (prec) {
    384     case bcinfo::RS_FP_Imprecise:
    385     case bcinfo::RS_FP_Relaxed:
    386 #if defined(ARCH_ARM_HAVE_NEON)
    387         // NEON-capable devices can use an accelerated math library for all
    388         // reduced precision scripts.
    389         core_lib = bcc::RSInfo::LibCLCoreNEONPath;
    390 #endif
    391         break;
    392     case bcinfo::RS_FP_Full:
    393         break;
    394     default:
    395         ALOGE("Unknown precision for bitcode");
    396         return false;
    397     }
    398 
    399 #if defined(ARCH_X86_HAVE_SSE2)
    400     // SSE2- or above capable devices will use an optimized library.
    401     core_lib = bcc::RSInfo::LibCLCoreX86Path;
    402 #endif
    403 
    404     RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
    405     if (selectRTCallback != NULL) {
    406         core_lib = selectRTCallback((const char *)bitcode, bitcodeSize);
    407     }
    408 
    409     if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
    410         // Use the libclcore_debug.bc instead of the default library.
    411         core_lib = bcc::RSInfo::LibCLCoreDebugPath;
    412         mCompilerDriver->setDebugContext(true);
    413         // Skip the cache lookup
    414     } else if (!is_force_recompile()) {
    415         // Attempt to just load the script from cache first if we can.
    416         exec = mCompilerDriver->loadScript(cacheDir, resName,
    417                                            (const char *)bitcode, bitcodeSize);
    418     }
    419 
    420     if (exec == NULL) {
    421 #ifdef EXTERNAL_BCC_COMPILER
    422         bool built = compileBitcode(cacheDir, resName, (const char *)bitcode,
    423                                     bitcodeSize, core_lib);
    424 #else
    425         bool built = mCompilerDriver->build(*mCompilerContext, cacheDir,
    426                                             resName, (const char *)bitcode,
    427                                             bitcodeSize, core_lib,
    428                                             mCtx->getLinkRuntimeCallback());
    429 #endif  // EXTERNAL_BCC_COMPILER
    430         if (built) {
    431             exec = mCompilerDriver->loadScript(cacheDir, resName,
    432                                                (const char *)bitcode,
    433                                                bitcodeSize);
    434         }
    435     }
    436 
    437     if (exec == NULL) {
    438         ALOGE("bcc: FAILS to prepare executable for '%s'", resName);
    439         mCtx->unlockMutex();
    440         return false;
    441     }
    442 
    443     mExecutable = exec;
    444 
    445     exec->setThreadable(mIsThreadable);
    446     if (!exec->syncInfo()) {
    447         ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
    448     }
    449 
    450     mRoot = reinterpret_cast<int (*)()>(exec->getSymbolAddress("root"));
    451     mRootExpand =
    452         reinterpret_cast<int (*)()>(exec->getSymbolAddress("root.expand"));
    453     mInit = reinterpret_cast<void (*)()>(exec->getSymbolAddress("init"));
    454     mFreeChildren =
    455         reinterpret_cast<void (*)()>(exec->getSymbolAddress(".rs.dtor"));
    456 
    457 
    458     const bcc::RSInfo *info = &mExecutable->getInfo();
    459     if (info->getExportVarNames().size()) {
    460         mBoundAllocs = new Allocation *[info->getExportVarNames().size()];
    461         memset(mBoundAllocs, 0, sizeof(void *) * info->getExportVarNames().size());
    462     }
    463 
    464 #else
    465 
    466     mScriptSO = loadSharedLibrary(cacheDir, resName);
    467 
    468     if (mScriptSO) {
    469         char line[MAXLINE];
    470         mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
    471         if (mRoot) {
    472             //ALOGE("Found root(): %p", mRoot);
    473         }
    474         mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
    475         if (mRootExpand) {
    476             //ALOGE("Found root.expand(): %p", mRootExpand);
    477         }
    478         mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
    479         if (mInit) {
    480             //ALOGE("Found init(): %p", mInit);
    481         }
    482         mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
    483         if (mFreeChildren) {
    484             //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
    485         }
    486 
    487         const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
    488         if (rsInfo) {
    489             //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
    490         }
    491 
    492         size_t varCount = 0;
    493         if (strgets(line, MAXLINE, &rsInfo) == NULL) {
    494             goto error;
    495         }
    496         if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
    497             ALOGE("Invalid export var count!: %s", line);
    498             goto error;
    499         }
    500 
    501         mExportedVariableCount = varCount;
    502         //ALOGE("varCount: %zu", varCount);
    503         if (varCount > 0) {
    504             // Start by creating/zeroing this member, since we don't want to
    505             // accidentally clean up invalid pointers later (if we error out).
    506             mFieldIsObject = new bool[varCount];
    507             if (mFieldIsObject == NULL) {
    508                 goto error;
    509             }
    510             memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
    511             mFieldAddress = new void*[varCount];
    512             if (mFieldAddress == NULL) {
    513                 goto error;
    514             }
    515             for (size_t i = 0; i < varCount; ++i) {
    516                 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
    517                     goto error;
    518                 }
    519                 char *c = strrchr(line, '\n');
    520                 if (c) {
    521                     *c = '\0';
    522                 }
    523                 mFieldAddress[i] = dlsym(mScriptSO, line);
    524                 if (mFieldAddress[i] == NULL) {
    525                     ALOGE("Failed to find variable address for %s: %s",
    526                           line, dlerror());
    527                     // Not a critical error if we don't find a global variable.
    528                 }
    529                 else {
    530                     //ALOGE("Found variable %s at %p", line,
    531                     //mFieldAddress[i]);
    532                 }
    533             }
    534         }
    535 
    536         size_t funcCount = 0;
    537         if (strgets(line, MAXLINE, &rsInfo) == NULL) {
    538             goto error;
    539         }
    540         if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
    541             ALOGE("Invalid export func count!: %s", line);
    542             goto error;
    543         }
    544 
    545         mExportedFunctionCount = funcCount;
    546         //ALOGE("funcCount: %zu", funcCount);
    547 
    548         if (funcCount > 0) {
    549             mInvokeFunctions = new InvokeFunc_t[funcCount];
    550             if (mInvokeFunctions == NULL) {
    551                 goto error;
    552             }
    553             for (size_t i = 0; i < funcCount; ++i) {
    554                 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
    555                     goto error;
    556                 }
    557                 char *c = strrchr(line, '\n');
    558                 if (c) {
    559                     *c = '\0';
    560                 }
    561 
    562                 mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
    563                 if (mInvokeFunctions[i] == NULL) {
    564                     ALOGE("Failed to get function address for %s(): %s",
    565                           line, dlerror());
    566                     goto error;
    567                 }
    568                 else {
    569                     //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
    570                 }
    571             }
    572         }
    573 
    574         size_t forEachCount = 0;
    575         if (strgets(line, MAXLINE, &rsInfo) == NULL) {
    576             goto error;
    577         }
    578         if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
    579             ALOGE("Invalid export forEach count!: %s", line);
    580             goto error;
    581         }
    582 
    583         if (forEachCount > 0) {
    584 
    585             mForEachSignatures = new uint32_t[forEachCount];
    586             if (mForEachSignatures == NULL) {
    587                 goto error;
    588             }
    589             mForEachFunctions = new ForEachFunc_t[forEachCount];
    590             if (mForEachFunctions == NULL) {
    591                 goto error;
    592             }
    593             for (size_t i = 0; i < forEachCount; ++i) {
    594                 unsigned int tmpSig = 0;
    595                 char tmpName[MAXLINE];
    596 
    597                 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
    598                     goto error;
    599                 }
    600                 if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
    601                            &tmpSig, tmpName) != 2) {
    602                     ALOGE("Invalid export forEach!: %s", line);
    603                     goto error;
    604                 }
    605 
    606                 // Lookup the expanded ForEach kernel.
    607                 strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
    608                 mForEachSignatures[i] = tmpSig;
    609                 mForEachFunctions[i] =
    610                         (ForEachFunc_t) dlsym(mScriptSO, tmpName);
    611                 if (i != 0 && mForEachFunctions[i] == NULL) {
    612                     // Ignore missing root.expand functions.
    613                     // root() is always specified at location 0.
    614                     ALOGE("Failed to find forEach function address for %s: %s",
    615                           tmpName, dlerror());
    616                     goto error;
    617                 }
    618                 else {
    619                     //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
    620                 }
    621             }
    622         }
    623 
    624         size_t objectSlotCount = 0;
    625         if (strgets(line, MAXLINE, &rsInfo) == NULL) {
    626             goto error;
    627         }
    628         if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
    629             ALOGE("Invalid object slot count!: %s", line);
    630             goto error;
    631         }
    632 
    633         if (objectSlotCount > 0) {
    634             rsAssert(varCount > 0);
    635             for (size_t i = 0; i < objectSlotCount; ++i) {
    636                 uint32_t varNum = 0;
    637                 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
    638                     goto error;
    639                 }
    640                 if (sscanf(line, "%u", &varNum) != 1) {
    641                     ALOGE("Invalid object slot!: %s", line);
    642                     goto error;
    643                 }
    644 
    645                 if (varNum < varCount) {
    646                     mFieldIsObject[varNum] = true;
    647                 }
    648             }
    649         }
    650 
    651         if (varCount > 0) {
    652             mBoundAllocs = new Allocation *[varCount];
    653             memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
    654         }
    655 
    656         if (mScriptSO == (void*)1) {
    657             //rsdLookupRuntimeStub(script, "acos");
    658         }
    659     } else {
    660         goto error;
    661     }
    662 #endif
    663 
    664     mCtx->unlockMutex();
    665     return true;
    666 
    667 #ifdef RS_COMPATIBILITY_LIB
    668 error:
    669 
    670     mCtx->unlockMutex();
    671     delete[] mInvokeFunctions;
    672     delete[] mForEachFunctions;
    673     delete[] mFieldAddress;
    674     delete[] mFieldIsObject;
    675     delete[] mForEachSignatures;
    676     delete[] mBoundAllocs;
    677     if (mScriptSO) {
    678         dlclose(mScriptSO);
    679     }
    680     return false;
    681 #endif
    682 }
    683 
    684 void RsdCpuScriptImpl::populateScript(Script *script) {
    685 #ifndef RS_COMPATIBILITY_LIB
    686     const bcc::RSInfo *info = &mExecutable->getInfo();
    687 
    688     // Copy info over to runtime
    689     script->mHal.info.exportedFunctionCount = info->getExportFuncNames().size();
    690     script->mHal.info.exportedVariableCount = info->getExportVarNames().size();
    691     script->mHal.info.exportedForeachFuncList = info->getExportForeachFuncs().array();
    692     script->mHal.info.exportedPragmaCount = info->getPragmas().size();
    693     script->mHal.info.exportedPragmaKeyList =
    694         const_cast<const char**>(mExecutable->getPragmaKeys().array());
    695     script->mHal.info.exportedPragmaValueList =
    696         const_cast<const char**>(mExecutable->getPragmaValues().array());
    697 
    698     if (mRootExpand) {
    699         script->mHal.info.root = mRootExpand;
    700     } else {
    701         script->mHal.info.root = mRoot;
    702     }
    703 #else
    704     // Copy info over to runtime
    705     script->mHal.info.exportedFunctionCount = mExportedFunctionCount;
    706     script->mHal.info.exportedVariableCount = mExportedVariableCount;
    707     script->mHal.info.exportedPragmaCount = 0;
    708     script->mHal.info.exportedPragmaKeyList = 0;
    709     script->mHal.info.exportedPragmaValueList = 0;
    710 
    711     // Bug, need to stash in metadata
    712     if (mRootExpand) {
    713         script->mHal.info.root = mRootExpand;
    714     } else {
    715         script->mHal.info.root = mRoot;
    716     }
    717 #endif
    718 }
    719 
    720 
    721 typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
    722 
    723 void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation * ain, Allocation * aout,
    724                                         const void * usr, uint32_t usrLen,
    725                                         const RsScriptCall *sc,
    726                                         MTLaunchStruct *mtls) {
    727 
    728     memset(mtls, 0, sizeof(MTLaunchStruct));
    729 
    730     // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
    731     if (ain && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) {
    732         mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null in allocations");
    733         return;
    734     }
    735     if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) {
    736         mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null out allocations");
    737         return;
    738     }
    739 
    740     if (ain) {
    741         mtls->fep.dimX = ain->getType()->getDimX();
    742         mtls->fep.dimY = ain->getType()->getDimY();
    743         mtls->fep.dimZ = ain->getType()->getDimZ();
    744         //mtls->dimArray = ain->getType()->getDimArray();
    745     } else if (aout) {
    746         mtls->fep.dimX = aout->getType()->getDimX();
    747         mtls->fep.dimY = aout->getType()->getDimY();
    748         mtls->fep.dimZ = aout->getType()->getDimZ();
    749         //mtls->dimArray = aout->getType()->getDimArray();
    750     } else {
    751         mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
    752         return;
    753     }
    754 
    755     if (!sc || (sc->xEnd == 0)) {
    756         mtls->xEnd = mtls->fep.dimX;
    757     } else {
    758         rsAssert(sc->xStart < mtls->fep.dimX);
    759         rsAssert(sc->xEnd <= mtls->fep.dimX);
    760         rsAssert(sc->xStart < sc->xEnd);
    761         mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
    762         mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
    763         if (mtls->xStart >= mtls->xEnd) return;
    764     }
    765 
    766     if (!sc || (sc->yEnd == 0)) {
    767         mtls->yEnd = mtls->fep.dimY;
    768     } else {
    769         rsAssert(sc->yStart < mtls->fep.dimY);
    770         rsAssert(sc->yEnd <= mtls->fep.dimY);
    771         rsAssert(sc->yStart < sc->yEnd);
    772         mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
    773         mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
    774         if (mtls->yStart >= mtls->yEnd) return;
    775     }
    776 
    777     if (!sc || (sc->zEnd == 0)) {
    778         mtls->zEnd = mtls->fep.dimZ;
    779     } else {
    780         rsAssert(sc->zStart < mtls->fep.dimZ);
    781         rsAssert(sc->zEnd <= mtls->fep.dimZ);
    782         rsAssert(sc->zStart < sc->zEnd);
    783         mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
    784         mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
    785         if (mtls->zStart >= mtls->zEnd) return;
    786     }
    787 
    788     mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
    789     mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
    790     mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
    791     mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
    792 
    793     rsAssert(!ain || (ain->getType()->getDimZ() == 0));
    794 
    795     mtls->rsc = mCtx;
    796     mtls->ain = ain;
    797     mtls->aout = aout;
    798     mtls->fep.usr = usr;
    799     mtls->fep.usrLen = usrLen;
    800     mtls->mSliceSize = 1;
    801     mtls->mSliceNum = 0;
    802 
    803     mtls->fep.ptrIn = NULL;
    804     mtls->fep.eStrideIn = 0;
    805     mtls->isThreadable = mIsThreadable;
    806 
    807     if (ain) {
    808         mtls->fep.ptrIn = (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr;
    809         mtls->fep.eStrideIn = ain->getType()->getElementSizeBytes();
    810         mtls->fep.yStrideIn = ain->mHal.drvState.lod[0].stride;
    811     }
    812 
    813     mtls->fep.ptrOut = NULL;
    814     mtls->fep.eStrideOut = 0;
    815     if (aout) {
    816         mtls->fep.ptrOut = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
    817         mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes();
    818         mtls->fep.yStrideOut = aout->mHal.drvState.lod[0].stride;
    819     }
    820 }
    821 
    822 
    823 void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
    824                                      const Allocation * ain,
    825                                      Allocation * aout,
    826                                      const void * usr,
    827                                      uint32_t usrLen,
    828                                      const RsScriptCall *sc) {
    829 
    830     MTLaunchStruct mtls;
    831     forEachMtlsSetup(ain, aout, usr, usrLen, sc, &mtls);
    832     forEachKernelSetup(slot, &mtls);
    833 
    834     RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
    835     mCtx->launchThreads(ain, aout, sc, &mtls);
    836     mCtx->setTLS(oldTLS);
    837 }
    838 
    839 void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
    840     mtls->script = this;
    841     mtls->fep.slot = slot;
    842 #ifndef RS_COMPATIBILITY_LIB
    843     rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
    844     mtls->kernel = reinterpret_cast<ForEachFunc_t>(
    845                       mExecutable->getExportForeachFuncAddrs()[slot]);
    846     rsAssert(mtls->kernel != NULL);
    847     mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
    848 #else
    849     mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
    850     rsAssert(mtls->kernel != NULL);
    851     mtls->sig = mForEachSignatures[slot];
    852 #endif
    853 }
    854 
    855 int RsdCpuScriptImpl::invokeRoot() {
    856     RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
    857     int ret = mRoot();
    858     mCtx->setTLS(oldTLS);
    859     return ret;
    860 }
    861 
    862 void RsdCpuScriptImpl::invokeInit() {
    863     if (mInit) {
    864         mInit();
    865     }
    866 }
    867 
    868 void RsdCpuScriptImpl::invokeFreeChildren() {
    869     if (mFreeChildren) {
    870         mFreeChildren();
    871     }
    872 }
    873 
    874 void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
    875                                       size_t paramLength) {
    876     //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
    877 
    878     RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
    879     reinterpret_cast<void (*)(const void *, uint32_t)>(
    880 #ifndef RS_COMPATIBILITY_LIB
    881         mExecutable->getExportFuncAddrs()[slot])(params, paramLength);
    882 #else
    883         mInvokeFunctions[slot])(params, paramLength);
    884 #endif
    885     mCtx->setTLS(oldTLS);
    886 }
    887 
    888 void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
    889     //rsAssert(!script->mFieldIsObject[slot]);
    890     //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
    891 
    892     //if (mIntrinsicID) {
    893         //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
    894         //return;
    895     //}
    896 
    897 #ifndef RS_COMPATIBILITY_LIB
    898     int32_t *destPtr = reinterpret_cast<int32_t *>(
    899                           mExecutable->getExportVarAddrs()[slot]);
    900 #else
    901     int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
    902 #endif
    903     if (!destPtr) {
    904         //ALOGV("Calling setVar on slot = %i which is null", slot);
    905         return;
    906     }
    907 
    908     memcpy(destPtr, data, dataLength);
    909 }
    910 
    911 void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
    912     //rsAssert(!script->mFieldIsObject[slot]);
    913     //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
    914 
    915 #ifndef RS_COMPATIBILITY_LIB
    916     int32_t *srcPtr = reinterpret_cast<int32_t *>(
    917                           mExecutable->getExportVarAddrs()[slot]);
    918 #else
    919     int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
    920 #endif
    921     if (!srcPtr) {
    922         //ALOGV("Calling setVar on slot = %i which is null", slot);
    923         return;
    924     }
    925     memcpy(data, srcPtr, dataLength);
    926 }
    927 
    928 
    929 void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
    930                                                 const Element *elem,
    931                                                 const size_t *dims, size_t dimLength) {
    932 
    933 #ifndef RS_COMPATIBILITY_LIB
    934     int32_t *destPtr = reinterpret_cast<int32_t *>(
    935         mExecutable->getExportVarAddrs()[slot]);
    936 #else
    937     int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
    938 #endif
    939     if (!destPtr) {
    940         //ALOGV("Calling setVar on slot = %i which is null", slot);
    941         return;
    942     }
    943 
    944     // We want to look at dimension in terms of integer components,
    945     // but dimLength is given in terms of bytes.
    946     dimLength /= sizeof(int);
    947 
    948     // Only a single dimension is currently supported.
    949     rsAssert(dimLength == 1);
    950     if (dimLength == 1) {
    951         // First do the increment loop.
    952         size_t stride = elem->getSizeBytes();
    953         const char *cVal = reinterpret_cast<const char *>(data);
    954         for (size_t i = 0; i < dims[0]; i++) {
    955             elem->incRefs(cVal);
    956             cVal += stride;
    957         }
    958 
    959         // Decrement loop comes after (to prevent race conditions).
    960         char *oldVal = reinterpret_cast<char *>(destPtr);
    961         for (size_t i = 0; i < dims[0]; i++) {
    962             elem->decRefs(oldVal);
    963             oldVal += stride;
    964         }
    965     }
    966 
    967     memcpy(destPtr, data, dataLength);
    968 }
    969 
    970 void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
    971 
    972     //rsAssert(!script->mFieldIsObject[slot]);
    973     //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
    974 
    975 #ifndef RS_COMPATIBILITY_LIB
    976     int32_t *destPtr = reinterpret_cast<int32_t *>(
    977                           mExecutable->getExportVarAddrs()[slot]);
    978 #else
    979     int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
    980 #endif
    981     if (!destPtr) {
    982         //ALOGV("Calling setVar on slot = %i which is null", slot);
    983         return;
    984     }
    985 
    986     void *ptr = NULL;
    987     mBoundAllocs[slot] = data;
    988     if(data) {
    989         ptr = data->mHal.drvState.lod[0].mallocPtr;
    990     }
    991     memcpy(destPtr, &ptr, sizeof(void *));
    992 }
    993 
    994 void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
    995 
    996     //rsAssert(script->mFieldIsObject[slot]);
    997     //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
    998 
    999     //if (mIntrinsicID) {
   1000         //mIntrinsicFuncs.setVarObj(dc, script, drv->mIntrinsicData, slot, alloc);
   1001         //return;
   1002     //}
   1003 
   1004 #ifndef RS_COMPATIBILITY_LIB
   1005     int32_t *destPtr = reinterpret_cast<int32_t *>(
   1006                           mExecutable->getExportVarAddrs()[slot]);
   1007 #else
   1008     int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
   1009 #endif
   1010     if (!destPtr) {
   1011         //ALOGV("Calling setVar on slot = %i which is null", slot);
   1012         return;
   1013     }
   1014 
   1015     rsrSetObject(mCtx->getContext(), (ObjectBase **)destPtr, data);
   1016 }
   1017 
   1018 RsdCpuScriptImpl::~RsdCpuScriptImpl() {
   1019 #ifndef RS_COMPATIBILITY_LIB
   1020     if (mExecutable) {
   1021         Vector<void *>::const_iterator var_addr_iter =
   1022             mExecutable->getExportVarAddrs().begin();
   1023         Vector<void *>::const_iterator var_addr_end =
   1024             mExecutable->getExportVarAddrs().end();
   1025 
   1026         bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter =
   1027             mExecutable->getInfo().getObjectSlots().begin();
   1028         bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end =
   1029             mExecutable->getInfo().getObjectSlots().end();
   1030 
   1031         while ((var_addr_iter != var_addr_end) &&
   1032                (is_object_iter != is_object_end)) {
   1033             // The field address can be NULL if the script-side has optimized
   1034             // the corresponding global variable away.
   1035             ObjectBase **obj_addr =
   1036                 reinterpret_cast<ObjectBase **>(*var_addr_iter);
   1037             if (*is_object_iter) {
   1038                 if (*var_addr_iter != NULL) {
   1039                     rsrClearObject(mCtx->getContext(), obj_addr);
   1040                 }
   1041             }
   1042             var_addr_iter++;
   1043             is_object_iter++;
   1044         }
   1045     }
   1046 
   1047     if (mCompilerContext) {
   1048         delete mCompilerContext;
   1049     }
   1050     if (mCompilerDriver) {
   1051         delete mCompilerDriver;
   1052     }
   1053     if (mExecutable) {
   1054         delete mExecutable;
   1055     }
   1056     if (mBoundAllocs) {
   1057         delete[] mBoundAllocs;
   1058     }
   1059 #else
   1060     if (mFieldIsObject) {
   1061         for (size_t i = 0; i < mExportedVariableCount; ++i) {
   1062             if (mFieldIsObject[i]) {
   1063                 if (mFieldAddress[i] != NULL) {
   1064                     ObjectBase **obj_addr =
   1065                         reinterpret_cast<ObjectBase **>(mFieldAddress[i]);
   1066                     rsrClearObject(mCtx->getContext(), obj_addr);
   1067                 }
   1068             }
   1069         }
   1070     }
   1071 
   1072     if (mInvokeFunctions) delete[] mInvokeFunctions;
   1073     if (mForEachFunctions) delete[] mForEachFunctions;
   1074     if (mFieldAddress) delete[] mFieldAddress;
   1075     if (mFieldIsObject) delete[] mFieldIsObject;
   1076     if (mForEachSignatures) delete[] mForEachSignatures;
   1077     if (mBoundAllocs) delete[] mBoundAllocs;
   1078     if (mScriptSO) {
   1079         dlclose(mScriptSO);
   1080     }
   1081 #endif
   1082 }
   1083 
   1084 Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const {
   1085     if (!ptr) {
   1086         return NULL;
   1087     }
   1088 
   1089     for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) {
   1090         Allocation *a = mBoundAllocs[ct];
   1091         if (!a) continue;
   1092         if (a->mHal.drvState.lod[0].mallocPtr == ptr) {
   1093             return a;
   1094         }
   1095     }
   1096     ALOGE("rsGetAllocation, failed to find %p", ptr);
   1097     return NULL;
   1098 }
   1099 
   1100 void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation * ain,
   1101                        Allocation * aout, const void * usr,
   1102                        uint32_t usrLen, const RsScriptCall *sc)
   1103 {
   1104 }
   1105 
   1106 void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation * ain,
   1107                         Allocation * aout, const void * usr,
   1108                         uint32_t usrLen, const RsScriptCall *sc)
   1109 {
   1110 }
   1111 
   1112 
   1113 }
   1114 }
   1115