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