rsdBcc.cpp revision 8eaba4fee0c7b5325742c87187622fdff51d5eff
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    RsScriptIntrisicID 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};
52
53typedef void (*outer_foreach_t)(
54    const android::renderscript::RsForEachStubParamStruct *,
55    uint32_t x1, uint32_t x2,
56    uint32_t instep, uint32_t outstep);
57
58static Script * setTLS(Script *sc) {
59    ScriptTLSStruct * tls = (ScriptTLSStruct *)pthread_getspecific(rsdgThreadTLSKey);
60    rsAssert(tls);
61    Script *old = tls->mScript;
62    tls->mScript = sc;
63    return old;
64}
65
66
67bool rsdScriptInit(const Context *rsc,
68                     ScriptC *script,
69                     char const *resName,
70                     char const *cacheDir,
71                     uint8_t const *bitcode,
72                     size_t bitcodeSize,
73                     uint32_t flags) {
74    //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
75    //ALOGE("rsdScriptInit %p %p", rsc, script);
76
77    pthread_mutex_lock(&rsdgInitMutex);
78
79    const char* coreLib = "/system/lib/libclcore.bc";
80    bcc::RSInfo::FloatPrecision prec;
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, RsScriptIntrisicID 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
182    s->mHal.info.exportedVariableCount = 1;
183
184
185
186
187    pthread_mutex_unlock(&rsdgInitMutex);
188    return true;
189
190error:
191    pthread_mutex_unlock(&rsdgInitMutex);
192    return false;
193}
194
195typedef struct {
196    RsForEachStubParamStruct fep;
197
198    Context *rsc;
199    Script *script;
200    ForEachFunc_t kernel;
201    uint32_t sig;
202    const Allocation * ain;
203    Allocation * aout;
204
205    uint32_t mSliceSize;
206    volatile int mSliceNum;
207
208    uint32_t xStart;
209    uint32_t xEnd;
210    uint32_t yStart;
211    uint32_t yEnd;
212    uint32_t zStart;
213    uint32_t zEnd;
214    uint32_t arrayStart;
215    uint32_t arrayEnd;
216} MTLaunchStruct;
217typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
218
219static void wc_xy(void *usr, uint32_t idx) {
220    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
221    RsForEachStubParamStruct p;
222    memcpy(&p, &mtls->fep, sizeof(p));
223    RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
224    uint32_t sig = mtls->sig;
225
226    outer_foreach_t fn = (outer_foreach_t) mtls->kernel;
227    while (1) {
228        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
229        uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
230        uint32_t yEnd = yStart + mtls->mSliceSize;
231        yEnd = rsMin(yEnd, mtls->yEnd);
232        if (yEnd <= yStart) {
233            return;
234        }
235
236        //ALOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
237        //ALOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
238        for (p.y = yStart; p.y < yEnd; p.y++) {
239            p.out = mtls->fep.ptrOut + (mtls->fep.yStrideOut * p.y);
240            p.in = mtls->fep.ptrIn + (mtls->fep.yStrideIn * p.y);
241            fn(&p, mtls->xStart, mtls->xEnd, mtls->fep.eStrideIn, mtls->fep.eStrideOut);
242        }
243    }
244}
245
246static void wc_x(void *usr, uint32_t idx) {
247    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
248    RsForEachStubParamStruct p;
249    memcpy(&p, &mtls->fep, sizeof(p));
250    RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
251    uint32_t sig = mtls->sig;
252
253    outer_foreach_t fn = (outer_foreach_t) mtls->kernel;
254    while (1) {
255        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
256        uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
257        uint32_t xEnd = xStart + mtls->mSliceSize;
258        xEnd = rsMin(xEnd, mtls->xEnd);
259        if (xEnd <= xStart) {
260            return;
261        }
262
263        //ALOGE("usr slice %i idx %i, x %i,%i", slice, idx, xStart, xEnd);
264        //ALOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
265
266        p.out = mtls->fep.ptrOut + (mtls->fep.eStrideOut * xStart);
267        p.in = mtls->fep.ptrIn + (mtls->fep.eStrideIn * xStart);
268        fn(&p, xStart, xEnd, mtls->fep.eStrideIn, mtls->fep.eStrideOut);
269    }
270}
271
272void rsdScriptInvokeForEach(const Context *rsc,
273                            Script *s,
274                            uint32_t slot,
275                            const Allocation * ain,
276                            Allocation * aout,
277                            const void * usr,
278                            uint32_t usrLen,
279                            const RsScriptCall *sc) {
280
281    RsdHal * dc = (RsdHal *)rsc->mHal.drv;
282
283    MTLaunchStruct mtls;
284    memset(&mtls, 0, sizeof(mtls));
285
286    ALOGE("for each script %p  in %p   out %p", s, ain, aout);
287
288    DrvScript *drv = (DrvScript *)s->mHal.drv;
289
290    if (drv->mIntrinsicID) {
291        mtls.kernel = (void (*)())&rsdIntrinsic_Convolve3x3_uchar4;
292    } else {
293        rsAssert(slot < drv->mExecutable->getExportForeachFuncAddrs().size());
294        mtls.kernel = reinterpret_cast<ForEachFunc_t>(
295                          drv->mExecutable->getExportForeachFuncAddrs()[slot]);
296        rsAssert(mtls.kernel != NULL);
297        mtls.sig = drv->mExecutable->getInfo().getExportForeachFuncs()[slot].second;
298    }
299
300    if (ain) {
301        mtls.fep.dimX = ain->getType()->getDimX();
302        mtls.fep.dimY = ain->getType()->getDimY();
303        mtls.fep.dimZ = ain->getType()->getDimZ();
304        //mtls.dimArray = ain->getType()->getDimArray();
305    } else if (aout) {
306        mtls.fep.dimX = aout->getType()->getDimX();
307        mtls.fep.dimY = aout->getType()->getDimY();
308        mtls.fep.dimZ = aout->getType()->getDimZ();
309        //mtls.dimArray = aout->getType()->getDimArray();
310    } else {
311        rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
312        return;
313    }
314
315    if (!sc || (sc->xEnd == 0)) {
316        mtls.xEnd = mtls.fep.dimX;
317    } else {
318        rsAssert(sc->xStart < mtls.fep.dimX);
319        rsAssert(sc->xEnd <= mtls.fep.dimX);
320        rsAssert(sc->xStart < sc->xEnd);
321        mtls.xStart = rsMin(mtls.fep.dimX, sc->xStart);
322        mtls.xEnd = rsMin(mtls.fep.dimX, sc->xEnd);
323        if (mtls.xStart >= mtls.xEnd) return;
324    }
325
326    if (!sc || (sc->yEnd == 0)) {
327        mtls.yEnd = mtls.fep.dimY;
328    } else {
329        rsAssert(sc->yStart < mtls.fep.dimY);
330        rsAssert(sc->yEnd <= mtls.fep.dimY);
331        rsAssert(sc->yStart < sc->yEnd);
332        mtls.yStart = rsMin(mtls.fep.dimY, sc->yStart);
333        mtls.yEnd = rsMin(mtls.fep.dimY, sc->yEnd);
334        if (mtls.yStart >= mtls.yEnd) return;
335    }
336
337    mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd);
338    mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd);
339    mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
340    mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
341
342    rsAssert(!ain || (ain->getType()->getDimZ() == 0));
343
344    Context *mrsc = (Context *)rsc;
345    Script * oldTLS = setTLS(s);
346
347    mtls.rsc = mrsc;
348    mtls.ain = ain;
349    mtls.aout = aout;
350    mtls.script = s;
351    mtls.fep.usr = usr;
352    mtls.fep.usrLen = usrLen;
353    mtls.mSliceSize = 10;
354    mtls.mSliceNum = 0;
355
356    mtls.fep.ptrIn = NULL;
357    mtls.fep.eStrideIn = 0;
358    if (ain) {
359        DrvAllocation *aindrv = (DrvAllocation *)ain->mHal.drv;
360        mtls.fep.ptrIn = (const uint8_t *)aindrv->lod[0].mallocPtr;
361        mtls.fep.eStrideIn = ain->getType()->getElementSizeBytes();
362        mtls.fep.yStrideIn = aindrv->lod[0].stride;
363    }
364
365    mtls.fep.ptrOut = NULL;
366    mtls.fep.eStrideOut = 0;
367    if (aout) {
368        DrvAllocation *aoutdrv = (DrvAllocation *)aout->mHal.drv;
369        mtls.fep.ptrOut = (uint8_t *)aoutdrv->lod[0].mallocPtr;
370        mtls.fep.eStrideOut = aout->getType()->getElementSizeBytes();
371        mtls.fep.yStrideOut = aoutdrv->lod[0].stride;
372    }
373
374
375    if ((dc->mWorkers.mCount > 1) && s->mHal.info.isThreadable && !dc->mInForEach) {
376        dc->mInForEach = true;
377        if (mtls.fep.dimY > 1) {
378            mtls.mSliceSize = mtls.fep.dimY / (dc->mWorkers.mCount * 4);
379            if(mtls.mSliceSize < 1) {
380                mtls.mSliceSize = 1;
381            }
382
383            rsdLaunchThreads(mrsc, wc_xy, &mtls);
384        } else {
385            mtls.mSliceSize = mtls.fep.dimX / (dc->mWorkers.mCount * 4);
386            if(mtls.mSliceSize < 1) {
387                mtls.mSliceSize = 1;
388            }
389
390            rsdLaunchThreads(mrsc, wc_x, &mtls);
391        }
392        dc->mInForEach = false;
393
394        //ALOGE("launch 1");
395    } else {
396        RsForEachStubParamStruct p;
397        memcpy(&p, &mtls.fep, sizeof(p));
398        uint32_t sig = mtls.sig;
399
400        //ALOGE("launch 3");
401        outer_foreach_t fn = (outer_foreach_t) mtls.kernel;
402        for (p.ar[0] = mtls.arrayStart; p.ar[0] < mtls.arrayEnd; p.ar[0]++) {
403            for (p.z = mtls.zStart; p.z < mtls.zEnd; p.z++) {
404                for (p.y = mtls.yStart; p.y < mtls.yEnd; p.y++) {
405                    uint32_t offset = mtls.fep.dimY * mtls.fep.dimZ * p.ar[0] +
406                                      mtls.fep.dimY * p.z + p.y;
407                    p.out = mtls.fep.ptrOut + (mtls.fep.yStrideOut * offset);
408                    p.in = mtls.fep.ptrIn + (mtls.fep.yStrideIn * offset);
409                    fn(&p, mtls.xStart, mtls.xEnd, mtls.fep.eStrideIn, mtls.fep.eStrideOut);
410                }
411            }
412        }
413    }
414
415    setTLS(oldTLS);
416}
417
418
419int rsdScriptInvokeRoot(const Context *dc, Script *script) {
420    DrvScript *drv = (DrvScript *)script->mHal.drv;
421
422    Script * oldTLS = setTLS(script);
423    int ret = drv->mRoot();
424    setTLS(oldTLS);
425
426    return ret;
427}
428
429void rsdScriptInvokeInit(const Context *dc, Script *script) {
430    DrvScript *drv = (DrvScript *)script->mHal.drv;
431
432    if (drv->mInit) {
433        drv->mInit();
434    }
435}
436
437void rsdScriptInvokeFreeChildren(const Context *dc, Script *script) {
438    DrvScript *drv = (DrvScript *)script->mHal.drv;
439
440    if (drv->mFreeChildren) {
441        drv->mFreeChildren();
442    }
443}
444
445void rsdScriptInvokeFunction(const Context *dc, Script *script,
446                            uint32_t slot,
447                            const void *params,
448                            size_t paramLength) {
449    DrvScript *drv = (DrvScript *)script->mHal.drv;
450    //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
451
452    Script * oldTLS = setTLS(script);
453    reinterpret_cast<void (*)(const void *, uint32_t)>(
454        drv->mExecutable->getExportFuncAddrs()[slot])(params, paramLength);
455    setTLS(oldTLS);
456}
457
458void rsdScriptSetGlobalVar(const Context *dc, const Script *script,
459                           uint32_t slot, void *data, size_t dataLength) {
460    DrvScript *drv = (DrvScript *)script->mHal.drv;
461    //rsAssert(!script->mFieldIsObject[slot]);
462    //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
463
464    if (drv->mIntrinsicID) {
465        rsdIntrinsic_Convolve3x3_SetVar(dc, script, slot, data, dataLength);
466        return;
467    }
468
469    int32_t *destPtr = reinterpret_cast<int32_t *>(
470                          drv->mExecutable->getExportVarAddrs()[slot]);
471    if (!destPtr) {
472        //ALOGV("Calling setVar on slot = %i which is null", slot);
473        return;
474    }
475
476    memcpy(destPtr, data, dataLength);
477}
478
479void rsdScriptSetGlobalVarWithElemDims(
480        const android::renderscript::Context *dc,
481        const android::renderscript::Script *script,
482        uint32_t slot, void *data, size_t dataLength,
483        const android::renderscript::Element *elem,
484        const size_t *dims, size_t dimLength) {
485    DrvScript *drv = (DrvScript *)script->mHal.drv;
486
487    int32_t *destPtr = reinterpret_cast<int32_t *>(
488        drv->mExecutable->getExportVarAddrs()[slot]);
489    if (!destPtr) {
490        //ALOGV("Calling setVar on slot = %i which is null", slot);
491        return;
492    }
493
494    // We want to look at dimension in terms of integer components,
495    // but dimLength is given in terms of bytes.
496    dimLength /= sizeof(int);
497
498    // Only a single dimension is currently supported.
499    rsAssert(dimLength == 1);
500    if (dimLength == 1) {
501        // First do the increment loop.
502        size_t stride = elem->getSizeBytes();
503        char *cVal = reinterpret_cast<char *>(data);
504        for (size_t i = 0; i < dims[0]; i++) {
505            elem->incRefs(cVal);
506            cVal += stride;
507        }
508
509        // Decrement loop comes after (to prevent race conditions).
510        char *oldVal = reinterpret_cast<char *>(destPtr);
511        for (size_t i = 0; i < dims[0]; i++) {
512            elem->decRefs(oldVal);
513            oldVal += stride;
514        }
515    }
516
517    memcpy(destPtr, data, dataLength);
518}
519
520void rsdScriptSetGlobalBind(const Context *dc, const Script *script, uint32_t slot, Allocation *data) {
521    DrvScript *drv = (DrvScript *)script->mHal.drv;
522
523    //rsAssert(!script->mFieldIsObject[slot]);
524    //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
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