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