rsCpuScript.cpp revision 99281b5bc2a81a42fa490ddbc1496621c2d84486
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
219const static char *BCC_EXE_PATH = "/system/bin/bcc";
220
221static bool compileBitcode(const char *cacheDir,
222                           const char *resName,
223                           const char *bitcode,
224                           size_t bitcodeSize,
225                           const char *core_lib,
226                           bool useRSDebugContext,
227                           const char *bccPluginName) {
228    rsAssert(cacheDir && resName && bitcode && bitcodeSize && core_lib);
229
230    android::String8 bcFilename(cacheDir);
231    bcFilename.append("/");
232    bcFilename.append(resName);
233    bcFilename.append(".bc");
234    FILE *bcfile = fopen(bcFilename.string(), "w");
235    if (!bcfile) {
236        ALOGE("Could not write to %s", bcFilename.string());
237        return false;
238    }
239    size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile);
240    fclose(bcfile);
241    if (nwritten != bitcodeSize) {
242        ALOGE("Could not write %zu bytes to %s", bitcodeSize,
243              bcFilename.string());
244        return false;
245    }
246
247    pid_t pid = fork();
248
249    switch (pid) {
250    case -1: {  // Error occurred (we attempt no recovery)
251        ALOGE("Couldn't fork for bcc compiler execution");
252        return false;
253    }
254    case 0: {  // Child process
255        std::vector<std::string> args;
256        args.push_back(BCC_EXE_PATH);
257        args.push_back("-o");
258        args.push_back(resName);
259        args.push_back("-output_path");
260        args.push_back(cacheDir);
261        args.push_back("-bclib");
262        args.push_back(core_lib);
263
264        // Execute the bcc compiler.
265        if (useRSDebugContext) {
266            args.push_back("-rs-debug-ctx");
267        } else {
268            // Only load additional libraries for compiles that don't use
269            // the debug context.
270            if (bccPluginName && strlen(bccPluginName) > 0) {
271                args.push_back("-load");
272                args.push_back(bccPluginName);
273            }
274        }
275
276        args.push_back(bcFilename.string());
277
278        const char **cargs = new const char *[args.size() + 1];
279        for (uint32_t i = 0; i < args.size(); i++) {
280            cargs[i] = args[i].c_str();
281        }
282        cargs[args.size()] = NULL;
283
284        execv(BCC_EXE_PATH, (char *const *)cargs);
285
286        delete [] cargs;
287        ALOGE("execv() failed: %s", strerror(errno));
288        abort();
289        return false;
290    }
291    default: {  // Parent process (actual driver)
292        // Wait on child process to finish compiling the source.
293        int status = 0;
294        pid_t w = waitpid(pid, &status, 0);
295        if (w == -1) {
296            ALOGE("Could not wait for bcc compiler");
297            return false;
298        }
299
300        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
301            return true;
302        }
303
304        ALOGE("bcc compiler terminated unexpectedly");
305        return false;
306    }
307    }
308}
309
310#endif  // !defined(RS_COMPATIBILITY_LIB)
311#endif
312}  // namespace
313
314namespace android {
315namespace renderscript {
316
317#ifdef RS_COMPATIBILITY_LIB
318#define MAXLINE 500
319#define MAKE_STR_HELPER(S) #S
320#define MAKE_STR(S) MAKE_STR_HELPER(S)
321#define EXPORT_VAR_STR "exportVarCount: "
322#define EXPORT_VAR_STR_LEN strlen(EXPORT_VAR_STR)
323#define EXPORT_FUNC_STR "exportFuncCount: "
324#define EXPORT_FUNC_STR_LEN strlen(EXPORT_FUNC_STR)
325#define EXPORT_FOREACH_STR "exportForEachCount: "
326#define EXPORT_FOREACH_STR_LEN strlen(EXPORT_FOREACH_STR)
327#define OBJECT_SLOT_STR "objectSlotCount: "
328#define OBJECT_SLOT_STR_LEN strlen(OBJECT_SLOT_STR)
329
330// Copy up to a newline or size chars from str -> s, updating str
331// Returns s when successful and NULL when '\0' is finally reached.
332static char* strgets(char *s, int size, const char **ppstr) {
333    if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
334        return NULL;
335    }
336
337    int i;
338    for (i = 0; i < (size - 1); i++) {
339        s[i] = **ppstr;
340        (*ppstr)++;
341        if (s[i] == '\0') {
342            return s;
343        } else if (s[i] == '\n') {
344            s[i+1] = '\0';
345            return s;
346        }
347    }
348
349    // size has been exceeded.
350    s[i] = '\0';
351
352    return s;
353}
354#endif
355
356RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
357    mCtx = ctx;
358    mScript = s;
359
360#ifndef FAKE_ARM64_BUILD
361#ifdef RS_COMPATIBILITY_LIB
362    mScriptSO = NULL;
363    mInvokeFunctions = NULL;
364    mForEachFunctions = NULL;
365    mFieldAddress = NULL;
366    mFieldIsObject = NULL;
367    mForEachSignatures = NULL;
368#else
369    mCompilerContext = NULL;
370    mCompilerDriver = NULL;
371    mExecutable = NULL;
372#endif
373
374
375    mRoot = NULL;
376    mRootExpand = NULL;
377    mInit = NULL;
378    mFreeChildren = NULL;
379
380
381    mBoundAllocs = NULL;
382    mIntrinsicData = NULL;
383    mIsThreadable = true;
384#endif
385}
386
387
388bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
389                            uint8_t const *bitcode, size_t bitcodeSize,
390                            uint32_t flags, char const *bccPluginName) {
391    //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
392    //ALOGE("rsdScriptInit %p %p", rsc, script);
393
394    mCtx->lockMutex();
395#ifndef FAKE_ARM64_BUILD
396#ifndef RS_COMPATIBILITY_LIB
397    bcc::RSExecutable *exec = NULL;
398    bool useRSDebugContext = false;
399
400    mCompilerContext = NULL;
401    mCompilerDriver = NULL;
402    mExecutable = NULL;
403
404    mCompilerContext = new bcc::BCCContext();
405    if (mCompilerContext == NULL) {
406        ALOGE("bcc: FAILS to create compiler context (out of memory)");
407        mCtx->unlockMutex();
408        return false;
409    }
410
411    mCompilerDriver = new bcc::RSCompilerDriver();
412    if (mCompilerDriver == NULL) {
413        ALOGE("bcc: FAILS to create compiler driver (out of memory)");
414        mCtx->unlockMutex();
415        return false;
416    }
417
418    mCompilerDriver->setRSRuntimeLookupFunction(lookupRuntimeStub);
419    mCompilerDriver->setRSRuntimeLookupContext(this);
420
421    // Run any compiler setup functions we have been provided with.
422    RSSetupCompilerCallback setupCompilerCallback =
423            mCtx->getSetupCompilerCallback();
424    if (setupCompilerCallback != NULL) {
425        setupCompilerCallback(mCompilerDriver);
426    }
427
428    const char *core_lib = bcc::RSInfo::LibCLCorePath;
429
430    bcinfo::MetadataExtractor ME((const char *) bitcode, bitcodeSize);
431    if (!ME.extract()) {
432        ALOGE("Could not extract metadata from bitcode");
433        return false;
434    }
435
436    enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision();
437    switch (prec) {
438    case bcinfo::RS_FP_Imprecise:
439    case bcinfo::RS_FP_Relaxed:
440#if defined(ARCH_ARM_HAVE_NEON)
441        // NEON-capable devices can use an accelerated math library for all
442        // reduced precision scripts.
443        core_lib = bcc::RSInfo::LibCLCoreNEONPath;
444#endif
445        break;
446    case bcinfo::RS_FP_Full:
447        break;
448    default:
449        ALOGE("Unknown precision for bitcode");
450        return false;
451    }
452
453#if defined(__i386__)
454    // x86 devices will use an optimized library.
455     core_lib = bcc::RSInfo::LibCLCoreX86Path;
456#endif
457
458    RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
459    if (selectRTCallback != NULL) {
460        core_lib = selectRTCallback((const char *)bitcode, bitcodeSize);
461    }
462
463    if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
464        // Use the libclcore_debug.bc instead of the default library.
465        core_lib = bcc::RSInfo::LibCLCoreDebugPath;
466        mCompilerDriver->setDebugContext(true);
467        useRSDebugContext = true;
468        // Skip the cache lookup
469    } else if (!is_force_recompile()) {
470        // Attempt to just load the script from cache first if we can.
471        exec = mCompilerDriver->loadScript(cacheDir, resName,
472                                           (const char *)bitcode, bitcodeSize);
473    }
474
475    if (exec == NULL) {
476        bool built = compileBitcode(cacheDir, resName, (const char *)bitcode,
477                                    bitcodeSize, core_lib, useRSDebugContext,
478                                    bccPluginName);
479        if (built) {
480            exec = mCompilerDriver->loadScript(cacheDir, resName,
481                                               (const char *)bitcode,
482                                               bitcodeSize);
483        }
484    }
485
486    if (exec == NULL) {
487        ALOGE("bcc: FAILS to prepare executable for '%s'", resName);
488        mCtx->unlockMutex();
489        return false;
490    }
491
492    mExecutable = exec;
493
494    exec->setThreadable(mIsThreadable);
495    if (!exec->syncInfo()) {
496        ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
497    }
498
499    mRoot = reinterpret_cast<int (*)()>(exec->getSymbolAddress("root"));
500    mRootExpand =
501        reinterpret_cast<int (*)()>(exec->getSymbolAddress("root.expand"));
502    mInit = reinterpret_cast<void (*)()>(exec->getSymbolAddress("init"));
503    mFreeChildren =
504        reinterpret_cast<void (*)()>(exec->getSymbolAddress(".rs.dtor"));
505
506
507    const bcc::RSInfo *info = &mExecutable->getInfo();
508    if (info->getExportVarNames().size()) {
509        mBoundAllocs = new Allocation *[info->getExportVarNames().size()];
510        memset(mBoundAllocs, 0, sizeof(void *) * info->getExportVarNames().size());
511    }
512
513#else
514
515    mScriptSO = loadSharedLibrary(cacheDir, resName);
516
517    if (mScriptSO) {
518        char line[MAXLINE];
519        mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
520        if (mRoot) {
521            //ALOGE("Found root(): %p", mRoot);
522        }
523        mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
524        if (mRootExpand) {
525            //ALOGE("Found root.expand(): %p", mRootExpand);
526        }
527        mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
528        if (mInit) {
529            //ALOGE("Found init(): %p", mInit);
530        }
531        mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
532        if (mFreeChildren) {
533            //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
534        }
535
536        const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
537        if (rsInfo) {
538            //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
539        }
540
541        size_t varCount = 0;
542        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
543            goto error;
544        }
545        if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
546            ALOGE("Invalid export var count!: %s", line);
547            goto error;
548        }
549
550        mExportedVariableCount = varCount;
551        //ALOGE("varCount: %zu", varCount);
552        if (varCount > 0) {
553            // Start by creating/zeroing this member, since we don't want to
554            // accidentally clean up invalid pointers later (if we error out).
555            mFieldIsObject = new bool[varCount];
556            if (mFieldIsObject == NULL) {
557                goto error;
558            }
559            memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
560            mFieldAddress = new void*[varCount];
561            if (mFieldAddress == NULL) {
562                goto error;
563            }
564            for (size_t i = 0; i < varCount; ++i) {
565                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
566                    goto error;
567                }
568                char *c = strrchr(line, '\n');
569                if (c) {
570                    *c = '\0';
571                }
572                mFieldAddress[i] = dlsym(mScriptSO, line);
573                if (mFieldAddress[i] == NULL) {
574                    ALOGE("Failed to find variable address for %s: %s",
575                          line, dlerror());
576                    // Not a critical error if we don't find a global variable.
577                }
578                else {
579                    //ALOGE("Found variable %s at %p", line,
580                    //mFieldAddress[i]);
581                }
582            }
583        }
584
585        size_t funcCount = 0;
586        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
587            goto error;
588        }
589        if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
590            ALOGE("Invalid export func count!: %s", line);
591            goto error;
592        }
593
594        mExportedFunctionCount = funcCount;
595        //ALOGE("funcCount: %zu", funcCount);
596
597        if (funcCount > 0) {
598            mInvokeFunctions = new InvokeFunc_t[funcCount];
599            if (mInvokeFunctions == NULL) {
600                goto error;
601            }
602            for (size_t i = 0; i < funcCount; ++i) {
603                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
604                    goto error;
605                }
606                char *c = strrchr(line, '\n');
607                if (c) {
608                    *c = '\0';
609                }
610
611                mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
612                if (mInvokeFunctions[i] == NULL) {
613                    ALOGE("Failed to get function address for %s(): %s",
614                          line, dlerror());
615                    goto error;
616                }
617                else {
618                    //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
619                }
620            }
621        }
622
623        size_t forEachCount = 0;
624        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
625            goto error;
626        }
627        if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
628            ALOGE("Invalid export forEach count!: %s", line);
629            goto error;
630        }
631
632        if (forEachCount > 0) {
633
634            mForEachSignatures = new uint32_t[forEachCount];
635            if (mForEachSignatures == NULL) {
636                goto error;
637            }
638            mForEachFunctions = new ForEachFunc_t[forEachCount];
639            if (mForEachFunctions == NULL) {
640                goto error;
641            }
642            for (size_t i = 0; i < forEachCount; ++i) {
643                unsigned int tmpSig = 0;
644                char tmpName[MAXLINE];
645
646                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
647                    goto error;
648                }
649                if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
650                           &tmpSig, tmpName) != 2) {
651                    ALOGE("Invalid export forEach!: %s", line);
652                    goto error;
653                }
654
655                // Lookup the expanded ForEach kernel.
656                strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
657                mForEachSignatures[i] = tmpSig;
658                mForEachFunctions[i] =
659                        (ForEachFunc_t) dlsym(mScriptSO, tmpName);
660                if (i != 0 && mForEachFunctions[i] == NULL) {
661                    // Ignore missing root.expand functions.
662                    // root() is always specified at location 0.
663                    ALOGE("Failed to find forEach function address for %s: %s",
664                          tmpName, dlerror());
665                    goto error;
666                }
667                else {
668                    //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
669                }
670            }
671        }
672
673        size_t objectSlotCount = 0;
674        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
675            goto error;
676        }
677        if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
678            ALOGE("Invalid object slot count!: %s", line);
679            goto error;
680        }
681
682        if (objectSlotCount > 0) {
683            rsAssert(varCount > 0);
684            for (size_t i = 0; i < objectSlotCount; ++i) {
685                uint32_t varNum = 0;
686                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
687                    goto error;
688                }
689                if (sscanf(line, "%u", &varNum) != 1) {
690                    ALOGE("Invalid object slot!: %s", line);
691                    goto error;
692                }
693
694                if (varNum < varCount) {
695                    mFieldIsObject[varNum] = true;
696                }
697            }
698        }
699
700        if (varCount > 0) {
701            mBoundAllocs = new Allocation *[varCount];
702            memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
703        }
704
705        if (mScriptSO == (void*)1) {
706            //rsdLookupRuntimeStub(script, "acos");
707        }
708    } else {
709        goto error;
710    }
711#endif
712#endif // FAKE_ARM64_BUILD
713    mCtx->unlockMutex();
714    return true;
715
716#ifdef RS_COMPATIBILITY_LIB
717error:
718
719    mCtx->unlockMutex();
720    delete[] mInvokeFunctions;
721    delete[] mForEachFunctions;
722    delete[] mFieldAddress;
723    delete[] mFieldIsObject;
724    delete[] mForEachSignatures;
725    delete[] mBoundAllocs;
726    if (mScriptSO) {
727        dlclose(mScriptSO);
728    }
729    return false;
730#endif
731}
732
733void RsdCpuScriptImpl::populateScript(Script *script) {
734#ifndef FAKE_ARM64_BUILD
735#ifndef RS_COMPATIBILITY_LIB
736    const bcc::RSInfo *info = &mExecutable->getInfo();
737
738    // Copy info over to runtime
739    script->mHal.info.exportedFunctionCount = info->getExportFuncNames().size();
740    script->mHal.info.exportedVariableCount = info->getExportVarNames().size();
741    script->mHal.info.exportedForeachFuncList = info->getExportForeachFuncs().array();
742    script->mHal.info.exportedPragmaCount = info->getPragmas().size();
743    script->mHal.info.exportedPragmaKeyList =
744        const_cast<const char**>(mExecutable->getPragmaKeys().array());
745    script->mHal.info.exportedPragmaValueList =
746        const_cast<const char**>(mExecutable->getPragmaValues().array());
747
748    if (mRootExpand) {
749        script->mHal.info.root = mRootExpand;
750    } else {
751        script->mHal.info.root = mRoot;
752    }
753#else
754    // Copy info over to runtime
755    script->mHal.info.exportedFunctionCount = mExportedFunctionCount;
756    script->mHal.info.exportedVariableCount = mExportedVariableCount;
757    script->mHal.info.exportedPragmaCount = 0;
758    script->mHal.info.exportedPragmaKeyList = 0;
759    script->mHal.info.exportedPragmaValueList = 0;
760
761    // Bug, need to stash in metadata
762    if (mRootExpand) {
763        script->mHal.info.root = mRootExpand;
764    } else {
765        script->mHal.info.root = mRoot;
766    }
767#endif
768#endif
769}
770
771
772typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
773
774void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation * ain, Allocation * aout,
775                                        const void * usr, uint32_t usrLen,
776                                        const RsScriptCall *sc,
777                                        MTLaunchStruct *mtls) {
778
779    memset(mtls, 0, sizeof(MTLaunchStruct));
780
781    // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
782    if (ain && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) {
783        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null in allocations");
784        return;
785    }
786    if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) {
787        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null out allocations");
788        return;
789    }
790
791    if (ain) {
792        mtls->fep.dimX = ain->getType()->getDimX();
793        mtls->fep.dimY = ain->getType()->getDimY();
794        mtls->fep.dimZ = ain->getType()->getDimZ();
795        //mtls->dimArray = ain->getType()->getDimArray();
796    } else if (aout) {
797        mtls->fep.dimX = aout->getType()->getDimX();
798        mtls->fep.dimY = aout->getType()->getDimY();
799        mtls->fep.dimZ = aout->getType()->getDimZ();
800        //mtls->dimArray = aout->getType()->getDimArray();
801    } else {
802        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
803        return;
804    }
805
806    if (!sc || (sc->xEnd == 0)) {
807        mtls->xEnd = mtls->fep.dimX;
808    } else {
809        rsAssert(sc->xStart < mtls->fep.dimX);
810        rsAssert(sc->xEnd <= mtls->fep.dimX);
811        rsAssert(sc->xStart < sc->xEnd);
812        mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
813        mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
814        if (mtls->xStart >= mtls->xEnd) return;
815    }
816
817    if (!sc || (sc->yEnd == 0)) {
818        mtls->yEnd = mtls->fep.dimY;
819    } else {
820        rsAssert(sc->yStart < mtls->fep.dimY);
821        rsAssert(sc->yEnd <= mtls->fep.dimY);
822        rsAssert(sc->yStart < sc->yEnd);
823        mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
824        mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
825        if (mtls->yStart >= mtls->yEnd) return;
826    }
827
828    if (!sc || (sc->zEnd == 0)) {
829        mtls->zEnd = mtls->fep.dimZ;
830    } else {
831        rsAssert(sc->zStart < mtls->fep.dimZ);
832        rsAssert(sc->zEnd <= mtls->fep.dimZ);
833        rsAssert(sc->zStart < sc->zEnd);
834        mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
835        mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
836        if (mtls->zStart >= mtls->zEnd) return;
837    }
838
839    mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
840    mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
841    mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
842    mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
843
844    rsAssert(!ain || (ain->getType()->getDimZ() == 0));
845
846    mtls->rsc = mCtx;
847    mtls->ain = ain;
848    mtls->aout = aout;
849    mtls->fep.usr = usr;
850    mtls->fep.usrLen = usrLen;
851    mtls->mSliceSize = 1;
852    mtls->mSliceNum = 0;
853
854    mtls->fep.ptrIn = NULL;
855    mtls->fep.eStrideIn = 0;
856    mtls->isThreadable = mIsThreadable;
857
858    if (ain) {
859        mtls->fep.ptrIn = (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr;
860        mtls->fep.eStrideIn = ain->getType()->getElementSizeBytes();
861        mtls->fep.yStrideIn = ain->mHal.drvState.lod[0].stride;
862    }
863
864    mtls->fep.ptrOut = NULL;
865    mtls->fep.eStrideOut = 0;
866    if (aout) {
867        mtls->fep.ptrOut = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
868        mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes();
869        mtls->fep.yStrideOut = aout->mHal.drvState.lod[0].stride;
870    }
871}
872
873
874void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
875                                     const Allocation * ain,
876                                     Allocation * aout,
877                                     const void * usr,
878                                     uint32_t usrLen,
879                                     const RsScriptCall *sc) {
880
881    MTLaunchStruct mtls;
882    forEachMtlsSetup(ain, aout, usr, usrLen, sc, &mtls);
883    forEachKernelSetup(slot, &mtls);
884
885    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
886    mCtx->launchThreads(ain, aout, sc, &mtls);
887    mCtx->setTLS(oldTLS);
888}
889
890void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
891    mtls->script = this;
892    mtls->fep.slot = slot;
893#ifndef FAKE_ARM64_BUILD
894#ifndef RS_COMPATIBILITY_LIB
895    rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
896    mtls->kernel = reinterpret_cast<ForEachFunc_t>(
897                      mExecutable->getExportForeachFuncAddrs()[slot]);
898    rsAssert(mtls->kernel != NULL);
899    mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
900#else
901    mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
902    rsAssert(mtls->kernel != NULL);
903    mtls->sig = mForEachSignatures[slot];
904#endif
905#endif
906}
907
908int RsdCpuScriptImpl::invokeRoot() {
909    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
910#ifndef FAKE_ARM64_BUILD
911    int ret = mRoot();
912#else
913    int ret = 0;
914#endif
915    mCtx->setTLS(oldTLS);
916    return ret;
917}
918
919void RsdCpuScriptImpl::invokeInit() {
920#ifndef FAKE_ARM64_BUILD
921    if (mInit) {
922        mInit();
923    }
924#endif
925}
926
927void RsdCpuScriptImpl::invokeFreeChildren() {
928#ifndef FAKE_ARM64_BUILD
929    if (mFreeChildren) {
930        mFreeChildren();
931    }
932#endif
933}
934
935void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
936                                      size_t paramLength) {
937    //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
938
939    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
940#ifndef FAKE_ARM64_BUILD
941    reinterpret_cast<void (*)(const void *, uint32_t)>(
942#ifndef RS_COMPATIBILITY_LIB
943        mExecutable->getExportFuncAddrs()[slot])(params, paramLength);
944#else
945        mInvokeFunctions[slot])(params, paramLength);
946#endif
947#endif
948    mCtx->setTLS(oldTLS);
949}
950
951void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
952    //rsAssert(!script->mFieldIsObject[slot]);
953    //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
954
955    //if (mIntrinsicID) {
956        //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
957        //return;
958    //}
959
960#ifndef FAKE_ARM64_BUILD
961#ifndef RS_COMPATIBILITY_LIB
962    int32_t *destPtr = reinterpret_cast<int32_t *>(
963                          mExecutable->getExportVarAddrs()[slot]);
964#else
965    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
966#endif
967#else
968    int32_t *destPtr = NULL;
969#endif
970    if (!destPtr) {
971        //ALOGV("Calling setVar on slot = %i which is null", slot);
972        return;
973    }
974
975    memcpy(destPtr, data, dataLength);
976}
977
978void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
979    //rsAssert(!script->mFieldIsObject[slot]);
980    //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
981
982#ifndef FAKE_ARM64_BUILD
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#else
990    int32_t *srcPtr = NULL;
991#endif
992    if (!srcPtr) {
993        //ALOGV("Calling setVar on slot = %i which is null", slot);
994        return;
995    }
996    memcpy(data, srcPtr, dataLength);
997}
998
999
1000void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
1001                                                const Element *elem,
1002                                                const size_t *dims, size_t dimLength) {
1003
1004#ifndef FAKE_ARM64_BUILD
1005#ifndef RS_COMPATIBILITY_LIB
1006    int32_t *destPtr = reinterpret_cast<int32_t *>(
1007        mExecutable->getExportVarAddrs()[slot]);
1008#else
1009    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1010#endif
1011#else
1012    int32_t *destPtr = NULL;
1013#endif
1014    if (!destPtr) {
1015        //ALOGV("Calling setVar on slot = %i which is null", slot);
1016        return;
1017    }
1018
1019    // We want to look at dimension in terms of integer components,
1020    // but dimLength is given in terms of bytes.
1021    dimLength /= sizeof(int);
1022
1023    // Only a single dimension is currently supported.
1024    rsAssert(dimLength == 1);
1025    if (dimLength == 1) {
1026        // First do the increment loop.
1027        size_t stride = elem->getSizeBytes();
1028        const char *cVal = reinterpret_cast<const char *>(data);
1029        for (size_t i = 0; i < dims[0]; i++) {
1030            elem->incRefs(cVal);
1031            cVal += stride;
1032        }
1033
1034        // Decrement loop comes after (to prevent race conditions).
1035        char *oldVal = reinterpret_cast<char *>(destPtr);
1036        for (size_t i = 0; i < dims[0]; i++) {
1037            elem->decRefs(oldVal);
1038            oldVal += stride;
1039        }
1040    }
1041
1042    memcpy(destPtr, data, dataLength);
1043}
1044
1045void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
1046
1047    //rsAssert(!script->mFieldIsObject[slot]);
1048    //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
1049
1050#ifndef FAKE_ARM64_BUILD
1051#ifndef RS_COMPATIBILITY_LIB
1052    int32_t *destPtr = reinterpret_cast<int32_t *>(
1053                          mExecutable->getExportVarAddrs()[slot]);
1054#else
1055    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1056#endif
1057#else
1058    int32_t *destPtr = NULL;
1059#endif
1060    if (!destPtr) {
1061        //ALOGV("Calling setVar on slot = %i which is null", slot);
1062        return;
1063    }
1064
1065    void *ptr = NULL;
1066    mBoundAllocs[slot] = data;
1067    if(data) {
1068        ptr = data->mHal.drvState.lod[0].mallocPtr;
1069    }
1070    memcpy(destPtr, &ptr, sizeof(void *));
1071}
1072
1073void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
1074
1075    //rsAssert(script->mFieldIsObject[slot]);
1076    //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
1077
1078    //if (mIntrinsicID) {
1079        //mIntrinsicFuncs.setVarObj(dc, script, drv->mIntrinsicData, slot, alloc);
1080        //return;
1081    //}
1082
1083#ifndef FAKE_ARM64_BUILD
1084#ifndef RS_COMPATIBILITY_LIB
1085    int32_t *destPtr = reinterpret_cast<int32_t *>(
1086                          mExecutable->getExportVarAddrs()[slot]);
1087#else
1088    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1089#endif
1090#else
1091    int32_t *destPtr = NULL;
1092#endif
1093
1094
1095    if (!destPtr) {
1096        //ALOGV("Calling setVar on slot = %i which is null", slot);
1097        return;
1098    }
1099
1100    rsrSetObject(mCtx->getContext(), (ObjectBase **)destPtr, data);
1101}
1102
1103RsdCpuScriptImpl::~RsdCpuScriptImpl() {
1104#ifndef FAKE_ARM64_BUILD
1105#ifndef RS_COMPATIBILITY_LIB
1106    if (mExecutable) {
1107        Vector<void *>::const_iterator var_addr_iter =
1108            mExecutable->getExportVarAddrs().begin();
1109        Vector<void *>::const_iterator var_addr_end =
1110            mExecutable->getExportVarAddrs().end();
1111
1112        bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter =
1113            mExecutable->getInfo().getObjectSlots().begin();
1114        bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end =
1115            mExecutable->getInfo().getObjectSlots().end();
1116
1117        while ((var_addr_iter != var_addr_end) &&
1118               (is_object_iter != is_object_end)) {
1119            // The field address can be NULL if the script-side has optimized
1120            // the corresponding global variable away.
1121            ObjectBase **obj_addr =
1122                reinterpret_cast<ObjectBase **>(*var_addr_iter);
1123            if (*is_object_iter) {
1124                if (*var_addr_iter != NULL) {
1125                    rsrClearObject(mCtx->getContext(), obj_addr);
1126                }
1127            }
1128            var_addr_iter++;
1129            is_object_iter++;
1130        }
1131    }
1132
1133    if (mCompilerContext) {
1134        delete mCompilerContext;
1135    }
1136    if (mCompilerDriver) {
1137        delete mCompilerDriver;
1138    }
1139    if (mExecutable) {
1140        delete mExecutable;
1141    }
1142    if (mBoundAllocs) {
1143        delete[] mBoundAllocs;
1144    }
1145#else
1146    if (mFieldIsObject) {
1147        for (size_t i = 0; i < mExportedVariableCount; ++i) {
1148            if (mFieldIsObject[i]) {
1149                if (mFieldAddress[i] != NULL) {
1150                    ObjectBase **obj_addr =
1151                        reinterpret_cast<ObjectBase **>(mFieldAddress[i]);
1152                    rsrClearObject(mCtx->getContext(), obj_addr);
1153                }
1154            }
1155        }
1156    }
1157
1158    if (mInvokeFunctions) delete[] mInvokeFunctions;
1159    if (mForEachFunctions) delete[] mForEachFunctions;
1160    if (mFieldAddress) delete[] mFieldAddress;
1161    if (mFieldIsObject) delete[] mFieldIsObject;
1162    if (mForEachSignatures) delete[] mForEachSignatures;
1163    if (mBoundAllocs) delete[] mBoundAllocs;
1164    if (mScriptSO) {
1165        dlclose(mScriptSO);
1166    }
1167#endif
1168#endif
1169}
1170
1171Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const {
1172    if (!ptr) {
1173        return NULL;
1174    }
1175
1176    for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) {
1177        Allocation *a = mBoundAllocs[ct];
1178        if (!a) continue;
1179        if (a->mHal.drvState.lod[0].mallocPtr == ptr) {
1180            return a;
1181        }
1182    }
1183    ALOGE("rsGetAllocation, failed to find %p", ptr);
1184    return NULL;
1185}
1186
1187void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation * ain,
1188                       Allocation * aout, const void * usr,
1189                       uint32_t usrLen, const RsScriptCall *sc)
1190{
1191}
1192
1193void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation * ain,
1194                        Allocation * aout, const void * usr,
1195                        uint32_t usrLen, const RsScriptCall *sc)
1196{
1197}
1198
1199
1200}
1201}
1202