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