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