rsdBcc.cpp revision 49202fbfe57d2cc92b183baa8cbce3141e9a9ead
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 <bcc/BCCContext.h>
24#include <bcc/Renderscript/RSCompilerDriver.h>
25#include <bcc/Renderscript/RSExecutable.h>
26#include <bcc/Renderscript/RSInfo.h>
27
28#include "rsContext.h"
29#include "rsElement.h"
30#include "rsScriptC.h"
31
32#include "utils/Vector.h"
33#include "utils/Timers.h"
34#include "utils/StopWatch.h"
35
36using namespace android;
37using namespace android::renderscript;
38
39struct DrvScript {
40    RsScriptIntrinsicID mIntrinsicID;
41    int (*mRoot)();
42    int (*mRootExpand)();
43    void (*mInit)();
44    void (*mFreeChildren)();
45
46    bcc::BCCContext *mCompilerContext;
47    bcc::RSCompilerDriver *mCompilerDriver;
48    bcc::RSExecutable *mExecutable;
49
50    Allocation **mBoundAllocs;
51    RsdIntriniscFuncs_t mIntrinsicFuncs;
52    void * mIntrinsicData;
53};
54
55typedef void (*outer_foreach_t)(
56    const android::renderscript::RsForEachStubParamStruct *,
57    uint32_t x1, uint32_t x2,
58    uint32_t instep, uint32_t outstep);
59
60static Script * setTLS(Script *sc) {
61    ScriptTLSStruct * tls = (ScriptTLSStruct *)pthread_getspecific(rsdgThreadTLSKey);
62    rsAssert(tls);
63    Script *old = tls->mScript;
64    tls->mScript = sc;
65    return old;
66}
67
68
69bool rsdScriptInit(const Context *rsc,
70                     ScriptC *script,
71                     char const *resName,
72                     char const *cacheDir,
73                     uint8_t const *bitcode,
74                     size_t bitcodeSize,
75                     uint32_t flags) {
76    //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
77    //ALOGE("rsdScriptInit %p %p", rsc, script);
78
79    pthread_mutex_lock(&rsdgInitMutex);
80
81    bcc::RSExecutable *exec;
82    const bcc::RSInfo *info;
83    DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript));
84    if (drv == NULL) {
85        goto error;
86    }
87    script->mHal.drv = drv;
88
89    drv->mCompilerContext = NULL;
90    drv->mCompilerDriver = NULL;
91    drv->mExecutable = NULL;
92
93    drv->mCompilerContext = new bcc::BCCContext();
94    if (drv->mCompilerContext == NULL) {
95        ALOGE("bcc: FAILS to create compiler context (out of memory)");
96        goto error;
97    }
98
99    drv->mCompilerDriver = new bcc::RSCompilerDriver();
100    if (drv->mCompilerDriver == NULL) {
101        ALOGE("bcc: FAILS to create compiler driver (out of memory)");
102        goto error;
103    }
104
105    script->mHal.info.isThreadable = true;
106
107    drv->mCompilerDriver->setRSRuntimeLookupFunction(rsdLookupRuntimeStub);
108    drv->mCompilerDriver->setRSRuntimeLookupContext(script);
109
110    exec = drv->mCompilerDriver->build(*drv->mCompilerContext,
111                                       cacheDir, resName,
112                                       (const char *)bitcode, bitcodeSize);
113
114    if (exec == NULL) {
115        ALOGE("bcc: FAILS to prepare executable for '%s'", resName);
116        goto error;
117    }
118
119    drv->mExecutable = exec;
120
121    exec->setThreadable(script->mHal.info.isThreadable);
122    if (!exec->syncInfo()) {
123        ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
124    }
125
126    drv->mRoot = reinterpret_cast<int (*)()>(exec->getSymbolAddress("root"));
127    drv->mRootExpand =
128        reinterpret_cast<int (*)()>(exec->getSymbolAddress("root.expand"));
129    drv->mInit = reinterpret_cast<void (*)()>(exec->getSymbolAddress("init"));
130    drv->mFreeChildren =
131        reinterpret_cast<void (*)()>(exec->getSymbolAddress(".rs.dtor"));
132
133    info = &drv->mExecutable->getInfo();
134    // Copy info over to runtime
135    script->mHal.info.exportedFunctionCount = info->getExportFuncNames().size();
136    script->mHal.info.exportedVariableCount = info->getExportVarNames().size();
137    script->mHal.info.exportedPragmaCount = info->getPragmas().size();
138    script->mHal.info.exportedPragmaKeyList =
139        const_cast<const char**>(exec->getPragmaKeys().array());
140    script->mHal.info.exportedPragmaValueList =
141        const_cast<const char**>(exec->getPragmaValues().array());
142
143    if (drv->mRootExpand) {
144        script->mHal.info.root = drv->mRootExpand;
145    } else {
146        script->mHal.info.root = drv->mRoot;
147    }
148
149    if (script->mHal.info.exportedVariableCount) {
150        drv->mBoundAllocs = new Allocation *[script->mHal.info.exportedVariableCount];
151        memset(drv->mBoundAllocs, 0, sizeof(void *) * script->mHal.info.exportedVariableCount);
152    }
153
154    pthread_mutex_unlock(&rsdgInitMutex);
155    return true;
156
157error:
158
159    pthread_mutex_unlock(&rsdgInitMutex);
160    if (drv) {
161        delete drv->mCompilerContext;
162        delete drv->mCompilerDriver;
163        delete drv->mExecutable;
164        delete[] drv->mBoundAllocs;
165        free(drv);
166    }
167    script->mHal.drv = NULL;
168    return false;
169
170}
171
172bool rsdInitIntrinsic(const Context *rsc, Script *s, RsScriptIntrinsicID iid, Element *e) {
173    pthread_mutex_lock(&rsdgInitMutex);
174
175    DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript));
176    if (drv == NULL) {
177        goto error;
178    }
179    s->mHal.drv = drv;
180    drv->mIntrinsicID = iid;
181    rsdIntrinsic_Init(rsc, s, iid, &drv->mIntrinsicFuncs);
182
183    pthread_mutex_unlock(&rsdgInitMutex);
184    return true;
185
186error:
187    pthread_mutex_unlock(&rsdgInitMutex);
188    return false;
189}
190
191typedef struct {
192    RsForEachStubParamStruct fep;
193
194    Context *rsc;
195    Script *script;
196    ForEachFunc_t kernel;
197    uint32_t sig;
198    const Allocation * ain;
199    Allocation * aout;
200
201    uint32_t mSliceSize;
202    volatile int mSliceNum;
203
204    uint32_t xStart;
205    uint32_t xEnd;
206    uint32_t yStart;
207    uint32_t yEnd;
208    uint32_t zStart;
209    uint32_t zEnd;
210    uint32_t arrayStart;
211    uint32_t arrayEnd;
212} MTLaunchStruct;
213typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
214
215static void wc_xy(void *usr, uint32_t idx) {
216    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
217    RsForEachStubParamStruct p;
218    memcpy(&p, &mtls->fep, sizeof(p));
219    RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
220    uint32_t sig = mtls->sig;
221
222    outer_foreach_t fn = (outer_foreach_t) mtls->kernel;
223    while (1) {
224        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
225        uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
226        uint32_t yEnd = yStart + mtls->mSliceSize;
227        yEnd = rsMin(yEnd, mtls->yEnd);
228        if (yEnd <= yStart) {
229            return;
230        }
231
232        //ALOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
233        //ALOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
234        for (p.y = yStart; p.y < yEnd; p.y++) {
235            p.out = mtls->fep.ptrOut + (mtls->fep.yStrideOut * p.y);
236            p.in = mtls->fep.ptrIn + (mtls->fep.yStrideIn * p.y);
237            fn(&p, mtls->xStart, mtls->xEnd, mtls->fep.eStrideIn, mtls->fep.eStrideOut);
238        }
239    }
240}
241
242static void wc_x(void *usr, uint32_t idx) {
243    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
244    RsForEachStubParamStruct p;
245    memcpy(&p, &mtls->fep, sizeof(p));
246    RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
247    uint32_t sig = mtls->sig;
248
249    outer_foreach_t fn = (outer_foreach_t) mtls->kernel;
250    while (1) {
251        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
252        uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
253        uint32_t xEnd = xStart + mtls->mSliceSize;
254        xEnd = rsMin(xEnd, mtls->xEnd);
255        if (xEnd <= xStart) {
256            return;
257        }
258
259        //ALOGE("usr slice %i idx %i, x %i,%i", slice, idx, xStart, xEnd);
260        //ALOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
261
262        p.out = mtls->fep.ptrOut + (mtls->fep.eStrideOut * xStart);
263        p.in = mtls->fep.ptrIn + (mtls->fep.eStrideIn * xStart);
264        fn(&p, xStart, xEnd, mtls->fep.eStrideIn, mtls->fep.eStrideOut);
265    }
266}
267
268void rsdScriptInvokeForEach(const Context *rsc,
269                            Script *s,
270                            uint32_t slot,
271                            const Allocation * ain,
272                            Allocation * aout,
273                            const void * usr,
274                            uint32_t usrLen,
275                            const RsScriptCall *sc) {
276
277    RsdHal * dc = (RsdHal *)rsc->mHal.drv;
278
279    MTLaunchStruct mtls;
280    memset(&mtls, 0, sizeof(mtls));
281
282    //ALOGE("for each script %p  in %p   out %p", s, ain, aout);
283
284    DrvScript *drv = (DrvScript *)s->mHal.drv;
285
286    if (drv->mIntrinsicID) {
287        mtls.kernel = (void (*)())drv->mIntrinsicFuncs.root;
288        usr = drv->mIntrinsicData;
289    } else {
290        rsAssert(slot < drv->mExecutable->getExportForeachFuncAddrs().size());
291        mtls.kernel = reinterpret_cast<ForEachFunc_t>(
292                          drv->mExecutable->getExportForeachFuncAddrs()[slot]);
293        rsAssert(mtls.kernel != NULL);
294        mtls.sig = drv->mExecutable->getInfo().getExportForeachFuncs()[slot].second;
295    }
296
297    if (ain) {
298        mtls.fep.dimX = ain->getType()->getDimX();
299        mtls.fep.dimY = ain->getType()->getDimY();
300        mtls.fep.dimZ = ain->getType()->getDimZ();
301        //mtls.dimArray = ain->getType()->getDimArray();
302    } else if (aout) {
303        mtls.fep.dimX = aout->getType()->getDimX();
304        mtls.fep.dimY = aout->getType()->getDimY();
305        mtls.fep.dimZ = aout->getType()->getDimZ();
306        //mtls.dimArray = aout->getType()->getDimArray();
307    } else {
308        rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
309        return;
310    }
311
312    if (!sc || (sc->xEnd == 0)) {
313        mtls.xEnd = mtls.fep.dimX;
314    } else {
315        rsAssert(sc->xStart < mtls.fep.dimX);
316        rsAssert(sc->xEnd <= mtls.fep.dimX);
317        rsAssert(sc->xStart < sc->xEnd);
318        mtls.xStart = rsMin(mtls.fep.dimX, sc->xStart);
319        mtls.xEnd = rsMin(mtls.fep.dimX, sc->xEnd);
320        if (mtls.xStart >= mtls.xEnd) return;
321    }
322
323    if (!sc || (sc->yEnd == 0)) {
324        mtls.yEnd = mtls.fep.dimY;
325    } else {
326        rsAssert(sc->yStart < mtls.fep.dimY);
327        rsAssert(sc->yEnd <= mtls.fep.dimY);
328        rsAssert(sc->yStart < sc->yEnd);
329        mtls.yStart = rsMin(mtls.fep.dimY, sc->yStart);
330        mtls.yEnd = rsMin(mtls.fep.dimY, sc->yEnd);
331        if (mtls.yStart >= mtls.yEnd) return;
332    }
333
334    mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd);
335    mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd);
336    mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
337    mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
338
339    rsAssert(!ain || (ain->getType()->getDimZ() == 0));
340
341    Context *mrsc = (Context *)rsc;
342    Script * oldTLS = setTLS(s);
343
344    mtls.rsc = mrsc;
345    mtls.ain = ain;
346    mtls.aout = aout;
347    mtls.script = s;
348    mtls.fep.usr = usr;
349    mtls.fep.usrLen = usrLen;
350    mtls.mSliceSize = 10;
351    mtls.mSliceNum = 0;
352
353    mtls.fep.ptrIn = NULL;
354    mtls.fep.eStrideIn = 0;
355    if (ain) {
356        DrvAllocation *aindrv = (DrvAllocation *)ain->mHal.drv;
357        mtls.fep.ptrIn = (const uint8_t *)aindrv->lod[0].mallocPtr;
358        mtls.fep.eStrideIn = ain->getType()->getElementSizeBytes();
359        mtls.fep.yStrideIn = aindrv->lod[0].stride;
360    }
361
362    mtls.fep.ptrOut = NULL;
363    mtls.fep.eStrideOut = 0;
364    if (aout) {
365        DrvAllocation *aoutdrv = (DrvAllocation *)aout->mHal.drv;
366        mtls.fep.ptrOut = (uint8_t *)aoutdrv->lod[0].mallocPtr;
367        mtls.fep.eStrideOut = aout->getType()->getElementSizeBytes();
368        mtls.fep.yStrideOut = aoutdrv->lod[0].stride;
369    }
370
371
372    if ((dc->mWorkers.mCount > 1) && s->mHal.info.isThreadable && !dc->mInForEach) {
373        dc->mInForEach = true;
374        if (mtls.fep.dimY > 1) {
375            mtls.mSliceSize = mtls.fep.dimY / (dc->mWorkers.mCount * 4);
376            if(mtls.mSliceSize < 1) {
377                mtls.mSliceSize = 1;
378            }
379
380            rsdLaunchThreads(mrsc, wc_xy, &mtls);
381        } else {
382            mtls.mSliceSize = mtls.fep.dimX / (dc->mWorkers.mCount * 4);
383            if(mtls.mSliceSize < 1) {
384                mtls.mSliceSize = 1;
385            }
386
387            rsdLaunchThreads(mrsc, wc_x, &mtls);
388        }
389        dc->mInForEach = false;
390
391        //ALOGE("launch 1");
392    } else {
393        RsForEachStubParamStruct p;
394        memcpy(&p, &mtls.fep, sizeof(p));
395        uint32_t sig = mtls.sig;
396
397        //ALOGE("launch 3");
398        outer_foreach_t fn = (outer_foreach_t) mtls.kernel;
399        for (p.ar[0] = mtls.arrayStart; p.ar[0] < mtls.arrayEnd; p.ar[0]++) {
400            for (p.z = mtls.zStart; p.z < mtls.zEnd; p.z++) {
401                for (p.y = mtls.yStart; p.y < mtls.yEnd; p.y++) {
402                    uint32_t offset = mtls.fep.dimY * mtls.fep.dimZ * p.ar[0] +
403                                      mtls.fep.dimY * p.z + p.y;
404                    p.out = mtls.fep.ptrOut + (mtls.fep.yStrideOut * offset);
405                    p.in = mtls.fep.ptrIn + (mtls.fep.yStrideIn * offset);
406                    fn(&p, mtls.xStart, mtls.xEnd, mtls.fep.eStrideIn, mtls.fep.eStrideOut);
407                }
408            }
409        }
410    }
411
412    setTLS(oldTLS);
413}
414
415
416int rsdScriptInvokeRoot(const Context *dc, Script *script) {
417    DrvScript *drv = (DrvScript *)script->mHal.drv;
418
419    Script * oldTLS = setTLS(script);
420    int ret = drv->mRoot();
421    setTLS(oldTLS);
422
423    return ret;
424}
425
426void rsdScriptInvokeInit(const Context *dc, Script *script) {
427    DrvScript *drv = (DrvScript *)script->mHal.drv;
428
429    if (drv->mInit) {
430        drv->mInit();
431    }
432}
433
434void rsdScriptInvokeFreeChildren(const Context *dc, Script *script) {
435    DrvScript *drv = (DrvScript *)script->mHal.drv;
436
437    if (drv->mFreeChildren) {
438        drv->mFreeChildren();
439    }
440}
441
442void rsdScriptInvokeFunction(const Context *dc, Script *script,
443                            uint32_t slot,
444                            const void *params,
445                            size_t paramLength) {
446    DrvScript *drv = (DrvScript *)script->mHal.drv;
447    //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
448
449    Script * oldTLS = setTLS(script);
450    reinterpret_cast<void (*)(const void *, uint32_t)>(
451        drv->mExecutable->getExportFuncAddrs()[slot])(params, paramLength);
452    setTLS(oldTLS);
453}
454
455void rsdScriptSetGlobalVar(const Context *dc, const Script *script,
456                           uint32_t slot, void *data, size_t dataLength) {
457    DrvScript *drv = (DrvScript *)script->mHal.drv;
458    //rsAssert(!script->mFieldIsObject[slot]);
459    //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
460
461    if (drv->mIntrinsicID) {
462        drv->mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
463        return;
464    }
465
466    int32_t *destPtr = reinterpret_cast<int32_t *>(
467                          drv->mExecutable->getExportVarAddrs()[slot]);
468    if (!destPtr) {
469        //ALOGV("Calling setVar on slot = %i which is null", slot);
470        return;
471    }
472
473    memcpy(destPtr, data, dataLength);
474}
475
476void rsdScriptSetGlobalVarWithElemDims(
477        const android::renderscript::Context *dc,
478        const android::renderscript::Script *script,
479        uint32_t slot, void *data, size_t dataLength,
480        const android::renderscript::Element *elem,
481        const size_t *dims, size_t dimLength) {
482    DrvScript *drv = (DrvScript *)script->mHal.drv;
483
484    int32_t *destPtr = reinterpret_cast<int32_t *>(
485        drv->mExecutable->getExportVarAddrs()[slot]);
486    if (!destPtr) {
487        //ALOGV("Calling setVar on slot = %i which is null", slot);
488        return;
489    }
490
491    // We want to look at dimension in terms of integer components,
492    // but dimLength is given in terms of bytes.
493    dimLength /= sizeof(int);
494
495    // Only a single dimension is currently supported.
496    rsAssert(dimLength == 1);
497    if (dimLength == 1) {
498        // First do the increment loop.
499        size_t stride = elem->getSizeBytes();
500        char *cVal = reinterpret_cast<char *>(data);
501        for (size_t i = 0; i < dims[0]; i++) {
502            elem->incRefs(cVal);
503            cVal += stride;
504        }
505
506        // Decrement loop comes after (to prevent race conditions).
507        char *oldVal = reinterpret_cast<char *>(destPtr);
508        for (size_t i = 0; i < dims[0]; i++) {
509            elem->decRefs(oldVal);
510            oldVal += stride;
511        }
512    }
513
514    memcpy(destPtr, data, dataLength);
515}
516
517void rsdScriptSetGlobalBind(const Context *dc, const Script *script, uint32_t slot, Allocation *data) {
518    DrvScript *drv = (DrvScript *)script->mHal.drv;
519
520    //rsAssert(!script->mFieldIsObject[slot]);
521    //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
522
523    if (drv->mIntrinsicID) {
524        drv->mIntrinsicFuncs.bind(dc, script, drv->mIntrinsicData, slot, data);
525        return;
526    }
527
528    int32_t *destPtr = reinterpret_cast<int32_t *>(
529                          drv->mExecutable->getExportVarAddrs()[slot]);
530    if (!destPtr) {
531        //ALOGV("Calling setVar on slot = %i which is null", slot);
532        return;
533    }
534
535    void *ptr = NULL;
536    drv->mBoundAllocs[slot] = data;
537    if(data) {
538        DrvAllocation *allocDrv = (DrvAllocation *)data->mHal.drv;
539        ptr = allocDrv->lod[0].mallocPtr;
540    }
541    memcpy(destPtr, &ptr, sizeof(void *));
542}
543
544void rsdScriptSetGlobalObj(const Context *dc, const Script *script, uint32_t slot, ObjectBase *data) {
545    DrvScript *drv = (DrvScript *)script->mHal.drv;
546    //rsAssert(script->mFieldIsObject[slot]);
547    //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
548
549    int32_t *destPtr = reinterpret_cast<int32_t *>(
550                          drv->mExecutable->getExportVarAddrs()[slot]);
551    if (!destPtr) {
552        //ALOGV("Calling setVar on slot = %i which is null", slot);
553        return;
554    }
555
556    rsrSetObject(dc, script, (ObjectBase **)destPtr, data);
557}
558
559void rsdScriptDestroy(const Context *dc, Script *script) {
560    DrvScript *drv = (DrvScript *)script->mHal.drv;
561
562    if (drv == NULL) {
563        return;
564    }
565
566    if (drv->mExecutable) {
567        Vector<void *>::const_iterator var_addr_iter =
568            drv->mExecutable->getExportVarAddrs().begin();
569        Vector<void *>::const_iterator var_addr_end =
570            drv->mExecutable->getExportVarAddrs().end();
571
572        bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter =
573            drv->mExecutable->getInfo().getObjectSlots().begin();
574        bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end =
575            drv->mExecutable->getInfo().getObjectSlots().end();
576
577        while ((var_addr_iter != var_addr_end) &&
578               (is_object_iter != is_object_end)) {
579            // The field address can be NULL if the script-side has optimized
580            // the corresponding global variable away.
581            ObjectBase **obj_addr =
582                reinterpret_cast<ObjectBase **>(*var_addr_iter);
583            if (*is_object_iter) {
584                if (*var_addr_iter != NULL) {
585                    rsrClearObject(dc, script, obj_addr);
586                }
587            }
588            var_addr_iter++;
589            is_object_iter++;
590        }
591    }
592
593    delete drv->mCompilerContext;
594    delete drv->mCompilerDriver;
595    delete drv->mExecutable;
596    delete[] drv->mBoundAllocs;
597    free(drv);
598    script->mHal.drv = NULL;
599}
600
601Allocation * rsdScriptGetAllocationForPointer(const android::renderscript::Context *dc,
602                                              const android::renderscript::Script *sc,
603                                              const void *ptr) {
604    DrvScript *drv = (DrvScript *)sc->mHal.drv;
605    if (!ptr) {
606        return NULL;
607    }
608
609    for (uint32_t ct=0; ct < sc->mHal.info.exportedVariableCount; ct++) {
610        Allocation *a = drv->mBoundAllocs[ct];
611        if (!a) continue;
612        DrvAllocation *adrv = (DrvAllocation *)a->mHal.drv;
613        if (adrv->lod[0].mallocPtr == ptr) {
614            return a;
615        }
616    }
617    ALOGE("rsGetAllocation, failed to find %p", ptr);
618    return NULL;
619}
620
621