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