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