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 "rsdCore.h"
18#include "rsdBcc.h"
19#include "rsdRuntime.h"
20#include "rsdAllocation.h"
21#include "rsdIntrinsics.h"
22
23#include "rsContext.h"
24#include "rsElement.h"
25#include "rsScriptC.h"
26
27#include "utils/Vector.h"
28#include "utils/Timers.h"
29#include "utils/StopWatch.h"
30#include "utils/String8.h"
31
32#include <dlfcn.h>
33#include <stdio.h>
34#include <string.h>
35
36using namespace android;
37using namespace android::renderscript;
38
39#define MAXLINE 500
40#define MAKE_STR_HELPER(S) #S
41#define MAKE_STR(S) MAKE_STR_HELPER(S)
42#define EXPORT_VAR_STR "exportVarCount: "
43#define EXPORT_VAR_STR_LEN strlen(EXPORT_VAR_STR)
44#define EXPORT_FUNC_STR "exportFuncCount: "
45#define EXPORT_FUNC_STR_LEN strlen(EXPORT_FUNC_STR)
46#define EXPORT_FOREACH_STR "exportForEachCount: "
47#define EXPORT_FOREACH_STR_LEN strlen(EXPORT_FOREACH_STR)
48#define OBJECT_SLOT_STR "objectSlotCount: "
49#define OBJECT_SLOT_STR_LEN strlen(OBJECT_SLOT_STR)
50
51
52
53static Script * setTLS(Script *sc) {
54    ScriptTLSStruct * tls = (ScriptTLSStruct *)pthread_getspecific(rsdgThreadTLSKey);
55    rsAssert(tls);
56    Script *old = tls->mScript;
57    tls->mScript = sc;
58    return old;
59}
60
61
62bool rsdScriptInit(const Context *rsc,
63                     ScriptC *script,
64                     char const *resName,
65                     char const *cacheDir,
66                     uint8_t const *bitcode,
67                     size_t bitcodeSize,
68                     uint32_t flags) {
69    //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
70    //ALOGE("rsdScriptInit %p %p", rsc, script);
71
72    pthread_mutex_lock(&rsdgInitMutex);
73
74    String8 scriptSOName(cacheDir);
75    scriptSOName = scriptSOName.getPathDir();
76    scriptSOName.appendPath("lib");
77    scriptSOName.append("/lib");
78    scriptSOName.append(resName);
79    scriptSOName.append(".so");
80
81    String8 scriptInfoName(cacheDir);
82    scriptInfoName = scriptInfoName.getPathDir();
83    scriptInfoName.appendPath("lib/");
84    scriptInfoName.append(resName);
85    scriptInfoName.append(".bcinfo");
86
87    void *scriptSO = NULL;
88    FILE *fp = NULL;
89    DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript));
90    if (drv == NULL) {
91        goto error;
92    }
93    script->mHal.drv = drv;
94
95    ALOGE("Opening up info object: %s", scriptInfoName.string());
96
97    fp = fopen(scriptInfoName.string(), "r");
98    if (!fp) {
99        ALOGE("Unable to open info file: %s", scriptInfoName.string());
100        goto error;
101    }
102
103    ALOGE("Opening up shared object: %s", scriptSOName.string());
104    scriptSO = dlopen(scriptSOName.string(), RTLD_NOW | RTLD_LOCAL);
105    if (scriptSO == NULL) {
106        ALOGE("Unable to open shared library (%s): %s",
107              scriptSOName.string(), dlerror());
108        goto error;
109    }
110    drv->mScriptSO = scriptSO;
111
112    if (scriptSO) {
113        char line[MAXLINE];
114        drv->mScriptSO = scriptSO;
115        drv->mRoot = (RootFunc_t) dlsym(scriptSO, "root");
116        if (drv->mRoot) {
117            ALOGE("Found root(): %p", drv->mRoot);
118        }
119        drv->mRootExpand = (RootFunc_t) dlsym(scriptSO, "root.expand");
120        if (drv->mRootExpand) {
121            ALOGE("Found root.expand(): %p", drv->mRootExpand);
122        }
123        drv->mInit = (InvokeFunc_t) dlsym(scriptSO, "init");
124        if (drv->mInit) {
125            ALOGE("Found init(): %p", drv->mInit);
126        }
127        drv->mFreeChildren = (InvokeFunc_t) dlsym(scriptSO, ".rs.dtor");
128        if (drv->mFreeChildren) {
129            ALOGE("Found .rs.dtor(): %p", drv->mFreeChildren);
130        }
131
132        size_t varCount = 0;
133        if (fgets(line, MAXLINE, fp) == NULL) {
134            goto error;
135        }
136        if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
137            ALOGE("Invalid export var count!: %s", line);
138            goto error;
139        }
140
141        script->mHal.info.exportedVariableCount = varCount;
142        ALOGE("varCount: %zu", varCount);
143        if (varCount > 0) {
144            // Start by creating/zeroing this member, since we don't want to
145            // accidentally clean up invalid pointers later (if we error out).
146            drv->mFieldIsObject = new bool[varCount];
147            if (drv->mFieldIsObject == NULL) {
148                goto error;
149            }
150            memset(drv->mFieldIsObject, 0,
151                   varCount * sizeof(*drv->mFieldIsObject));
152            drv->mFieldAddress = new void*[varCount];
153            if (drv->mFieldAddress == NULL) {
154                goto error;
155            }
156            for (size_t i = 0; i < varCount; ++i) {
157                if (fgets(line, MAXLINE, fp) == NULL) {
158                    goto error;
159                }
160                char *c = strrchr(line, '\n');
161                if (c) {
162                    *c = '\0';
163                }
164                drv->mFieldAddress[i] = dlsym(scriptSO, line);
165                if (drv->mFieldAddress[i] == NULL) {
166                    ALOGE("Failed to find variable address for %s: %s",
167                          line, dlerror());
168                    // Not a critical error if we don't find a global variable.
169                }
170                else {
171                    ALOGE("Found variable %s at %p", line,
172                          drv->mFieldAddress[i]);
173                }
174            }
175        }
176
177        size_t funcCount = 0;
178        if (fgets(line, MAXLINE, fp) == NULL) {
179            goto error;
180        }
181        if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
182            ALOGE("Invalid export func count!: %s", line);
183            goto error;
184        }
185
186        script->mHal.info.exportedFunctionCount = funcCount;
187        ALOGE("funcCount: %zu", funcCount);
188
189        if (funcCount > 0) {
190            drv->mInvokeFunctions = new InvokeFunc_t[funcCount];
191            if (drv->mInvokeFunctions == NULL) {
192                goto error;
193            }
194            for (size_t i = 0; i < funcCount; ++i) {
195                if (fgets(line, MAXLINE, fp) == NULL) {
196                    goto error;
197                }
198                char *c = strrchr(line, '\n');
199                if (c) {
200                    *c = '\0';
201                }
202
203                drv->mInvokeFunctions[i] =
204                        (InvokeFunc_t) dlsym(scriptSO, line);
205                if (drv->mInvokeFunctions[i] == NULL) {
206                    ALOGE("Failed to get function address for %s(): %s",
207                          line, dlerror());
208                    goto error;
209                }
210                else {
211                    ALOGE("Found InvokeFunc_t %s at %p", line,
212                          drv->mInvokeFunctions[i]);
213                }
214            }
215        }
216
217        size_t forEachCount = 0;
218        if (fgets(line, MAXLINE, fp) == NULL) {
219            goto error;
220        }
221        if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
222            ALOGE("Invalid export forEach count!: %s", line);
223            goto error;
224        }
225
226        if (forEachCount > 0) {
227
228            drv->mForEachSignatures = new uint32_t[forEachCount];
229            if (drv->mForEachSignatures == NULL) {
230                goto error;
231            }
232            drv->mForEachFunctions = new ForEachFunc_t[forEachCount];
233            if (drv->mForEachFunctions == NULL) {
234                goto error;
235            }
236            for (size_t i = 0; i < forEachCount; ++i) {
237                unsigned int tmpSig = 0;
238                char tmpName[MAXLINE];
239
240                if (fgets(line, MAXLINE, fp) == NULL) {
241                    goto error;
242                }
243                if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
244                           &tmpSig, tmpName) != 2) {
245                    ALOGE("Invalid export forEach!: %s", line);
246                    goto error;
247                }
248
249                drv->mForEachSignatures[i] = tmpSig;
250                drv->mForEachFunctions[i] =
251                        (ForEachFunc_t) dlsym(scriptSO, tmpName);
252                if (drv->mForEachFunctions[i] == NULL) {
253                    ALOGE("Failed to find forEach function address for %s: %s",
254                          tmpName, dlerror());
255                    goto error;
256                }
257                else {
258                    // TODO - Maybe add ForEachExpandPass to .so creation and
259                    // then lookup the ".expand" version of these kernels
260                    // instead.
261                    ALOGE("Found forEach %s at %p", tmpName,
262                          drv->mForEachFunctions[i]);
263                }
264            }
265        }
266
267        size_t objectSlotCount = 0;
268        if (fgets(line, MAXLINE, fp) == NULL) {
269            goto error;
270        }
271        if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
272            ALOGE("Invalid object slot count!: %s", line);
273            goto error;
274        }
275
276        if (objectSlotCount > 0) {
277            rsAssert(varCount > 0);
278            for (size_t i = 0; i < objectSlotCount; ++i) {
279                uint32_t varNum = 0;
280                if (fgets(line, MAXLINE, fp) == NULL) {
281                    goto error;
282                }
283                if (sscanf(line, "%u", &varNum) != 1) {
284                    ALOGE("Invalid object slot!: %s", line);
285                    goto error;
286                }
287
288                if (varNum < varCount) {
289                    drv->mFieldIsObject[varNum] = true;
290                }
291            }
292        }
293
294        script->mHal.info.exportedPragmaCount = 0;
295
296        if (drv->mRootExpand) {
297            script->mHal.info.root = drv->mRootExpand;
298        } else {
299            script->mHal.info.root = drv->mRoot;
300        }
301
302        if (varCount > 0) {
303            drv->mBoundAllocs = new Allocation *[varCount];
304            memset(drv->mBoundAllocs, 0, varCount * sizeof(*drv->mBoundAllocs));
305        }
306
307        script->mHal.info.isThreadable = true;
308
309        if (scriptSO == (void*)1) {
310            rsdLookupRuntimeStub(script, "acos");
311        }
312    }
313
314    fclose(fp);
315    pthread_mutex_unlock(&rsdgInitMutex);
316    return true;
317
318error:
319
320    fclose(fp);
321    pthread_mutex_unlock(&rsdgInitMutex);
322    if (drv) {
323        delete[] drv->mInvokeFunctions;
324        delete[] drv->mForEachFunctions;
325        delete[] drv->mFieldAddress;
326        delete[] drv->mFieldIsObject;
327        delete[] drv->mForEachSignatures;
328        delete[] drv->mBoundAllocs;
329        if (drv->mScriptSO) {
330            dlclose(drv->mScriptSO);
331        }
332        free(drv);
333    }
334    script->mHal.drv = NULL;
335    return false;
336
337}
338
339bool rsdInitIntrinsic(const Context *rsc, Script *s, RsScriptIntrinsicID iid, Element *e) {
340    pthread_mutex_lock(&rsdgInitMutex);
341
342    DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript));
343    if (drv == NULL) {
344        goto error;
345    }
346    s->mHal.drv = drv;
347    drv->mIntrinsicID = iid;
348    drv->mIntrinsicData = rsdIntrinsic_Init(rsc, s, iid, &drv->mIntrinsicFuncs);
349    s->mHal.info.isThreadable = true;
350
351    pthread_mutex_unlock(&rsdgInitMutex);
352    return true;
353
354error:
355    pthread_mutex_unlock(&rsdgInitMutex);
356    return false;
357}
358
359typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
360
361static void wc_xy(void *usr, uint32_t idx) {
362    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
363    RsForEachStubParamStruct p;
364    memcpy(&p, &mtls->fep, sizeof(p));
365    RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
366    uint32_t sig = mtls->sig;
367
368    rs_t bare_fn = (rs_t) mtls->kernel;
369    while (1) {
370        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
371        uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
372        uint32_t yEnd = yStart + mtls->mSliceSize;
373        yEnd = rsMin(yEnd, mtls->yEnd);
374        if (yEnd <= yStart) {
375            return;
376        }
377
378        //ALOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
379        //ALOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
380        for (p.y = yStart; p.y < yEnd; p.y++) {
381            p.out = mtls->fep.ptrOut + (mtls->fep.yStrideOut * p.y);
382            p.in = mtls->fep.ptrIn + (mtls->fep.yStrideIn * p.y);
383            for (uint32_t x = mtls->xStart; x < mtls->xEnd; ++x) {
384                bare_fn(p.in, p.out, p.usr, x, p.y, 0, 0);
385                p.in = (char *)(p.in) + mtls->fep.eStrideIn;
386                p.out = (char *)(p.out) + mtls->fep.eStrideOut;
387            }
388        }
389    }
390}
391
392static void wc_x(void *usr, uint32_t idx) {
393    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
394    RsForEachStubParamStruct p;
395    memcpy(&p, &mtls->fep, sizeof(p));
396    RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
397    uint32_t sig = mtls->sig;
398
399    rs_t bare_fn = (rs_t) mtls->kernel;
400    while (1) {
401        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
402        uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
403        uint32_t xEnd = xStart + mtls->mSliceSize;
404        xEnd = rsMin(xEnd, mtls->xEnd);
405        if (xEnd <= xStart) {
406            return;
407        }
408
409        //ALOGE("usr slice %i idx %i, x %i,%i", slice, idx, xStart, xEnd);
410        //ALOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
411
412        p.out = mtls->fep.ptrOut + (mtls->fep.eStrideOut * xStart);
413        p.in = mtls->fep.ptrIn + (mtls->fep.eStrideIn * xStart);
414        for (uint32_t x = mtls->xStart; x < mtls->xEnd; ++x) {
415            bare_fn(p.in, p.out, p.usr, x, 0, 0, 0);
416            p.in = (char *)(p.in) + mtls->fep.eStrideIn;
417            p.out = (char *)(p.out) + mtls->fep.eStrideOut;
418        }
419    }
420}
421
422void rsdScriptInvokeForEachMtlsSetup(const Context *rsc,
423                                     const Allocation * ain,
424                                     Allocation * aout,
425                                     const void * usr,
426                                     uint32_t usrLen,
427                                     const RsScriptCall *sc,
428                                     MTLaunchStruct *mtls) {
429
430    memset(mtls, 0, sizeof(MTLaunchStruct));
431
432    if (ain) {
433        mtls->fep.dimX = ain->getType()->getDimX();
434        mtls->fep.dimY = ain->getType()->getDimY();
435        mtls->fep.dimZ = ain->getType()->getDimZ();
436        //mtls->dimArray = ain->getType()->getDimArray();
437    } else if (aout) {
438        mtls->fep.dimX = aout->getType()->getDimX();
439        mtls->fep.dimY = aout->getType()->getDimY();
440        mtls->fep.dimZ = aout->getType()->getDimZ();
441        //mtls->dimArray = aout->getType()->getDimArray();
442    } else {
443        rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
444        return;
445    }
446
447    if (!sc || (sc->xEnd == 0)) {
448        mtls->xEnd = mtls->fep.dimX;
449    } else {
450        rsAssert(sc->xStart < mtls->fep.dimX);
451        rsAssert(sc->xEnd <= mtls->fep.dimX);
452        rsAssert(sc->xStart < sc->xEnd);
453        mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
454        mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
455        if (mtls->xStart >= mtls->xEnd) return;
456    }
457
458    if (!sc || (sc->yEnd == 0)) {
459        mtls->yEnd = mtls->fep.dimY;
460    } else {
461        rsAssert(sc->yStart < mtls->fep.dimY);
462        rsAssert(sc->yEnd <= mtls->fep.dimY);
463        rsAssert(sc->yStart < sc->yEnd);
464        mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
465        mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
466        if (mtls->yStart >= mtls->yEnd) return;
467    }
468
469    mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
470    mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
471    mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
472    mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
473
474    rsAssert(!ain || (ain->getType()->getDimZ() == 0));
475
476    Context *mrsc = (Context *)rsc;
477    mtls->rsc = mrsc;
478    mtls->ain = ain;
479    mtls->aout = aout;
480    mtls->fep.usr = usr;
481    mtls->fep.usrLen = usrLen;
482    mtls->mSliceSize = 10;
483    mtls->mSliceNum = 0;
484
485    mtls->fep.ptrIn = NULL;
486    mtls->fep.eStrideIn = 0;
487
488    if (ain) {
489        DrvAllocation *aindrv = (DrvAllocation *)ain->mHal.drv;
490        mtls->fep.ptrIn = (const uint8_t *)aindrv->lod[0].mallocPtr;
491        mtls->fep.eStrideIn = ain->getType()->getElementSizeBytes();
492        mtls->fep.yStrideIn = aindrv->lod[0].stride;
493    }
494
495    mtls->fep.ptrOut = NULL;
496    mtls->fep.eStrideOut = 0;
497    if (aout) {
498        DrvAllocation *aoutdrv = (DrvAllocation *)aout->mHal.drv;
499        mtls->fep.ptrOut = (uint8_t *)aoutdrv->lod[0].mallocPtr;
500        mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes();
501        mtls->fep.yStrideOut = aoutdrv->lod[0].stride;
502    }
503}
504
505void rsdScriptLaunchThreads(const Context *rsc,
506                            Script *s,
507                            uint32_t slot,
508                            const Allocation * ain,
509                            Allocation * aout,
510                            const void * usr,
511                            uint32_t usrLen,
512                            const RsScriptCall *sc,
513                            MTLaunchStruct *mtls) {
514
515    Script * oldTLS = setTLS(s);
516    Context *mrsc = (Context *)rsc;
517    RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
518
519    if ((dc->mWorkers.mCount > 1) && s->mHal.info.isThreadable && !dc->mInForEach) {
520        dc->mInForEach = true;
521        if (mtls->fep.dimY > 1) {
522            mtls->mSliceSize = mtls->fep.dimY / (dc->mWorkers.mCount * 4);
523            if(mtls->mSliceSize < 1) {
524                mtls->mSliceSize = 1;
525            }
526
527            rsdLaunchThreads(mrsc, wc_xy, mtls);
528        } else {
529            mtls->mSliceSize = mtls->fep.dimX / (dc->mWorkers.mCount * 4);
530            if(mtls->mSliceSize < 1) {
531                mtls->mSliceSize = 1;
532            }
533
534            rsdLaunchThreads(mrsc, wc_x, mtls);
535        }
536        dc->mInForEach = false;
537
538        //ALOGE("launch 1");
539    } else {
540        RsForEachStubParamStruct p;
541        memcpy(&p, &mtls->fep, sizeof(p));
542        uint32_t sig = mtls->sig;
543
544        //ALOGE("launch 3");
545        outer_foreach_t fn = (outer_foreach_t) mtls->kernel;
546        for (p.ar[0] = mtls->arrayStart; p.ar[0] < mtls->arrayEnd; p.ar[0]++) {
547            for (p.z = mtls->zStart; p.z < mtls->zEnd; p.z++) {
548                for (p.y = mtls->yStart; p.y < mtls->yEnd; p.y++) {
549                    uint32_t offset = mtls->fep.dimY * mtls->fep.dimZ * p.ar[0] +
550                                      mtls->fep.dimY * p.z + p.y;
551                    p.out = mtls->fep.ptrOut + (mtls->fep.yStrideOut * offset);
552                    p.in = mtls->fep.ptrIn + (mtls->fep.yStrideIn * offset);
553                    fn(&p, mtls->xStart, mtls->xEnd, mtls->fep.eStrideIn, mtls->fep.eStrideOut);
554                }
555            }
556        }
557    }
558
559    setTLS(oldTLS);
560}
561
562void rsdScriptInvokeForEach(const Context *rsc,
563                            Script *s,
564                            uint32_t slot,
565                            const Allocation * ain,
566                            Allocation * aout,
567                            const void * usr,
568                            uint32_t usrLen,
569                            const RsScriptCall *sc) {
570
571    RsdHal * dc = (RsdHal *)rsc->mHal.drv;
572
573    MTLaunchStruct mtls;
574    rsdScriptInvokeForEachMtlsSetup(rsc, ain, aout, usr, usrLen, sc, &mtls);
575    mtls.script = s;
576    mtls.fep.slot = slot;
577
578    DrvScript *drv = (DrvScript *)s->mHal.drv;
579    if (drv->mIntrinsicID) {
580        mtls.kernel = (void (*)())drv->mIntrinsicFuncs.root;
581        mtls.fep.usr = drv->mIntrinsicData;
582    } else {
583		mtls.kernel = drv->mForEachFunctions[slot];
584        rsAssert(mtls.kernel != NULL);
585        mtls.sig = drv->mForEachSignatures[slot];
586    }
587
588
589    rsdScriptLaunchThreads(rsc, s, slot, ain, aout, usr, usrLen, sc, &mtls);
590}
591
592
593int rsdScriptInvokeRoot(const Context *dc, Script *script) {
594    DrvScript *drv = (DrvScript *)script->mHal.drv;
595
596    Script * oldTLS = setTLS(script);
597    int ret = drv->mRoot();
598    setTLS(oldTLS);
599
600    return ret;
601}
602
603void rsdScriptInvokeInit(const Context *dc, Script *script) {
604    DrvScript *drv = (DrvScript *)script->mHal.drv;
605
606    if (drv->mInit) {
607        drv->mInit();
608    }
609}
610
611void rsdScriptInvokeFreeChildren(const Context *dc, Script *script) {
612    DrvScript *drv = (DrvScript *)script->mHal.drv;
613
614    if (drv->mFreeChildren) {
615        drv->mFreeChildren();
616    }
617}
618
619void rsdScriptInvokeFunction(const Context *dc, Script *script,
620                            uint32_t slot,
621                            const void *params,
622                            size_t paramLength) {
623    DrvScript *drv = (DrvScript *)script->mHal.drv;
624    //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
625
626    Script * oldTLS = setTLS(script);
627    reinterpret_cast<void (*)(const void *, uint32_t)>(
628        drv->mInvokeFunctions[slot])(params, paramLength);
629    setTLS(oldTLS);
630}
631
632void rsdScriptSetGlobalVar(const Context *dc, const Script *script,
633                           uint32_t slot, void *data, size_t dataLength) {
634    DrvScript *drv = (DrvScript *)script->mHal.drv;
635    //rsAssert(!script->mFieldIsObject[slot]);
636    //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
637
638    if (drv->mIntrinsicID) {
639        drv->mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
640        return;
641    }
642
643    int32_t *destPtr = reinterpret_cast<int32_t *>(drv->mFieldAddress[slot]);
644    if (!destPtr) {
645        //ALOGV("Calling setVar on slot = %i which is null", slot);
646        return;
647    }
648
649    memcpy(destPtr, data, dataLength);
650}
651
652void rsdScriptSetGlobalVarWithElemDims(
653        const android::renderscript::Context *dc,
654        const android::renderscript::Script *script,
655        uint32_t slot, void *data, size_t dataLength,
656        const android::renderscript::Element *elem,
657        const size_t *dims, size_t dimLength) {
658    DrvScript *drv = (DrvScript *)script->mHal.drv;
659
660    int32_t *destPtr = reinterpret_cast<int32_t *>(drv->mFieldAddress[slot]);
661    if (!destPtr) {
662        //ALOGV("Calling setVar on slot = %i which is null", slot);
663        return;
664    }
665
666    // We want to look at dimension in terms of integer components,
667    // but dimLength is given in terms of bytes.
668    dimLength /= sizeof(int);
669
670    // Only a single dimension is currently supported.
671    rsAssert(dimLength == 1);
672    if (dimLength == 1) {
673        // First do the increment loop.
674        size_t stride = elem->getSizeBytes();
675        char *cVal = reinterpret_cast<char *>(data);
676        for (size_t i = 0; i < dims[0]; i++) {
677            elem->incRefs(cVal);
678            cVal += stride;
679        }
680
681        // Decrement loop comes after (to prevent race conditions).
682        char *oldVal = reinterpret_cast<char *>(destPtr);
683        for (size_t i = 0; i < dims[0]; i++) {
684            elem->decRefs(oldVal);
685            oldVal += stride;
686        }
687    }
688
689    memcpy(destPtr, data, dataLength);
690}
691
692void rsdScriptSetGlobalBind(const Context *dc, const Script *script, uint32_t slot, Allocation *data) {
693    DrvScript *drv = (DrvScript *)script->mHal.drv;
694
695    //rsAssert(!script->mFieldIsObject[slot]);
696    //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
697
698    if (drv->mIntrinsicID) {
699        drv->mIntrinsicFuncs.bind(dc, script, drv->mIntrinsicData, slot, data);
700        return;
701    }
702
703    int32_t *destPtr = reinterpret_cast<int32_t *>(drv->mFieldAddress[slot]);
704    if (!destPtr) {
705        //ALOGV("Calling setVar on slot = %i which is null", slot);
706        return;
707    }
708
709    void *ptr = NULL;
710    drv->mBoundAllocs[slot] = data;
711    if(data) {
712        DrvAllocation *allocDrv = (DrvAllocation *)data->mHal.drv;
713        ptr = allocDrv->lod[0].mallocPtr;
714    }
715    memcpy(destPtr, &ptr, sizeof(void *));
716}
717
718void rsdScriptSetGlobalObj(const Context *dc, const Script *script, uint32_t slot, ObjectBase *data) {
719    DrvScript *drv = (DrvScript *)script->mHal.drv;
720    //rsAssert(script->mFieldIsObject[slot]);
721    //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
722
723    int32_t *destPtr = reinterpret_cast<int32_t *>(drv->mFieldAddress[slot]);
724    if (!destPtr) {
725        //ALOGV("Calling setVar on slot = %i which is null", slot);
726        return;
727    }
728
729    rsrSetObject(dc, script, (ObjectBase **)destPtr, data);
730}
731
732void rsdScriptDestroy(const Context *dc, Script *script) {
733    DrvScript *drv = (DrvScript *)script->mHal.drv;
734
735    if (drv == NULL) {
736        return;
737    }
738
739    for (size_t i = 0; i < script->mHal.info.exportedVariableCount; ++i) {
740        if (drv->mFieldIsObject[i]) {
741            if (drv->mFieldAddress[i] != NULL) {
742                ObjectBase **obj_addr =
743                    reinterpret_cast<ObjectBase **>(drv->mFieldAddress[i]);
744                rsrClearObject(dc, script, obj_addr);
745            }
746        }
747    }
748
749    delete[] drv->mInvokeFunctions;
750    delete[] drv->mForEachFunctions;
751    delete[] drv->mFieldAddress;
752    delete[] drv->mFieldIsObject;
753    delete[] drv->mForEachSignatures;
754    delete[] drv->mBoundAllocs;
755    if (drv->mScriptSO) {
756        dlclose(drv->mScriptSO);
757    }
758    free(drv);
759    script->mHal.drv = NULL;
760}
761
762Allocation * rsdScriptGetAllocationForPointer(const android::renderscript::Context *dc,
763                                              const android::renderscript::Script *sc,
764                                              const void *ptr) {
765    DrvScript *drv = (DrvScript *)sc->mHal.drv;
766    if (!ptr) {
767        return NULL;
768    }
769
770    for (uint32_t ct=0; ct < sc->mHal.info.exportedVariableCount; ct++) {
771        Allocation *a = drv->mBoundAllocs[ct];
772        if (!a) continue;
773        DrvAllocation *adrv = (DrvAllocation *)a->mHal.drv;
774        if (adrv->lod[0].mallocPtr == ptr) {
775            return a;
776        }
777    }
778    ALOGE("rsGetAllocation, failed to find %p", ptr);
779    return NULL;
780}
781
782