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