rsCpuScript.cpp revision 47935ac8e3dd619f758abd576605a564e33bb59c
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
18
19#include "rsCpuCore.h"
20
21#include "rsCpuScript.h"
22//#include "rsdRuntime.h"
23//#include "rsdAllocation.h"
24//#include "rsCpuIntrinsics.h"
25
26#ifndef RS_SERVER
27#include "utils/Vector.h"
28#include "utils/Timers.h"
29#include "utils/StopWatch.h"
30#endif
31
32#ifdef RS_COMPATIBILITY_LIB
33    #include <dlfcn.h>
34    #include <stdio.h>
35    #include <string.h>
36#else
37    #include <bcc/BCCContext.h>
38    #include <bcc/Renderscript/RSCompilerDriver.h>
39    #include <bcc/Renderscript/RSExecutable.h>
40    #include <bcc/Renderscript/RSInfo.h>
41    #include <cutils/properties.h>
42#endif
43
44#ifndef RS_COMPATIBILITY_LIB
45namespace {
46static bool is_force_recompile() {
47#ifdef RS_SERVER
48  return false;
49#else
50  char buf[PROPERTY_VALUE_MAX];
51
52  // Re-compile if floating point precision has been overridden.
53  property_get("debug.rs.precision", buf, "");
54  if (buf[0] != '\0') {
55    return true;
56  }
57
58  // Re-compile if debug.rs.forcerecompile is set.
59  property_get("debug.rs.forcerecompile", buf, "0");
60  if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
61    return true;
62  } else {
63    return false;
64  }
65#endif  // RS_SERVER
66}
67}  // namespace
68#endif  // !defined(RS_COMPATIBILITY_LIB)
69
70namespace android {
71namespace renderscript {
72
73
74#ifdef RS_COMPATIBILITY_LIB
75#define MAXLINE 500
76#define MAKE_STR_HELPER(S) #S
77#define MAKE_STR(S) MAKE_STR_HELPER(S)
78#define EXPORT_VAR_STR "exportVarCount: "
79#define EXPORT_VAR_STR_LEN strlen(EXPORT_VAR_STR)
80#define EXPORT_FUNC_STR "exportFuncCount: "
81#define EXPORT_FUNC_STR_LEN strlen(EXPORT_FUNC_STR)
82#define EXPORT_FOREACH_STR "exportForEachCount: "
83#define EXPORT_FOREACH_STR_LEN strlen(EXPORT_FOREACH_STR)
84#define OBJECT_SLOT_STR "objectSlotCount: "
85#define OBJECT_SLOT_STR_LEN strlen(OBJECT_SLOT_STR)
86
87// Copy up to a newline or size chars from str -> s, updating str
88// Returns s when successful and NULL when '\0' is finally reached.
89static char* strgets(char *s, int size, const char **ppstr) {
90    if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
91        return NULL;
92    }
93
94    int i;
95    for (i = 0; i < (size - 1); i++) {
96        s[i] = **ppstr;
97        (*ppstr)++;
98        if (s[i] == '\0') {
99            return s;
100        } else if (s[i] == '\n') {
101            s[i+1] = '\0';
102            return s;
103        }
104    }
105
106    // size has been exceeded.
107    s[i] = '\0';
108
109    return s;
110}
111#endif
112
113RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
114    mCtx = ctx;
115    mScript = s;
116
117#ifdef RS_COMPATIBILITY_LIB
118    mScriptSO = NULL;
119    mInvokeFunctions = NULL;
120    mForEachFunctions = NULL;
121    mFieldAddress = NULL;
122    mFieldIsObject = NULL;
123    mForEachSignatures = NULL;
124#else
125    mCompilerContext = NULL;
126    mCompilerDriver = NULL;
127    mExecutable = NULL;
128#endif
129
130    mRoot = NULL;
131    mRootExpand = NULL;
132    mInit = NULL;
133    mFreeChildren = NULL;
134
135
136    mBoundAllocs = NULL;
137    mIntrinsicData = NULL;
138    mIsThreadable = true;
139}
140
141
142bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
143                            uint8_t const *bitcode, size_t bitcodeSize,
144                            uint32_t flags) {
145    //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
146    //ALOGE("rsdScriptInit %p %p", rsc, script);
147
148    mCtx->lockMutex();
149
150#ifndef RS_COMPATIBILITY_LIB
151    bcc::RSExecutable *exec = NULL;
152
153    mCompilerContext = NULL;
154    mCompilerDriver = NULL;
155    mExecutable = NULL;
156
157    mCompilerContext = new bcc::BCCContext();
158    if (mCompilerContext == NULL) {
159        ALOGE("bcc: FAILS to create compiler context (out of memory)");
160        mCtx->unlockMutex();
161        return false;
162    }
163
164    mCompilerDriver = new bcc::RSCompilerDriver();
165    if (mCompilerDriver == NULL) {
166        ALOGE("bcc: FAILS to create compiler driver (out of memory)");
167        mCtx->unlockMutex();
168        return false;
169    }
170
171    mCompilerDriver->setRSRuntimeLookupFunction(lookupRuntimeStub);
172    mCompilerDriver->setRSRuntimeLookupContext(this);
173
174    // Run any compiler setup functions we have been provided with.
175    RSSetupCompilerCallback setupCompilerCallback =
176            mCtx->getSetupCompilerCallback();
177    if (setupCompilerCallback != NULL) {
178        setupCompilerCallback(mCompilerDriver);
179    }
180
181    const char *core_lib = NULL;
182    RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
183    if (selectRTCallback != NULL) {
184        core_lib = selectRTCallback((const char *)bitcode, bitcodeSize);
185    }
186
187    if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
188        // Use the libclcore_debug.bc instead of the default library.
189        core_lib = bcc::RSInfo::LibCLCoreDebugPath;
190        mCompilerDriver->setDebugContext(true);
191        // Skip the cache lookup
192    } else if (!is_force_recompile()) {
193        // Attempt to just load the script from cache first if we can.
194        exec = mCompilerDriver->loadScript(cacheDir, resName,
195                                           (const char *)bitcode, bitcodeSize);
196    }
197
198    // TODO(srhines): This is being refactored, but it simply wraps the
199    // build (compile) and load steps together.
200    if (exec == NULL) {
201        bool built = mCompilerDriver->build(*mCompilerContext, cacheDir,
202                                            resName, (const char *)bitcode,
203                                            bitcodeSize, core_lib,
204                                            mCtx->getLinkRuntimeCallback());
205        if (built) {
206            exec = mCompilerDriver->loadScript(cacheDir, resName,
207                                               (const char *)bitcode,
208                                               bitcodeSize);
209        }
210    }
211
212    if (exec == NULL) {
213        ALOGE("bcc: FAILS to prepare executable for '%s'", resName);
214        mCtx->unlockMutex();
215        return false;
216    }
217
218    mExecutable = exec;
219
220    exec->setThreadable(mIsThreadable);
221    if (!exec->syncInfo()) {
222        ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
223    }
224
225    mRoot = reinterpret_cast<int (*)()>(exec->getSymbolAddress("root"));
226    mRootExpand =
227        reinterpret_cast<int (*)()>(exec->getSymbolAddress("root.expand"));
228    mInit = reinterpret_cast<void (*)()>(exec->getSymbolAddress("init"));
229    mFreeChildren =
230        reinterpret_cast<void (*)()>(exec->getSymbolAddress(".rs.dtor"));
231
232
233    const bcc::RSInfo *info = &mExecutable->getInfo();
234    if (info->getExportVarNames().size()) {
235        mBoundAllocs = new Allocation *[info->getExportVarNames().size()];
236        memset(mBoundAllocs, 0, sizeof(void *) * info->getExportVarNames().size());
237    }
238
239#else
240
241#ifndef RS_SERVER
242    String8 scriptSOName(cacheDir);
243    scriptSOName = scriptSOName.getPathDir();
244    scriptSOName.appendPath("lib");
245    scriptSOName.append("/librs.");
246#else
247    String8 scriptSOName("lib");
248#endif
249    scriptSOName.append(resName);
250    scriptSOName.append(".so");
251
252    //script->mHal.drv = drv;
253
254    //ALOGV("Opening up shared object: %s", scriptSOName.string());
255    mScriptSO = dlopen(scriptSOName.string(), RTLD_NOW | RTLD_LOCAL);
256    if (mScriptSO == NULL) {
257        ALOGE("Unable to open shared library (%s): %s",
258              scriptSOName.string(), dlerror());
259
260        // One final attempt to find the library in "/system/lib".
261        // We do this to allow bundled applications to use the compatibility
262        // library fallback path. Those applications don't have a private
263        // library path, so they need to install to the system directly.
264        String8 scriptSONameSystem("/system/lib/librs.");
265        scriptSONameSystem.append(resName);
266        scriptSONameSystem.append(".so");
267        mScriptSO = dlopen(scriptSONameSystem.string(), RTLD_NOW | RTLD_LOCAL);
268        if (mScriptSO == NULL) {
269            ALOGE("Unable to open system shared library (%s): %s",
270                  scriptSONameSystem.string(), dlerror());
271            goto error;
272        }
273    }
274
275    if (mScriptSO) {
276        char line[MAXLINE];
277        mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
278        if (mRoot) {
279            //ALOGE("Found root(): %p", mRoot);
280        }
281        mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
282        if (mRootExpand) {
283            //ALOGE("Found root.expand(): %p", mRootExpand);
284        }
285        mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
286        if (mInit) {
287            //ALOGE("Found init(): %p", mInit);
288        }
289        mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
290        if (mFreeChildren) {
291            //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
292        }
293
294        const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
295        if (rsInfo) {
296            //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
297        }
298
299        size_t varCount = 0;
300        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
301            goto error;
302        }
303        if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
304            ALOGE("Invalid export var count!: %s", line);
305            goto error;
306        }
307
308        mExportedVariableCount = varCount;
309        //ALOGE("varCount: %zu", varCount);
310        if (varCount > 0) {
311            // Start by creating/zeroing this member, since we don't want to
312            // accidentally clean up invalid pointers later (if we error out).
313            mFieldIsObject = new bool[varCount];
314            if (mFieldIsObject == NULL) {
315                goto error;
316            }
317            memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
318            mFieldAddress = new void*[varCount];
319            if (mFieldAddress == NULL) {
320                goto error;
321            }
322            for (size_t i = 0; i < varCount; ++i) {
323                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
324                    goto error;
325                }
326                char *c = strrchr(line, '\n');
327                if (c) {
328                    *c = '\0';
329                }
330                mFieldAddress[i] = dlsym(mScriptSO, line);
331                if (mFieldAddress[i] == NULL) {
332                    ALOGE("Failed to find variable address for %s: %s",
333                          line, dlerror());
334                    // Not a critical error if we don't find a global variable.
335                }
336                else {
337                    //ALOGE("Found variable %s at %p", line,
338                    //mFieldAddress[i]);
339                }
340            }
341        }
342
343        size_t funcCount = 0;
344        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
345            goto error;
346        }
347        if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
348            ALOGE("Invalid export func count!: %s", line);
349            goto error;
350        }
351
352        mExportedFunctionCount = funcCount;
353        //ALOGE("funcCount: %zu", funcCount);
354
355        if (funcCount > 0) {
356            mInvokeFunctions = new InvokeFunc_t[funcCount];
357            if (mInvokeFunctions == NULL) {
358                goto error;
359            }
360            for (size_t i = 0; i < funcCount; ++i) {
361                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
362                    goto error;
363                }
364                char *c = strrchr(line, '\n');
365                if (c) {
366                    *c = '\0';
367                }
368
369                mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
370                if (mInvokeFunctions[i] == NULL) {
371                    ALOGE("Failed to get function address for %s(): %s",
372                          line, dlerror());
373                    goto error;
374                }
375                else {
376                    //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
377                }
378            }
379        }
380
381        size_t forEachCount = 0;
382        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
383            goto error;
384        }
385        if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
386            ALOGE("Invalid export forEach count!: %s", line);
387            goto error;
388        }
389
390        if (forEachCount > 0) {
391
392            mForEachSignatures = new uint32_t[forEachCount];
393            if (mForEachSignatures == NULL) {
394                goto error;
395            }
396            mForEachFunctions = new ForEachFunc_t[forEachCount];
397            if (mForEachFunctions == NULL) {
398                goto error;
399            }
400            for (size_t i = 0; i < forEachCount; ++i) {
401                unsigned int tmpSig = 0;
402                char tmpName[MAXLINE];
403
404                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
405                    goto error;
406                }
407                if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
408                           &tmpSig, tmpName) != 2) {
409                    ALOGE("Invalid export forEach!: %s", line);
410                    goto error;
411                }
412
413                // Lookup the expanded ForEach kernel.
414                strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
415                mForEachSignatures[i] = tmpSig;
416                mForEachFunctions[i] =
417                        (ForEachFunc_t) dlsym(mScriptSO, tmpName);
418                if (i != 0 && mForEachFunctions[i] == NULL) {
419                    // Ignore missing root.expand functions.
420                    // root() is always specified at location 0.
421                    ALOGE("Failed to find forEach function address for %s: %s",
422                          tmpName, dlerror());
423                    goto error;
424                }
425                else {
426                    //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
427                }
428            }
429        }
430
431        size_t objectSlotCount = 0;
432        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
433            goto error;
434        }
435        if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
436            ALOGE("Invalid object slot count!: %s", line);
437            goto error;
438        }
439
440        if (objectSlotCount > 0) {
441            rsAssert(varCount > 0);
442            for (size_t i = 0; i < objectSlotCount; ++i) {
443                uint32_t varNum = 0;
444                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
445                    goto error;
446                }
447                if (sscanf(line, "%u", &varNum) != 1) {
448                    ALOGE("Invalid object slot!: %s", line);
449                    goto error;
450                }
451
452                if (varNum < varCount) {
453                    mFieldIsObject[varNum] = true;
454                }
455            }
456        }
457
458        if (varCount > 0) {
459            mBoundAllocs = new Allocation *[varCount];
460            memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
461        }
462
463        if (mScriptSO == (void*)1) {
464            //rsdLookupRuntimeStub(script, "acos");
465        }
466    }
467#endif
468
469    mCtx->unlockMutex();
470    return true;
471
472#ifdef RS_COMPATIBILITY_LIB
473error:
474
475    mCtx->unlockMutex();
476    delete[] mInvokeFunctions;
477    delete[] mForEachFunctions;
478    delete[] mFieldAddress;
479    delete[] mFieldIsObject;
480    delete[] mForEachSignatures;
481    delete[] mBoundAllocs;
482    if (mScriptSO) {
483        dlclose(mScriptSO);
484    }
485    return false;
486#endif
487}
488
489void RsdCpuScriptImpl::populateScript(Script *script) {
490#ifndef RS_COMPATIBILITY_LIB
491    const bcc::RSInfo *info = &mExecutable->getInfo();
492
493    // Copy info over to runtime
494    script->mHal.info.exportedFunctionCount = info->getExportFuncNames().size();
495    script->mHal.info.exportedVariableCount = info->getExportVarNames().size();
496    script->mHal.info.exportedForeachFuncList = info->getExportForeachFuncs().array();
497    script->mHal.info.exportedPragmaCount = info->getPragmas().size();
498    script->mHal.info.exportedPragmaKeyList =
499        const_cast<const char**>(mExecutable->getPragmaKeys().array());
500    script->mHal.info.exportedPragmaValueList =
501        const_cast<const char**>(mExecutable->getPragmaValues().array());
502
503    if (mRootExpand) {
504        script->mHal.info.root = mRootExpand;
505    } else {
506        script->mHal.info.root = mRoot;
507    }
508#else
509    // Copy info over to runtime
510    script->mHal.info.exportedFunctionCount = mExportedFunctionCount;
511    script->mHal.info.exportedVariableCount = mExportedVariableCount;
512    script->mHal.info.exportedPragmaCount = 0;
513    script->mHal.info.exportedPragmaKeyList = 0;
514    script->mHal.info.exportedPragmaValueList = 0;
515
516    // Bug, need to stash in metadata
517    if (mRootExpand) {
518        script->mHal.info.root = mRootExpand;
519    } else {
520        script->mHal.info.root = mRoot;
521    }
522#endif
523}
524
525
526typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
527
528void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation * ain, Allocation * aout,
529                                        const void * usr, uint32_t usrLen,
530                                        const RsScriptCall *sc,
531                                        MTLaunchStruct *mtls) {
532
533    memset(mtls, 0, sizeof(MTLaunchStruct));
534
535    // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
536    if (ain && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) {
537        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
538        return;
539    }
540    if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) {
541        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
542        return;
543    }
544
545    if (ain) {
546        mtls->fep.dimX = ain->getType()->getDimX();
547        mtls->fep.dimY = ain->getType()->getDimY();
548        mtls->fep.dimZ = ain->getType()->getDimZ();
549        //mtls->dimArray = ain->getType()->getDimArray();
550    } else if (aout) {
551        mtls->fep.dimX = aout->getType()->getDimX();
552        mtls->fep.dimY = aout->getType()->getDimY();
553        mtls->fep.dimZ = aout->getType()->getDimZ();
554        //mtls->dimArray = aout->getType()->getDimArray();
555    } else {
556        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
557        return;
558    }
559
560    if (!sc || (sc->xEnd == 0)) {
561        mtls->xEnd = mtls->fep.dimX;
562    } else {
563        rsAssert(sc->xStart < mtls->fep.dimX);
564        rsAssert(sc->xEnd <= mtls->fep.dimX);
565        rsAssert(sc->xStart < sc->xEnd);
566        mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
567        mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
568        if (mtls->xStart >= mtls->xEnd) return;
569    }
570
571    if (!sc || (sc->yEnd == 0)) {
572        mtls->yEnd = mtls->fep.dimY;
573    } else {
574        rsAssert(sc->yStart < mtls->fep.dimY);
575        rsAssert(sc->yEnd <= mtls->fep.dimY);
576        rsAssert(sc->yStart < sc->yEnd);
577        mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
578        mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
579        if (mtls->yStart >= mtls->yEnd) return;
580    }
581
582    if (!sc || (sc->zEnd == 0)) {
583        mtls->zEnd = mtls->fep.dimZ;
584    } else {
585        rsAssert(sc->zStart < mtls->fep.dimZ);
586        rsAssert(sc->zEnd <= mtls->fep.dimZ);
587        rsAssert(sc->zStart < sc->zEnd);
588        mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
589        mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
590        if (mtls->zStart >= mtls->zEnd) return;
591    }
592
593    mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
594    mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
595    mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
596    mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
597
598    rsAssert(!ain || (ain->getType()->getDimZ() == 0));
599
600    mtls->rsc = mCtx;
601    mtls->ain = ain;
602    mtls->aout = aout;
603    mtls->fep.usr = usr;
604    mtls->fep.usrLen = usrLen;
605    mtls->mSliceSize = 1;
606    mtls->mSliceNum = 0;
607
608    mtls->fep.ptrIn = NULL;
609    mtls->fep.eStrideIn = 0;
610    mtls->isThreadable = mIsThreadable;
611
612    if (ain) {
613        mtls->fep.ptrIn = (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr;
614        mtls->fep.eStrideIn = ain->getType()->getElementSizeBytes();
615        mtls->fep.yStrideIn = ain->mHal.drvState.lod[0].stride;
616    }
617
618    mtls->fep.ptrOut = NULL;
619    mtls->fep.eStrideOut = 0;
620    if (aout) {
621        mtls->fep.ptrOut = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
622        mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes();
623        mtls->fep.yStrideOut = aout->mHal.drvState.lod[0].stride;
624    }
625}
626
627
628void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
629                                     const Allocation * ain,
630                                     Allocation * aout,
631                                     const void * usr,
632                                     uint32_t usrLen,
633                                     const RsScriptCall *sc) {
634
635    MTLaunchStruct mtls;
636    forEachMtlsSetup(ain, aout, usr, usrLen, sc, &mtls);
637    forEachKernelSetup(slot, &mtls);
638
639    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
640    mCtx->launchThreads(ain, aout, sc, &mtls);
641    mCtx->setTLS(oldTLS);
642}
643
644void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
645    mtls->script = this;
646    mtls->fep.slot = slot;
647#ifndef RS_COMPATIBILITY_LIB
648    rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
649    mtls->kernel = reinterpret_cast<ForEachFunc_t>(
650                      mExecutable->getExportForeachFuncAddrs()[slot]);
651    rsAssert(mtls->kernel != NULL);
652    mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
653#else
654    mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
655    rsAssert(mtls->kernel != NULL);
656    mtls->sig = mForEachSignatures[slot];
657#endif
658}
659
660int RsdCpuScriptImpl::invokeRoot() {
661    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
662    int ret = mRoot();
663    mCtx->setTLS(oldTLS);
664    return ret;
665}
666
667void RsdCpuScriptImpl::invokeInit() {
668    if (mInit) {
669        mInit();
670    }
671}
672
673void RsdCpuScriptImpl::invokeFreeChildren() {
674    if (mFreeChildren) {
675        mFreeChildren();
676    }
677}
678
679void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
680                                      size_t paramLength) {
681    //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
682
683    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
684    reinterpret_cast<void (*)(const void *, uint32_t)>(
685#ifndef RS_COMPATIBILITY_LIB
686        mExecutable->getExportFuncAddrs()[slot])(params, paramLength);
687#else
688        mInvokeFunctions[slot])(params, paramLength);
689#endif
690    mCtx->setTLS(oldTLS);
691}
692
693void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
694    //rsAssert(!script->mFieldIsObject[slot]);
695    //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
696
697    //if (mIntrinsicID) {
698        //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
699        //return;
700    //}
701
702#ifndef RS_COMPATIBILITY_LIB
703    int32_t *destPtr = reinterpret_cast<int32_t *>(
704                          mExecutable->getExportVarAddrs()[slot]);
705#else
706    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
707#endif
708    if (!destPtr) {
709        //ALOGV("Calling setVar on slot = %i which is null", slot);
710        return;
711    }
712
713    memcpy(destPtr, data, dataLength);
714}
715
716void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
717    //rsAssert(!script->mFieldIsObject[slot]);
718    //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
719
720#ifndef RS_COMPATIBILITY_LIB
721    int32_t *srcPtr = reinterpret_cast<int32_t *>(
722                          mExecutable->getExportVarAddrs()[slot]);
723#else
724    int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
725#endif
726    if (!srcPtr) {
727        //ALOGV("Calling setVar on slot = %i which is null", slot);
728        return;
729    }
730    memcpy(data, srcPtr, dataLength);
731}
732
733
734void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
735                                                const Element *elem,
736                                                const size_t *dims, size_t dimLength) {
737
738#ifndef RS_COMPATIBILITY_LIB
739    int32_t *destPtr = reinterpret_cast<int32_t *>(
740        mExecutable->getExportVarAddrs()[slot]);
741#else
742    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
743#endif
744    if (!destPtr) {
745        //ALOGV("Calling setVar on slot = %i which is null", slot);
746        return;
747    }
748
749    // We want to look at dimension in terms of integer components,
750    // but dimLength is given in terms of bytes.
751    dimLength /= sizeof(int);
752
753    // Only a single dimension is currently supported.
754    rsAssert(dimLength == 1);
755    if (dimLength == 1) {
756        // First do the increment loop.
757        size_t stride = elem->getSizeBytes();
758        const char *cVal = reinterpret_cast<const char *>(data);
759        for (size_t i = 0; i < dims[0]; i++) {
760            elem->incRefs(cVal);
761            cVal += stride;
762        }
763
764        // Decrement loop comes after (to prevent race conditions).
765        char *oldVal = reinterpret_cast<char *>(destPtr);
766        for (size_t i = 0; i < dims[0]; i++) {
767            elem->decRefs(oldVal);
768            oldVal += stride;
769        }
770    }
771
772    memcpy(destPtr, data, dataLength);
773}
774
775void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
776
777    //rsAssert(!script->mFieldIsObject[slot]);
778    //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
779
780#ifndef RS_COMPATIBILITY_LIB
781    int32_t *destPtr = reinterpret_cast<int32_t *>(
782                          mExecutable->getExportVarAddrs()[slot]);
783#else
784    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
785#endif
786    if (!destPtr) {
787        //ALOGV("Calling setVar on slot = %i which is null", slot);
788        return;
789    }
790
791    void *ptr = NULL;
792    mBoundAllocs[slot] = data;
793    if(data) {
794        ptr = data->mHal.drvState.lod[0].mallocPtr;
795    }
796    memcpy(destPtr, &ptr, sizeof(void *));
797}
798
799void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
800
801    //rsAssert(script->mFieldIsObject[slot]);
802    //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
803
804    //if (mIntrinsicID) {
805        //mIntrinsicFuncs.setVarObj(dc, script, drv->mIntrinsicData, slot, alloc);
806        //return;
807    //}
808
809#ifndef RS_COMPATIBILITY_LIB
810    int32_t *destPtr = reinterpret_cast<int32_t *>(
811                          mExecutable->getExportVarAddrs()[slot]);
812#else
813    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
814#endif
815    if (!destPtr) {
816        //ALOGV("Calling setVar on slot = %i which is null", slot);
817        return;
818    }
819
820    rsrSetObject(mCtx->getContext(), (ObjectBase **)destPtr, data);
821}
822
823RsdCpuScriptImpl::~RsdCpuScriptImpl() {
824#ifndef RS_COMPATIBILITY_LIB
825    if (mExecutable) {
826        Vector<void *>::const_iterator var_addr_iter =
827            mExecutable->getExportVarAddrs().begin();
828        Vector<void *>::const_iterator var_addr_end =
829            mExecutable->getExportVarAddrs().end();
830
831        bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter =
832            mExecutable->getInfo().getObjectSlots().begin();
833        bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end =
834            mExecutable->getInfo().getObjectSlots().end();
835
836        while ((var_addr_iter != var_addr_end) &&
837               (is_object_iter != is_object_end)) {
838            // The field address can be NULL if the script-side has optimized
839            // the corresponding global variable away.
840            ObjectBase **obj_addr =
841                reinterpret_cast<ObjectBase **>(*var_addr_iter);
842            if (*is_object_iter) {
843                if (*var_addr_iter != NULL) {
844                    rsrClearObject(mCtx->getContext(), obj_addr);
845                }
846            }
847            var_addr_iter++;
848            is_object_iter++;
849        }
850    }
851
852    if (mCompilerContext) {
853        delete mCompilerContext;
854    }
855    if (mCompilerDriver) {
856        delete mCompilerDriver;
857    }
858    if (mExecutable) {
859        delete mExecutable;
860    }
861    if (mBoundAllocs) {
862        delete[] mBoundAllocs;
863    }
864#else
865    if (mFieldIsObject) {
866        for (size_t i = 0; i < mExportedVariableCount; ++i) {
867            if (mFieldIsObject[i]) {
868                if (mFieldAddress[i] != NULL) {
869                    ObjectBase **obj_addr =
870                        reinterpret_cast<ObjectBase **>(mFieldAddress[i]);
871                    rsrClearObject(mCtx->getContext(), obj_addr);
872                }
873            }
874        }
875    }
876
877    if (mInvokeFunctions) delete[] mInvokeFunctions;
878    if (mForEachFunctions) delete[] mForEachFunctions;
879    if (mFieldAddress) delete[] mFieldAddress;
880    if (mFieldIsObject) delete[] mFieldIsObject;
881    if (mForEachSignatures) delete[] mForEachSignatures;
882    if (mBoundAllocs) delete[] mBoundAllocs;
883    if (mScriptSO) {
884        dlclose(mScriptSO);
885    }
886#endif
887}
888
889Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const {
890    if (!ptr) {
891        return NULL;
892    }
893
894    for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) {
895        Allocation *a = mBoundAllocs[ct];
896        if (!a) continue;
897        if (a->mHal.drvState.lod[0].mallocPtr == ptr) {
898            return a;
899        }
900    }
901    ALOGE("rsGetAllocation, failed to find %p", ptr);
902    return NULL;
903}
904
905
906}
907}
908