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