rsdBcc.cpp revision 6d958bc9ac6efc404be2b502c5c579e00837bff1
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