rsCpuScript.cpp revision 2abfcc6d129fe3defddef4540aa95cc445c03a7a
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#include "rsCpuExecutable.h"
20
21#ifdef RS_COMPATIBILITY_LIB
22    #include <stdio.h>
23    #include <sys/stat.h>
24    #include <unistd.h>
25#else
26    #include <bcc/BCCContext.h>
27    #include <bcc/Config/Config.h>
28    #include <bcc/Renderscript/RSCompilerDriver.h>
29    #include <bcinfo/MetadataExtractor.h>
30    #include <cutils/properties.h>
31
32    #include <sys/types.h>
33    #include <sys/wait.h>
34    #include <unistd.h>
35
36    #include <string>
37    #include <vector>
38#endif
39
40#include <set>
41#include <string>
42#include <dlfcn.h>
43#include <stdlib.h>
44#include <string.h>
45#include <iostream>
46
47#ifdef __LP64__
48#define SYSLIBPATH "/system/lib64"
49#else
50#define SYSLIBPATH "/system/lib"
51#endif
52
53namespace {
54#ifndef RS_COMPATIBILITY_LIB
55
56static bool is_force_recompile() {
57#ifdef RS_SERVER
58  return false;
59#else
60  char buf[PROPERTY_VALUE_MAX];
61
62  // Re-compile if floating point precision has been overridden.
63  property_get("debug.rs.precision", buf, "");
64  if (buf[0] != '\0') {
65    return true;
66  }
67
68  // Re-compile if debug.rs.forcerecompile is set.
69  property_get("debug.rs.forcerecompile", buf, "0");
70  if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
71    return true;
72  } else {
73    return false;
74  }
75#endif  // RS_SERVER
76}
77
78static void setCompileArguments(std::vector<const char*>* args,
79                                const std::string& bcFileName,
80                                const char* cacheDir, const char* resName,
81                                const char* core_lib, bool useRSDebugContext,
82                                const char* bccPluginName) {
83    rsAssert(cacheDir && resName && core_lib);
84    args->push_back(android::renderscript::RsdCpuScriptImpl::BCC_EXE_PATH);
85    args->push_back("-unroll-runtime");
86    args->push_back("-scalarize-load-store");
87    args->push_back("-o");
88    args->push_back(resName);
89    args->push_back("-output_path");
90    args->push_back(cacheDir);
91    args->push_back("-bclib");
92    args->push_back(core_lib);
93    args->push_back("-mtriple");
94    args->push_back(DEFAULT_TARGET_TRIPLE_STRING);
95
96    // Enable workaround for A53 codegen by default.
97#if defined(__aarch64__) && !defined(DISABLE_A53_WORKAROUND)
98    args->push_back("-aarch64-fix-cortex-a53-835769");
99#endif
100
101    // Execute the bcc compiler.
102    if (useRSDebugContext) {
103        args->push_back("-rs-debug-ctx");
104    } else {
105        // Only load additional libraries for compiles that don't use
106        // the debug context.
107        if (bccPluginName && strlen(bccPluginName) > 0) {
108            args->push_back("-load");
109            args->push_back(bccPluginName);
110        }
111    }
112
113    args->push_back("-fPIC");
114    args->push_back("-embedRSInfo");
115
116    args->push_back(bcFileName.c_str());
117    args->push_back(nullptr);
118}
119
120static bool compileBitcode(const std::string &bcFileName,
121                           const char *bitcode,
122                           size_t bitcodeSize,
123                           const char **compileArguments,
124                           const std::string &compileCommandLine) {
125    rsAssert(bitcode && bitcodeSize);
126
127    FILE *bcfile = fopen(bcFileName.c_str(), "w");
128    if (!bcfile) {
129        ALOGE("Could not write to %s", bcFileName.c_str());
130        return false;
131    }
132    size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile);
133    fclose(bcfile);
134    if (nwritten != bitcodeSize) {
135        ALOGE("Could not write %zu bytes to %s", bitcodeSize,
136              bcFileName.c_str());
137        return false;
138    }
139
140    pid_t pid = fork();
141
142    switch (pid) {
143    case -1: {  // Error occurred (we attempt no recovery)
144        ALOGE("Couldn't fork for bcc compiler execution");
145        return false;
146    }
147    case 0: {  // Child process
148        ALOGV("Invoking BCC with: %s", compileCommandLine.c_str());
149        execv(android::renderscript::RsdCpuScriptImpl::BCC_EXE_PATH,
150              (char* const*)compileArguments);
151
152        ALOGE("execv() failed: %s", strerror(errno));
153        abort();
154        return false;
155    }
156    default: {  // Parent process (actual driver)
157        // Wait on child process to finish compiling the source.
158        int status = 0;
159        pid_t w = waitpid(pid, &status, 0);
160        if (w == -1) {
161            ALOGE("Could not wait for bcc compiler");
162            return false;
163        }
164
165        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
166            return true;
167        }
168
169        ALOGE("bcc compiler terminated unexpectedly");
170        return false;
171    }
172    }
173}
174
175#endif  // !defined(RS_COMPATIBILITY_LIB)
176}  // namespace
177
178namespace android {
179namespace renderscript {
180
181RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
182    mCtx = ctx;
183    mScript = s;
184
185    mScriptSO = nullptr;
186
187#ifndef RS_COMPATIBILITY_LIB
188    mCompilerDriver = nullptr;
189#endif
190
191
192    mRoot = nullptr;
193    mRootExpand = nullptr;
194    mInit = nullptr;
195    mFreeChildren = nullptr;
196    mScriptExec = nullptr;
197
198    mBoundAllocs = nullptr;
199    mIntrinsicData = nullptr;
200    mIsThreadable = true;
201}
202
203bool RsdCpuScriptImpl::storeRSInfoFromSO() {
204    mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
205    if (mRoot) {
206        //ALOGE("Found root(): %p", mRoot);
207    }
208    mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
209    if (mRootExpand) {
210        //ALOGE("Found root.expand(): %p", mRootExpand);
211    }
212    mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
213    if (mInit) {
214        //ALOGE("Found init(): %p", mInit);
215    }
216    mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
217    if (mFreeChildren) {
218        //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
219    }
220
221    mScriptExec = ScriptExecutable::createFromSharedObject(
222            mCtx->getContext(), mScriptSO);
223
224    if (mScriptExec == nullptr) {
225        return false;
226    }
227
228    size_t varCount = mScriptExec->getExportedVariableCount();
229    if (varCount > 0) {
230        mBoundAllocs = new Allocation *[varCount];
231        memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
232    }
233
234    mIsThreadable = mScriptExec->getThreadable();
235    //ALOGE("Script isThreadable? %d", mIsThreadable);
236
237    return true;
238}
239
240bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
241                            uint8_t const *bitcode, size_t bitcodeSize,
242                            uint32_t flags, char const *bccPluginName) {
243    //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir,
244    // bitcode, bitcodeSize, flags, lookupFunc);
245    //ALOGE("rsdScriptInit %p %p", rsc, script);
246
247    mCtx->lockMutex();
248#ifndef RS_COMPATIBILITY_LIB
249    bool useRSDebugContext = false;
250
251    mCompilerDriver = nullptr;
252
253    mCompilerDriver = new bcc::RSCompilerDriver();
254    if (mCompilerDriver == nullptr) {
255        ALOGE("bcc: FAILS to create compiler driver (out of memory)");
256        mCtx->unlockMutex();
257        return false;
258    }
259
260    // Run any compiler setup functions we have been provided with.
261    RSSetupCompilerCallback setupCompilerCallback =
262            mCtx->getSetupCompilerCallback();
263    if (setupCompilerCallback != nullptr) {
264        setupCompilerCallback(mCompilerDriver);
265    }
266
267    bcinfo::MetadataExtractor bitcodeMetadata((const char *) bitcode, bitcodeSize);
268    if (!bitcodeMetadata.extract()) {
269        ALOGE("Could not extract metadata from bitcode");
270        mCtx->unlockMutex();
271        return false;
272    }
273
274    const char* core_lib = findCoreLib(bitcodeMetadata, (const char*)bitcode, bitcodeSize);
275
276    if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
277        mCompilerDriver->setDebugContext(true);
278        useRSDebugContext = true;
279    }
280
281    std::string bcFileName(cacheDir);
282    bcFileName.append("/");
283    bcFileName.append(resName);
284    bcFileName.append(".bc");
285
286    std::vector<const char*> compileArguments;
287    setCompileArguments(&compileArguments, bcFileName, cacheDir, resName, core_lib,
288                        useRSDebugContext, bccPluginName);
289    // The last argument of compileArguments ia a nullptr, so remove 1 from the size.
290    std::unique_ptr<const char> joined(
291        rsuJoinStrings(compileArguments.size() - 1, compileArguments.data()));
292    std::string compileCommandLine (joined.get());
293
294    if (!is_force_recompile() && !useRSDebugContext) {
295        mScriptSO = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);
296    }
297
298    // If we can't, it's either not there or out of date.  We compile the bit code and try loading
299    // again.
300    if (mScriptSO == nullptr) {
301        if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize,
302                            compileArguments.data(), compileCommandLine))
303        {
304            ALOGE("bcc: FAILS to compile '%s'", resName);
305            mCtx->unlockMutex();
306            return false;
307        }
308
309        if (!SharedLibraryUtils::createSharedLibrary(cacheDir, resName)) {
310            ALOGE("Linker: Failed to link object file '%s'", resName);
311            mCtx->unlockMutex();
312            return false;
313        }
314
315        mScriptSO = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);
316        if (mScriptSO == nullptr) {
317            ALOGE("Unable to load '%s'", resName);
318            mCtx->unlockMutex();
319            return false;
320        }
321    }
322
323    mBitcodeFilePath.setTo(bcFileName.c_str());
324
325    // Read RS symbol information from the .so.
326    if ( !mScriptSO) {
327        goto error;
328    }
329
330    if ( !storeRSInfoFromSO()) {
331      goto error;
332    }
333#else  // RS_COMPATIBILITY_LIB is defined
334    const char *nativeLibDir = mCtx->getContext()->getNativeLibDir();
335    mScriptSO = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName, nativeLibDir);
336
337    if (!mScriptSO) {
338        goto error;
339    }
340
341    if (!storeRSInfoFromSO()) {
342        goto error;
343    }
344#endif
345    mCtx->unlockMutex();
346    return true;
347
348error:
349
350    mCtx->unlockMutex();
351    if (mScriptSO) {
352        dlclose(mScriptSO);
353        mScriptSO = nullptr;
354    }
355    return false;
356}
357
358#ifndef RS_COMPATIBILITY_LIB
359
360const char* RsdCpuScriptImpl::findCoreLib(const bcinfo::MetadataExtractor& ME, const char* bitcode,
361                                          size_t bitcodeSize) {
362    const char* defaultLib = SYSLIBPATH"/libclcore.bc";
363
364    // If we're debugging, use the debug library.
365    if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
366        return SYSLIBPATH"/libclcore_debug.bc";
367    }
368
369    // If a callback has been registered to specify a library, use that.
370    RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
371    if (selectRTCallback != nullptr) {
372        return selectRTCallback((const char*)bitcode, bitcodeSize);
373    }
374
375    // Check for a platform specific library
376#if defined(ARCH_ARM_HAVE_NEON) && !defined(DISABLE_CLCORE_NEON)
377    enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision();
378    if (prec == bcinfo::RS_FP_Relaxed) {
379        // NEON-capable ARMv7a devices can use an accelerated math library
380        // for all reduced precision scripts.
381        // ARMv8 does not use NEON, as ASIMD can be used with all precision
382        // levels.
383        return SYSLIBPATH"/libclcore_neon.bc";
384    } else {
385        return defaultLib;
386    }
387#elif defined(__i386__) || defined(__x86_64__)
388    // x86 devices will use an optimized library.
389    return SYSLIBPATH"/libclcore_x86.bc";
390#else
391    return defaultLib;
392#endif
393}
394
395#endif
396
397void RsdCpuScriptImpl::populateScript(Script *script) {
398    // Copy info over to runtime
399    script->mHal.info.exportedFunctionCount = mScriptExec->getExportedFunctionCount();
400    script->mHal.info.exportedVariableCount = mScriptExec->getExportedVariableCount();
401    script->mHal.info.exportedPragmaCount = mScriptExec->getPragmaCount();;
402    script->mHal.info.exportedPragmaKeyList = mScriptExec->getPragmaKeys();
403    script->mHal.info.exportedPragmaValueList = mScriptExec->getPragmaValues();
404
405    // Bug, need to stash in metadata
406    if (mRootExpand) {
407        script->mHal.info.root = mRootExpand;
408    } else {
409        script->mHal.info.root = mRoot;
410    }
411}
412
413
414typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
415
416bool RsdCpuScriptImpl::forEachMtlsSetup(const Allocation ** ains,
417                                        uint32_t inLen,
418                                        Allocation * aout,
419                                        const void * usr, uint32_t usrLen,
420                                        const RsScriptCall *sc,
421                                        MTLaunchStruct *mtls) {
422
423    memset(mtls, 0, sizeof(MTLaunchStruct));
424
425    for (int index = inLen; --index >= 0;) {
426        const Allocation* ain = ains[index];
427
428        // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
429        if (ain != nullptr &&
430            (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == nullptr) {
431
432            mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
433                                         "rsForEach called with null in allocations");
434            return false;
435        }
436    }
437
438    if (aout &&
439        (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == nullptr) {
440
441        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
442                                     "rsForEach called with null out allocations");
443        return false;
444    }
445
446    if (inLen > 0) {
447        const Allocation *ain0   = ains[0];
448        const Type       *inType = ain0->getType();
449
450        mtls->fep.dim.x = inType->getDimX();
451        mtls->fep.dim.y = inType->getDimY();
452        mtls->fep.dim.z = inType->getDimZ();
453
454        for (int Index = inLen; --Index >= 1;) {
455            if (!ain0->hasSameDims(ains[Index])) {
456                mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
457                  "Failed to launch kernel; dimensions of input and output"
458                  "allocations do not match.");
459
460                return false;
461            }
462        }
463
464    } else if (aout != nullptr) {
465        const Type *outType = aout->getType();
466
467        mtls->fep.dim.x = outType->getDimX();
468        mtls->fep.dim.y = outType->getDimY();
469        mtls->fep.dim.z = outType->getDimZ();
470
471    } else {
472        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
473                                     "rsForEach called with null allocations");
474        return false;
475    }
476
477    if (inLen > 0 && aout != nullptr) {
478        if (!ains[0]->hasSameDims(aout)) {
479            mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
480              "Failed to launch kernel; dimensions of input and output allocations do not match.");
481
482            return false;
483        }
484    }
485
486    if (!sc || (sc->xEnd == 0)) {
487        mtls->end.x = mtls->fep.dim.x;
488    } else {
489        mtls->start.x = rsMin(mtls->fep.dim.x, sc->xStart);
490        mtls->end.x = rsMin(mtls->fep.dim.x, sc->xEnd);
491        if (mtls->start.x >= mtls->end.x) return false;
492    }
493
494    if (!sc || (sc->yEnd == 0)) {
495        mtls->end.y = mtls->fep.dim.y;
496    } else {
497        mtls->start.y = rsMin(mtls->fep.dim.y, sc->yStart);
498        mtls->end.y = rsMin(mtls->fep.dim.y, sc->yEnd);
499        if (mtls->start.y >= mtls->end.y) return false;
500    }
501
502    if (!sc || (sc->zEnd == 0)) {
503        mtls->end.z = mtls->fep.dim.z;
504    } else {
505        mtls->start.z = rsMin(mtls->fep.dim.z, sc->zStart);
506        mtls->end.z = rsMin(mtls->fep.dim.z, sc->zEnd);
507        if (mtls->start.z >= mtls->end.z) return false;
508    }
509
510    if (!sc || (sc->arrayEnd == 0)) {
511        mtls->end.array[0] = mtls->fep.dim.array[0];
512    } else {
513        mtls->start.array[0] = rsMin(mtls->fep.dim.array[0], sc->arrayStart);
514        mtls->end.array[0] = rsMin(mtls->fep.dim.array[0], sc->arrayEnd);
515        if (mtls->start.array[0] >= mtls->end.array[0]) return false;
516    }
517
518    if (!sc || (sc->array2End == 0)) {
519        mtls->end.array[1] = mtls->fep.dim.array[1];
520    } else {
521        mtls->start.array[1] = rsMin(mtls->fep.dim.array[1], sc->array2Start);
522        mtls->end.array[1] = rsMin(mtls->fep.dim.array[1], sc->array2End);
523        if (mtls->start.array[1] >= mtls->end.array[1]) return false;
524    }
525
526    if (!sc || (sc->array3End == 0)) {
527        mtls->end.array[2] = mtls->fep.dim.array[2];
528    } else {
529        mtls->start.array[2] = rsMin(mtls->fep.dim.array[2], sc->array3Start);
530        mtls->end.array[2] = rsMin(mtls->fep.dim.array[2], sc->array3End);
531        if (mtls->start.array[2] >= mtls->end.array[2]) return false;
532    }
533
534    if (!sc || (sc->array4End == 0)) {
535        mtls->end.array[3] = mtls->fep.dim.array[3];
536    } else {
537        mtls->start.array[3] = rsMin(mtls->fep.dim.array[3], sc->array4Start);
538        mtls->end.array[3] = rsMin(mtls->fep.dim.array[3], sc->array4End);
539        if (mtls->start.array[3] >= mtls->end.array[3]) return false;
540    }
541
542
543    // The X & Y walkers always want 0-1 min even if dim is not present
544    mtls->end.x    = rsMax((uint32_t)1, mtls->end.x);
545    mtls->end.y    = rsMax((uint32_t)1, mtls->end.y);
546
547    mtls->rsc        = mCtx;
548    if (ains) {
549        memcpy(mtls->ains, ains, inLen * sizeof(ains[0]));
550    }
551    mtls->aout[0]    = aout;
552    mtls->fep.usr    = usr;
553    mtls->fep.usrLen = usrLen;
554    mtls->mSliceSize = 1;
555    mtls->mSliceNum  = 0;
556
557    mtls->isThreadable  = mIsThreadable;
558
559    if (inLen > 0) {
560        mtls->fep.inLen = inLen;
561        for (int index = inLen; --index >= 0;) {
562            mtls->fep.inPtr[index] = (const uint8_t*)ains[index]->mHal.drvState.lod[0].mallocPtr;
563            mtls->fep.inStride[index] = ains[index]->getType()->getElementSizeBytes();
564        }
565    }
566
567    if (aout != nullptr) {
568        mtls->fep.outPtr[0] = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
569        mtls->fep.outStride[0] = aout->getType()->getElementSizeBytes();
570    }
571
572    // All validation passed, ok to launch threads
573    return true;
574}
575
576
577void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
578                                     const Allocation ** ains,
579                                     uint32_t inLen,
580                                     Allocation * aout,
581                                     const void * usr,
582                                     uint32_t usrLen,
583                                     const RsScriptCall *sc) {
584
585    MTLaunchStruct mtls;
586
587    if (forEachMtlsSetup(ains, inLen, aout, usr, usrLen, sc, &mtls)) {
588        forEachKernelSetup(slot, &mtls);
589
590        RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
591        mCtx->launchThreads(ains, inLen, aout, sc, &mtls);
592        mCtx->setTLS(oldTLS);
593    }
594}
595
596void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
597    mtls->script = this;
598    mtls->fep.slot = slot;
599    mtls->kernel = mScriptExec->getForEachFunction(slot);
600    rsAssert(mtls->kernel != nullptr);
601    mtls->sig = mScriptExec->getForEachSignature(slot);
602}
603
604int RsdCpuScriptImpl::invokeRoot() {
605    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
606    int ret = mRoot();
607    mCtx->setTLS(oldTLS);
608    return ret;
609}
610
611void RsdCpuScriptImpl::invokeInit() {
612    if (mInit) {
613        mInit();
614    }
615}
616
617void RsdCpuScriptImpl::invokeFreeChildren() {
618    if (mFreeChildren) {
619        mFreeChildren();
620    }
621}
622
623void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
624                                      size_t paramLength) {
625    //ALOGE("invoke %i %p %zu", slot, params, paramLength);
626    void * ap = nullptr;
627
628#if defined(__x86_64__)
629    // The invoked function could have input parameter of vector type for example float4 which
630    // requires void* params to be 16 bytes aligned when using SSE instructions for x86_64 platform.
631    // So try to align void* params before passing them into RS exported function.
632
633    if ((uint8_t)(uint64_t)params & 0x0F) {
634        if ((ap = (void*)memalign(16, paramLength)) != nullptr) {
635            memcpy(ap, params, paramLength);
636        } else {
637            ALOGE("x86_64: invokeFunction memalign error, still use params which"
638                  " is not 16 bytes aligned.");
639        }
640    }
641#endif
642
643    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
644    reinterpret_cast<void (*)(const void *, uint32_t)>(
645        mScriptExec->getInvokeFunction(slot))(ap? (const void *) ap: params, paramLength);
646
647    mCtx->setTLS(oldTLS);
648}
649
650void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
651    //rsAssert(!script->mFieldIsObject[slot]);
652    //ALOGE("setGlobalVar %i %p %zu", slot, data, dataLength);
653
654    //if (mIntrinsicID) {
655        //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
656        //return;
657    //}
658
659    int32_t *destPtr = reinterpret_cast<int32_t *>(mScriptExec->getFieldAddress(slot));
660    if (!destPtr) {
661        //ALOGV("Calling setVar on slot = %i which is null", slot);
662        return;
663    }
664
665    memcpy(destPtr, data, dataLength);
666}
667
668void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
669    //rsAssert(!script->mFieldIsObject[slot]);
670    //ALOGE("getGlobalVar %i %p %zu", slot, data, dataLength);
671
672    int32_t *srcPtr = reinterpret_cast<int32_t *>(mScriptExec->getFieldAddress(slot));
673    if (!srcPtr) {
674        //ALOGV("Calling setVar on slot = %i which is null", slot);
675        return;
676    }
677    memcpy(data, srcPtr, dataLength);
678}
679
680
681void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
682                                                const Element *elem,
683                                                const uint32_t *dims, size_t dimLength) {
684    int32_t *destPtr = reinterpret_cast<int32_t *>(mScriptExec->getFieldAddress(slot));
685    if (!destPtr) {
686        //ALOGV("Calling setVar on slot = %i which is null", slot);
687        return;
688    }
689
690    // We want to look at dimension in terms of integer components,
691    // but dimLength is given in terms of bytes.
692    dimLength /= sizeof(int);
693
694    // Only a single dimension is currently supported.
695    rsAssert(dimLength == 1);
696    if (dimLength == 1) {
697        // First do the increment loop.
698        size_t stride = elem->getSizeBytes();
699        const char *cVal = reinterpret_cast<const char *>(data);
700        for (uint32_t i = 0; i < dims[0]; i++) {
701            elem->incRefs(cVal);
702            cVal += stride;
703        }
704
705        // Decrement loop comes after (to prevent race conditions).
706        char *oldVal = reinterpret_cast<char *>(destPtr);
707        for (uint32_t i = 0; i < dims[0]; i++) {
708            elem->decRefs(oldVal);
709            oldVal += stride;
710        }
711    }
712
713    memcpy(destPtr, data, dataLength);
714}
715
716void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
717
718    //rsAssert(!script->mFieldIsObject[slot]);
719    //ALOGE("setGlobalBind %i %p", slot, data);
720
721    int32_t *destPtr = reinterpret_cast<int32_t *>(mScriptExec->getFieldAddress(slot));
722    if (!destPtr) {
723        //ALOGV("Calling setVar on slot = %i which is null", slot);
724        return;
725    }
726
727    void *ptr = nullptr;
728    mBoundAllocs[slot] = data;
729    if (data) {
730        ptr = data->mHal.drvState.lod[0].mallocPtr;
731    }
732    memcpy(destPtr, &ptr, sizeof(void *));
733}
734
735void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
736
737    //rsAssert(script->mFieldIsObject[slot]);
738    //ALOGE("setGlobalObj %i %p", slot, data);
739
740    int32_t *destPtr = reinterpret_cast<int32_t *>(mScriptExec->getFieldAddress(slot));
741    if (!destPtr) {
742        //ALOGV("Calling setVar on slot = %i which is null", slot);
743        return;
744    }
745
746    rsrSetObject(mCtx->getContext(), (rs_object_base *)destPtr, data);
747}
748
749RsdCpuScriptImpl::~RsdCpuScriptImpl() {
750#ifndef RS_COMPATIBILITY_LIB
751    if (mCompilerDriver) {
752        delete mCompilerDriver;
753    }
754#endif
755
756    if (mScriptExec != nullptr) {
757        delete mScriptExec;
758    }
759    if (mBoundAllocs) delete[] mBoundAllocs;
760    if (mScriptSO) {
761        dlclose(mScriptSO);
762    }
763}
764
765Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const {
766    if (!ptr) {
767        return nullptr;
768    }
769
770    for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) {
771        Allocation *a = mBoundAllocs[ct];
772        if (!a) continue;
773        if (a->mHal.drvState.lod[0].mallocPtr == ptr) {
774            return a;
775        }
776    }
777    ALOGE("rsGetAllocation, failed to find %p", ptr);
778    return nullptr;
779}
780
781void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation ** ains,
782                                 uint32_t inLen, Allocation * aout,
783                                 const void * usr, uint32_t usrLen,
784                                 const RsScriptCall *sc) {}
785
786void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation ** ains,
787                                  uint32_t inLen, Allocation * aout,
788                                  const void * usr, uint32_t usrLen,
789                                  const RsScriptCall *sc) {}
790
791
792}
793}
794