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 "rsCpuCore.h" 18 #include "rsCpuScript.h" 19 20 #ifdef RS_COMPATIBILITY_LIB 21 #include <set> 22 #include <string> 23 #include <dlfcn.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 #else 29 #include <bcc/BCCContext.h> 30 #include <bcc/Renderscript/RSCompilerDriver.h> 31 #include <bcc/Renderscript/RSExecutable.h> 32 #include <bcc/Renderscript/RSInfo.h> 33 #include <bcinfo/MetadataExtractor.h> 34 #include <cutils/properties.h> 35 36 #include <sys/types.h> 37 #include <sys/wait.h> 38 #include <unistd.h> 39 #endif 40 41 namespace { 42 #ifdef RS_COMPATIBILITY_LIB 43 44 // Create a len length string containing random characters from [A-Za-z0-9]. 45 static std::string getRandomString(size_t len) { 46 char buf[len + 1]; 47 for (size_t i = 0; i < len; i++) { 48 uint32_t r = arc4random() & 0xffff; 49 r %= 62; 50 if (r < 26) { 51 // lowercase 52 buf[i] = 'a' + r; 53 } else if (r < 52) { 54 // uppercase 55 buf[i] = 'A' + (r - 26); 56 } else { 57 // Use a number 58 buf[i] = '0' + (r - 52); 59 } 60 } 61 buf[len] = '\0'; 62 return std::string(buf); 63 } 64 65 // Attempt to load the shared library from origName, but then fall back to 66 // creating the symlinked shared library if necessary (to ensure instancing). 67 // This function returns the dlopen()-ed handle if successful. 68 static void *loadSOHelper(const char *origName, const char *cacheDir, 69 const char *resName) { 70 // Keep track of which .so libraries have been loaded. Once a library is 71 // in the set (per-process granularity), we must instead make a symlink to 72 // the original shared object (randomly named .so file) and load that one 73 // instead. If we don't do this, we end up aliasing global data between 74 // the various Script instances (which are supposed to be completely 75 // independent). 76 static std::set<std::string> LoadedLibraries; 77 78 void *loaded = NULL; 79 80 // Skip everything if we don't even have the original library available. 81 if (access(origName, F_OK) != 0) { 82 return NULL; 83 } 84 85 // Common path is that we have not loaded this Script/library before. 86 if (LoadedLibraries.find(origName) == LoadedLibraries.end()) { 87 loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL); 88 if (loaded) { 89 LoadedLibraries.insert(origName); 90 } 91 return loaded; 92 } 93 94 // Construct an appropriately randomized filename for the symlink. 95 std::string newName(cacheDir); 96 newName.append("/com.android.renderscript.cache/librs."); 97 newName.append(resName); 98 newName.append("#"); 99 newName.append(getRandomString(6)); // 62^6 potential filename variants. 100 newName.append(".so"); 101 102 int r = symlink(origName, newName.c_str()); 103 if (r != 0) { 104 ALOGE("Could not create symlink %s -> %s", newName.c_str(), origName); 105 return NULL; 106 } 107 loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL); 108 r = unlink(newName.c_str()); 109 if (r != 0) { 110 ALOGE("Could not unlink symlink %s", newName.c_str()); 111 } 112 if (loaded) { 113 LoadedLibraries.insert(newName.c_str()); 114 } 115 116 return loaded; 117 } 118 119 // Load the shared library referred to by cacheDir and resName. If we have 120 // already loaded this library, we instead create a new symlink (in the 121 // cache dir) and then load that. We then immediately destroy the symlink. 122 // This is required behavior to implement script instancing for the support 123 // library, since shared objects are loaded and de-duped by name only. 124 static void *loadSharedLibrary(const char *cacheDir, const char *resName) { 125 void *loaded = NULL; 126 //arc4random_stir(); 127 #ifndef RS_SERVER 128 std::string scriptSOName(cacheDir); 129 size_t cutPos = scriptSOName.rfind("cache"); 130 if (cutPos != std::string::npos) { 131 scriptSOName.erase(cutPos); 132 } else { 133 ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir); 134 } 135 scriptSOName.append("/lib/librs."); 136 #else 137 std::string scriptSOName("lib"); 138 #endif 139 scriptSOName.append(resName); 140 scriptSOName.append(".so"); 141 142 // We should check if we can load the library from the standard app 143 // location for shared libraries first. 144 loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName); 145 146 if (loaded == NULL) { 147 ALOGE("Unable to open shared library (%s): %s", 148 scriptSOName.c_str(), dlerror()); 149 150 // One final attempt to find the library in "/system/lib". 151 // We do this to allow bundled applications to use the compatibility 152 // library fallback path. Those applications don't have a private 153 // library path, so they need to install to the system directly. 154 // Note that this is really just a testing path. 155 android::String8 scriptSONameSystem("/system/lib/librs."); 156 scriptSONameSystem.append(resName); 157 scriptSONameSystem.append(".so"); 158 loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir, 159 resName); 160 if (loaded == NULL) { 161 ALOGE("Unable to open system shared library (%s): %s", 162 scriptSONameSystem.c_str(), dlerror()); 163 } 164 } 165 166 return loaded; 167 } 168 169 170 #else 171 static bool is_force_recompile() { 172 #ifdef RS_SERVER 173 return false; 174 #else 175 char buf[PROPERTY_VALUE_MAX]; 176 177 // Re-compile if floating point precision has been overridden. 178 property_get("debug.rs.precision", buf, ""); 179 if (buf[0] != '\0') { 180 return true; 181 } 182 183 // Re-compile if debug.rs.forcerecompile is set. 184 property_get("debug.rs.forcerecompile", buf, "0"); 185 if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) { 186 return true; 187 } else { 188 return false; 189 } 190 #endif // RS_SERVER 191 } 192 193 //#define EXTERNAL_BCC_COMPILER 1 194 #ifdef EXTERNAL_BCC_COMPILER 195 const static char *BCC_EXE_PATH = "/system/bin/bcc"; 196 197 static bool compileBitcode(const char *cacheDir, 198 const char *resName, 199 const char *bitcode, 200 size_t bitcodeSize, 201 const char *core_lib) { 202 rsAssert(cacheDir && resName && bitcode && bitcodeSize && core_lib); 203 204 android::String8 bcFilename(cacheDir); 205 bcFilename.append("/"); 206 bcFilename.append(resName); 207 bcFilename.append(".bc"); 208 FILE *bcfile = fopen(bcFilename.string(), "w"); 209 if (!bcfile) { 210 ALOGE("Could not write to %s", bcFilename.string()); 211 return false; 212 } 213 size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile); 214 fclose(bcfile); 215 if (nwritten != bitcodeSize) { 216 ALOGE("Could not write %zu bytes to %s", bitcodeSize, 217 bcFilename.string()); 218 return false; 219 } 220 221 pid_t pid = fork(); 222 switch (pid) { 223 case -1: { // Error occurred (we attempt no recovery) 224 ALOGE("Couldn't fork for bcc compiler execution"); 225 return false; 226 } 227 case 0: { // Child process 228 // Execute the bcc compiler. 229 execl(BCC_EXE_PATH, 230 BCC_EXE_PATH, 231 "-o", resName, 232 "-output_path", cacheDir, 233 "-bclib", core_lib, 234 bcFilename.string(), 235 (char *) NULL); 236 ALOGE("execl() failed: %s", strerror(errno)); 237 abort(); 238 return false; 239 } 240 default: { // Parent process (actual driver) 241 // Wait on child process to finish compiling the source. 242 int status = 0; 243 pid_t w = waitpid(pid, &status, 0); 244 if (w == -1) { 245 ALOGE("Could not wait for bcc compiler"); 246 return false; 247 } 248 249 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 250 return true; 251 } 252 253 ALOGE("bcc compiler terminated unexpectedly"); 254 return false; 255 } 256 } 257 } 258 #endif // EXTERNAL_BCC_COMPILER 259 260 #endif // !defined(RS_COMPATIBILITY_LIB) 261 } // namespace 262 263 namespace android { 264 namespace renderscript { 265 266 267 #ifdef RS_COMPATIBILITY_LIB 268 #define MAXLINE 500 269 #define MAKE_STR_HELPER(S) #S 270 #define MAKE_STR(S) MAKE_STR_HELPER(S) 271 #define EXPORT_VAR_STR "exportVarCount: " 272 #define EXPORT_VAR_STR_LEN strlen(EXPORT_VAR_STR) 273 #define EXPORT_FUNC_STR "exportFuncCount: " 274 #define EXPORT_FUNC_STR_LEN strlen(EXPORT_FUNC_STR) 275 #define EXPORT_FOREACH_STR "exportForEachCount: " 276 #define EXPORT_FOREACH_STR_LEN strlen(EXPORT_FOREACH_STR) 277 #define OBJECT_SLOT_STR "objectSlotCount: " 278 #define OBJECT_SLOT_STR_LEN strlen(OBJECT_SLOT_STR) 279 280 // Copy up to a newline or size chars from str -> s, updating str 281 // Returns s when successful and NULL when '\0' is finally reached. 282 static char* strgets(char *s, int size, const char **ppstr) { 283 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) { 284 return NULL; 285 } 286 287 int i; 288 for (i = 0; i < (size - 1); i++) { 289 s[i] = **ppstr; 290 (*ppstr)++; 291 if (s[i] == '\0') { 292 return s; 293 } else if (s[i] == '\n') { 294 s[i+1] = '\0'; 295 return s; 296 } 297 } 298 299 // size has been exceeded. 300 s[i] = '\0'; 301 302 return s; 303 } 304 #endif 305 306 RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) { 307 mCtx = ctx; 308 mScript = s; 309 310 #ifdef RS_COMPATIBILITY_LIB 311 mScriptSO = NULL; 312 mInvokeFunctions = NULL; 313 mForEachFunctions = NULL; 314 mFieldAddress = NULL; 315 mFieldIsObject = NULL; 316 mForEachSignatures = NULL; 317 #else 318 mCompilerContext = NULL; 319 mCompilerDriver = NULL; 320 mExecutable = NULL; 321 #endif 322 323 mRoot = NULL; 324 mRootExpand = NULL; 325 mInit = NULL; 326 mFreeChildren = NULL; 327 328 329 mBoundAllocs = NULL; 330 mIntrinsicData = NULL; 331 mIsThreadable = true; 332 } 333 334 335 bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir, 336 uint8_t const *bitcode, size_t bitcodeSize, 337 uint32_t flags) { 338 //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc); 339 //ALOGE("rsdScriptInit %p %p", rsc, script); 340 341 mCtx->lockMutex(); 342 343 #ifndef RS_COMPATIBILITY_LIB 344 bcc::RSExecutable *exec = NULL; 345 346 mCompilerContext = NULL; 347 mCompilerDriver = NULL; 348 mExecutable = NULL; 349 350 mCompilerContext = new bcc::BCCContext(); 351 if (mCompilerContext == NULL) { 352 ALOGE("bcc: FAILS to create compiler context (out of memory)"); 353 mCtx->unlockMutex(); 354 return false; 355 } 356 357 mCompilerDriver = new bcc::RSCompilerDriver(); 358 if (mCompilerDriver == NULL) { 359 ALOGE("bcc: FAILS to create compiler driver (out of memory)"); 360 mCtx->unlockMutex(); 361 return false; 362 } 363 364 mCompilerDriver->setRSRuntimeLookupFunction(lookupRuntimeStub); 365 mCompilerDriver->setRSRuntimeLookupContext(this); 366 367 // Run any compiler setup functions we have been provided with. 368 RSSetupCompilerCallback setupCompilerCallback = 369 mCtx->getSetupCompilerCallback(); 370 if (setupCompilerCallback != NULL) { 371 setupCompilerCallback(mCompilerDriver); 372 } 373 374 const char *core_lib = bcc::RSInfo::LibCLCorePath; 375 376 bcinfo::MetadataExtractor ME((const char *) bitcode, bitcodeSize); 377 if (!ME.extract()) { 378 ALOGE("Could not extract metadata from bitcode"); 379 return false; 380 } 381 382 enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision(); 383 switch (prec) { 384 case bcinfo::RS_FP_Imprecise: 385 case bcinfo::RS_FP_Relaxed: 386 #if defined(ARCH_ARM_HAVE_NEON) 387 // NEON-capable devices can use an accelerated math library for all 388 // reduced precision scripts. 389 core_lib = bcc::RSInfo::LibCLCoreNEONPath; 390 #endif 391 break; 392 case bcinfo::RS_FP_Full: 393 break; 394 default: 395 ALOGE("Unknown precision for bitcode"); 396 return false; 397 } 398 399 #if defined(ARCH_X86_HAVE_SSE2) 400 // SSE2- or above capable devices will use an optimized library. 401 core_lib = bcc::RSInfo::LibCLCoreX86Path; 402 #endif 403 404 RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback(); 405 if (selectRTCallback != NULL) { 406 core_lib = selectRTCallback((const char *)bitcode, bitcodeSize); 407 } 408 409 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) { 410 // Use the libclcore_debug.bc instead of the default library. 411 core_lib = bcc::RSInfo::LibCLCoreDebugPath; 412 mCompilerDriver->setDebugContext(true); 413 // Skip the cache lookup 414 } else if (!is_force_recompile()) { 415 // Attempt to just load the script from cache first if we can. 416 exec = mCompilerDriver->loadScript(cacheDir, resName, 417 (const char *)bitcode, bitcodeSize); 418 } 419 420 if (exec == NULL) { 421 #ifdef EXTERNAL_BCC_COMPILER 422 bool built = compileBitcode(cacheDir, resName, (const char *)bitcode, 423 bitcodeSize, core_lib); 424 #else 425 bool built = mCompilerDriver->build(*mCompilerContext, cacheDir, 426 resName, (const char *)bitcode, 427 bitcodeSize, core_lib, 428 mCtx->getLinkRuntimeCallback()); 429 #endif // EXTERNAL_BCC_COMPILER 430 if (built) { 431 exec = mCompilerDriver->loadScript(cacheDir, resName, 432 (const char *)bitcode, 433 bitcodeSize); 434 } 435 } 436 437 if (exec == NULL) { 438 ALOGE("bcc: FAILS to prepare executable for '%s'", resName); 439 mCtx->unlockMutex(); 440 return false; 441 } 442 443 mExecutable = exec; 444 445 exec->setThreadable(mIsThreadable); 446 if (!exec->syncInfo()) { 447 ALOGW("bcc: FAILS to synchronize the RS info file to the disk"); 448 } 449 450 mRoot = reinterpret_cast<int (*)()>(exec->getSymbolAddress("root")); 451 mRootExpand = 452 reinterpret_cast<int (*)()>(exec->getSymbolAddress("root.expand")); 453 mInit = reinterpret_cast<void (*)()>(exec->getSymbolAddress("init")); 454 mFreeChildren = 455 reinterpret_cast<void (*)()>(exec->getSymbolAddress(".rs.dtor")); 456 457 458 const bcc::RSInfo *info = &mExecutable->getInfo(); 459 if (info->getExportVarNames().size()) { 460 mBoundAllocs = new Allocation *[info->getExportVarNames().size()]; 461 memset(mBoundAllocs, 0, sizeof(void *) * info->getExportVarNames().size()); 462 } 463 464 #else 465 466 mScriptSO = loadSharedLibrary(cacheDir, resName); 467 468 if (mScriptSO) { 469 char line[MAXLINE]; 470 mRoot = (RootFunc_t) dlsym(mScriptSO, "root"); 471 if (mRoot) { 472 //ALOGE("Found root(): %p", mRoot); 473 } 474 mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand"); 475 if (mRootExpand) { 476 //ALOGE("Found root.expand(): %p", mRootExpand); 477 } 478 mInit = (InvokeFunc_t) dlsym(mScriptSO, "init"); 479 if (mInit) { 480 //ALOGE("Found init(): %p", mInit); 481 } 482 mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor"); 483 if (mFreeChildren) { 484 //ALOGE("Found .rs.dtor(): %p", mFreeChildren); 485 } 486 487 const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info"); 488 if (rsInfo) { 489 //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo); 490 } 491 492 size_t varCount = 0; 493 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 494 goto error; 495 } 496 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) { 497 ALOGE("Invalid export var count!: %s", line); 498 goto error; 499 } 500 501 mExportedVariableCount = varCount; 502 //ALOGE("varCount: %zu", varCount); 503 if (varCount > 0) { 504 // Start by creating/zeroing this member, since we don't want to 505 // accidentally clean up invalid pointers later (if we error out). 506 mFieldIsObject = new bool[varCount]; 507 if (mFieldIsObject == NULL) { 508 goto error; 509 } 510 memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject)); 511 mFieldAddress = new void*[varCount]; 512 if (mFieldAddress == NULL) { 513 goto error; 514 } 515 for (size_t i = 0; i < varCount; ++i) { 516 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 517 goto error; 518 } 519 char *c = strrchr(line, '\n'); 520 if (c) { 521 *c = '\0'; 522 } 523 mFieldAddress[i] = dlsym(mScriptSO, line); 524 if (mFieldAddress[i] == NULL) { 525 ALOGE("Failed to find variable address for %s: %s", 526 line, dlerror()); 527 // Not a critical error if we don't find a global variable. 528 } 529 else { 530 //ALOGE("Found variable %s at %p", line, 531 //mFieldAddress[i]); 532 } 533 } 534 } 535 536 size_t funcCount = 0; 537 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 538 goto error; 539 } 540 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) { 541 ALOGE("Invalid export func count!: %s", line); 542 goto error; 543 } 544 545 mExportedFunctionCount = funcCount; 546 //ALOGE("funcCount: %zu", funcCount); 547 548 if (funcCount > 0) { 549 mInvokeFunctions = new InvokeFunc_t[funcCount]; 550 if (mInvokeFunctions == NULL) { 551 goto error; 552 } 553 for (size_t i = 0; i < funcCount; ++i) { 554 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 555 goto error; 556 } 557 char *c = strrchr(line, '\n'); 558 if (c) { 559 *c = '\0'; 560 } 561 562 mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line); 563 if (mInvokeFunctions[i] == NULL) { 564 ALOGE("Failed to get function address for %s(): %s", 565 line, dlerror()); 566 goto error; 567 } 568 else { 569 //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]); 570 } 571 } 572 } 573 574 size_t forEachCount = 0; 575 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 576 goto error; 577 } 578 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) { 579 ALOGE("Invalid export forEach count!: %s", line); 580 goto error; 581 } 582 583 if (forEachCount > 0) { 584 585 mForEachSignatures = new uint32_t[forEachCount]; 586 if (mForEachSignatures == NULL) { 587 goto error; 588 } 589 mForEachFunctions = new ForEachFunc_t[forEachCount]; 590 if (mForEachFunctions == NULL) { 591 goto error; 592 } 593 for (size_t i = 0; i < forEachCount; ++i) { 594 unsigned int tmpSig = 0; 595 char tmpName[MAXLINE]; 596 597 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 598 goto error; 599 } 600 if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s", 601 &tmpSig, tmpName) != 2) { 602 ALOGE("Invalid export forEach!: %s", line); 603 goto error; 604 } 605 606 // Lookup the expanded ForEach kernel. 607 strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName)); 608 mForEachSignatures[i] = tmpSig; 609 mForEachFunctions[i] = 610 (ForEachFunc_t) dlsym(mScriptSO, tmpName); 611 if (i != 0 && mForEachFunctions[i] == NULL) { 612 // Ignore missing root.expand functions. 613 // root() is always specified at location 0. 614 ALOGE("Failed to find forEach function address for %s: %s", 615 tmpName, dlerror()); 616 goto error; 617 } 618 else { 619 //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]); 620 } 621 } 622 } 623 624 size_t objectSlotCount = 0; 625 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 626 goto error; 627 } 628 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) { 629 ALOGE("Invalid object slot count!: %s", line); 630 goto error; 631 } 632 633 if (objectSlotCount > 0) { 634 rsAssert(varCount > 0); 635 for (size_t i = 0; i < objectSlotCount; ++i) { 636 uint32_t varNum = 0; 637 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 638 goto error; 639 } 640 if (sscanf(line, "%u", &varNum) != 1) { 641 ALOGE("Invalid object slot!: %s", line); 642 goto error; 643 } 644 645 if (varNum < varCount) { 646 mFieldIsObject[varNum] = true; 647 } 648 } 649 } 650 651 if (varCount > 0) { 652 mBoundAllocs = new Allocation *[varCount]; 653 memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs)); 654 } 655 656 if (mScriptSO == (void*)1) { 657 //rsdLookupRuntimeStub(script, "acos"); 658 } 659 } else { 660 goto error; 661 } 662 #endif 663 664 mCtx->unlockMutex(); 665 return true; 666 667 #ifdef RS_COMPATIBILITY_LIB 668 error: 669 670 mCtx->unlockMutex(); 671 delete[] mInvokeFunctions; 672 delete[] mForEachFunctions; 673 delete[] mFieldAddress; 674 delete[] mFieldIsObject; 675 delete[] mForEachSignatures; 676 delete[] mBoundAllocs; 677 if (mScriptSO) { 678 dlclose(mScriptSO); 679 } 680 return false; 681 #endif 682 } 683 684 void RsdCpuScriptImpl::populateScript(Script *script) { 685 #ifndef RS_COMPATIBILITY_LIB 686 const bcc::RSInfo *info = &mExecutable->getInfo(); 687 688 // Copy info over to runtime 689 script->mHal.info.exportedFunctionCount = info->getExportFuncNames().size(); 690 script->mHal.info.exportedVariableCount = info->getExportVarNames().size(); 691 script->mHal.info.exportedForeachFuncList = info->getExportForeachFuncs().array(); 692 script->mHal.info.exportedPragmaCount = info->getPragmas().size(); 693 script->mHal.info.exportedPragmaKeyList = 694 const_cast<const char**>(mExecutable->getPragmaKeys().array()); 695 script->mHal.info.exportedPragmaValueList = 696 const_cast<const char**>(mExecutable->getPragmaValues().array()); 697 698 if (mRootExpand) { 699 script->mHal.info.root = mRootExpand; 700 } else { 701 script->mHal.info.root = mRoot; 702 } 703 #else 704 // Copy info over to runtime 705 script->mHal.info.exportedFunctionCount = mExportedFunctionCount; 706 script->mHal.info.exportedVariableCount = mExportedVariableCount; 707 script->mHal.info.exportedPragmaCount = 0; 708 script->mHal.info.exportedPragmaKeyList = 0; 709 script->mHal.info.exportedPragmaValueList = 0; 710 711 // Bug, need to stash in metadata 712 if (mRootExpand) { 713 script->mHal.info.root = mRootExpand; 714 } else { 715 script->mHal.info.root = mRoot; 716 } 717 #endif 718 } 719 720 721 typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t); 722 723 void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation * ain, Allocation * aout, 724 const void * usr, uint32_t usrLen, 725 const RsScriptCall *sc, 726 MTLaunchStruct *mtls) { 727 728 memset(mtls, 0, sizeof(MTLaunchStruct)); 729 730 // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface 731 if (ain && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) { 732 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null in allocations"); 733 return; 734 } 735 if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) { 736 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null out allocations"); 737 return; 738 } 739 740 if (ain) { 741 mtls->fep.dimX = ain->getType()->getDimX(); 742 mtls->fep.dimY = ain->getType()->getDimY(); 743 mtls->fep.dimZ = ain->getType()->getDimZ(); 744 //mtls->dimArray = ain->getType()->getDimArray(); 745 } else if (aout) { 746 mtls->fep.dimX = aout->getType()->getDimX(); 747 mtls->fep.dimY = aout->getType()->getDimY(); 748 mtls->fep.dimZ = aout->getType()->getDimZ(); 749 //mtls->dimArray = aout->getType()->getDimArray(); 750 } else { 751 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations"); 752 return; 753 } 754 755 if (!sc || (sc->xEnd == 0)) { 756 mtls->xEnd = mtls->fep.dimX; 757 } else { 758 rsAssert(sc->xStart < mtls->fep.dimX); 759 rsAssert(sc->xEnd <= mtls->fep.dimX); 760 rsAssert(sc->xStart < sc->xEnd); 761 mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart); 762 mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd); 763 if (mtls->xStart >= mtls->xEnd) return; 764 } 765 766 if (!sc || (sc->yEnd == 0)) { 767 mtls->yEnd = mtls->fep.dimY; 768 } else { 769 rsAssert(sc->yStart < mtls->fep.dimY); 770 rsAssert(sc->yEnd <= mtls->fep.dimY); 771 rsAssert(sc->yStart < sc->yEnd); 772 mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart); 773 mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd); 774 if (mtls->yStart >= mtls->yEnd) return; 775 } 776 777 if (!sc || (sc->zEnd == 0)) { 778 mtls->zEnd = mtls->fep.dimZ; 779 } else { 780 rsAssert(sc->zStart < mtls->fep.dimZ); 781 rsAssert(sc->zEnd <= mtls->fep.dimZ); 782 rsAssert(sc->zStart < sc->zEnd); 783 mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart); 784 mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd); 785 if (mtls->zStart >= mtls->zEnd) return; 786 } 787 788 mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd); 789 mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd); 790 mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd); 791 mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd); 792 793 rsAssert(!ain || (ain->getType()->getDimZ() == 0)); 794 795 mtls->rsc = mCtx; 796 mtls->ain = ain; 797 mtls->aout = aout; 798 mtls->fep.usr = usr; 799 mtls->fep.usrLen = usrLen; 800 mtls->mSliceSize = 1; 801 mtls->mSliceNum = 0; 802 803 mtls->fep.ptrIn = NULL; 804 mtls->fep.eStrideIn = 0; 805 mtls->isThreadable = mIsThreadable; 806 807 if (ain) { 808 mtls->fep.ptrIn = (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr; 809 mtls->fep.eStrideIn = ain->getType()->getElementSizeBytes(); 810 mtls->fep.yStrideIn = ain->mHal.drvState.lod[0].stride; 811 } 812 813 mtls->fep.ptrOut = NULL; 814 mtls->fep.eStrideOut = 0; 815 if (aout) { 816 mtls->fep.ptrOut = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr; 817 mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes(); 818 mtls->fep.yStrideOut = aout->mHal.drvState.lod[0].stride; 819 } 820 } 821 822 823 void RsdCpuScriptImpl::invokeForEach(uint32_t slot, 824 const Allocation * ain, 825 Allocation * aout, 826 const void * usr, 827 uint32_t usrLen, 828 const RsScriptCall *sc) { 829 830 MTLaunchStruct mtls; 831 forEachMtlsSetup(ain, aout, usr, usrLen, sc, &mtls); 832 forEachKernelSetup(slot, &mtls); 833 834 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 835 mCtx->launchThreads(ain, aout, sc, &mtls); 836 mCtx->setTLS(oldTLS); 837 } 838 839 void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) { 840 mtls->script = this; 841 mtls->fep.slot = slot; 842 #ifndef RS_COMPATIBILITY_LIB 843 rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size()); 844 mtls->kernel = reinterpret_cast<ForEachFunc_t>( 845 mExecutable->getExportForeachFuncAddrs()[slot]); 846 rsAssert(mtls->kernel != NULL); 847 mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second; 848 #else 849 mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]); 850 rsAssert(mtls->kernel != NULL); 851 mtls->sig = mForEachSignatures[slot]; 852 #endif 853 } 854 855 int RsdCpuScriptImpl::invokeRoot() { 856 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 857 int ret = mRoot(); 858 mCtx->setTLS(oldTLS); 859 return ret; 860 } 861 862 void RsdCpuScriptImpl::invokeInit() { 863 if (mInit) { 864 mInit(); 865 } 866 } 867 868 void RsdCpuScriptImpl::invokeFreeChildren() { 869 if (mFreeChildren) { 870 mFreeChildren(); 871 } 872 } 873 874 void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params, 875 size_t paramLength) { 876 //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength); 877 878 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 879 reinterpret_cast<void (*)(const void *, uint32_t)>( 880 #ifndef RS_COMPATIBILITY_LIB 881 mExecutable->getExportFuncAddrs()[slot])(params, paramLength); 882 #else 883 mInvokeFunctions[slot])(params, paramLength); 884 #endif 885 mCtx->setTLS(oldTLS); 886 } 887 888 void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) { 889 //rsAssert(!script->mFieldIsObject[slot]); 890 //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength); 891 892 //if (mIntrinsicID) { 893 //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength); 894 //return; 895 //} 896 897 #ifndef RS_COMPATIBILITY_LIB 898 int32_t *destPtr = reinterpret_cast<int32_t *>( 899 mExecutable->getExportVarAddrs()[slot]); 900 #else 901 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 902 #endif 903 if (!destPtr) { 904 //ALOGV("Calling setVar on slot = %i which is null", slot); 905 return; 906 } 907 908 memcpy(destPtr, data, dataLength); 909 } 910 911 void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) { 912 //rsAssert(!script->mFieldIsObject[slot]); 913 //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength); 914 915 #ifndef RS_COMPATIBILITY_LIB 916 int32_t *srcPtr = reinterpret_cast<int32_t *>( 917 mExecutable->getExportVarAddrs()[slot]); 918 #else 919 int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 920 #endif 921 if (!srcPtr) { 922 //ALOGV("Calling setVar on slot = %i which is null", slot); 923 return; 924 } 925 memcpy(data, srcPtr, dataLength); 926 } 927 928 929 void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength, 930 const Element *elem, 931 const size_t *dims, size_t dimLength) { 932 933 #ifndef RS_COMPATIBILITY_LIB 934 int32_t *destPtr = reinterpret_cast<int32_t *>( 935 mExecutable->getExportVarAddrs()[slot]); 936 #else 937 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 938 #endif 939 if (!destPtr) { 940 //ALOGV("Calling setVar on slot = %i which is null", slot); 941 return; 942 } 943 944 // We want to look at dimension in terms of integer components, 945 // but dimLength is given in terms of bytes. 946 dimLength /= sizeof(int); 947 948 // Only a single dimension is currently supported. 949 rsAssert(dimLength == 1); 950 if (dimLength == 1) { 951 // First do the increment loop. 952 size_t stride = elem->getSizeBytes(); 953 const char *cVal = reinterpret_cast<const char *>(data); 954 for (size_t i = 0; i < dims[0]; i++) { 955 elem->incRefs(cVal); 956 cVal += stride; 957 } 958 959 // Decrement loop comes after (to prevent race conditions). 960 char *oldVal = reinterpret_cast<char *>(destPtr); 961 for (size_t i = 0; i < dims[0]; i++) { 962 elem->decRefs(oldVal); 963 oldVal += stride; 964 } 965 } 966 967 memcpy(destPtr, data, dataLength); 968 } 969 970 void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) { 971 972 //rsAssert(!script->mFieldIsObject[slot]); 973 //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data); 974 975 #ifndef RS_COMPATIBILITY_LIB 976 int32_t *destPtr = reinterpret_cast<int32_t *>( 977 mExecutable->getExportVarAddrs()[slot]); 978 #else 979 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 980 #endif 981 if (!destPtr) { 982 //ALOGV("Calling setVar on slot = %i which is null", slot); 983 return; 984 } 985 986 void *ptr = NULL; 987 mBoundAllocs[slot] = data; 988 if(data) { 989 ptr = data->mHal.drvState.lod[0].mallocPtr; 990 } 991 memcpy(destPtr, &ptr, sizeof(void *)); 992 } 993 994 void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) { 995 996 //rsAssert(script->mFieldIsObject[slot]); 997 //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data); 998 999 //if (mIntrinsicID) { 1000 //mIntrinsicFuncs.setVarObj(dc, script, drv->mIntrinsicData, slot, alloc); 1001 //return; 1002 //} 1003 1004 #ifndef RS_COMPATIBILITY_LIB 1005 int32_t *destPtr = reinterpret_cast<int32_t *>( 1006 mExecutable->getExportVarAddrs()[slot]); 1007 #else 1008 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1009 #endif 1010 if (!destPtr) { 1011 //ALOGV("Calling setVar on slot = %i which is null", slot); 1012 return; 1013 } 1014 1015 rsrSetObject(mCtx->getContext(), (ObjectBase **)destPtr, data); 1016 } 1017 1018 RsdCpuScriptImpl::~RsdCpuScriptImpl() { 1019 #ifndef RS_COMPATIBILITY_LIB 1020 if (mExecutable) { 1021 Vector<void *>::const_iterator var_addr_iter = 1022 mExecutable->getExportVarAddrs().begin(); 1023 Vector<void *>::const_iterator var_addr_end = 1024 mExecutable->getExportVarAddrs().end(); 1025 1026 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter = 1027 mExecutable->getInfo().getObjectSlots().begin(); 1028 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end = 1029 mExecutable->getInfo().getObjectSlots().end(); 1030 1031 while ((var_addr_iter != var_addr_end) && 1032 (is_object_iter != is_object_end)) { 1033 // The field address can be NULL if the script-side has optimized 1034 // the corresponding global variable away. 1035 ObjectBase **obj_addr = 1036 reinterpret_cast<ObjectBase **>(*var_addr_iter); 1037 if (*is_object_iter) { 1038 if (*var_addr_iter != NULL) { 1039 rsrClearObject(mCtx->getContext(), obj_addr); 1040 } 1041 } 1042 var_addr_iter++; 1043 is_object_iter++; 1044 } 1045 } 1046 1047 if (mCompilerContext) { 1048 delete mCompilerContext; 1049 } 1050 if (mCompilerDriver) { 1051 delete mCompilerDriver; 1052 } 1053 if (mExecutable) { 1054 delete mExecutable; 1055 } 1056 if (mBoundAllocs) { 1057 delete[] mBoundAllocs; 1058 } 1059 #else 1060 if (mFieldIsObject) { 1061 for (size_t i = 0; i < mExportedVariableCount; ++i) { 1062 if (mFieldIsObject[i]) { 1063 if (mFieldAddress[i] != NULL) { 1064 ObjectBase **obj_addr = 1065 reinterpret_cast<ObjectBase **>(mFieldAddress[i]); 1066 rsrClearObject(mCtx->getContext(), obj_addr); 1067 } 1068 } 1069 } 1070 } 1071 1072 if (mInvokeFunctions) delete[] mInvokeFunctions; 1073 if (mForEachFunctions) delete[] mForEachFunctions; 1074 if (mFieldAddress) delete[] mFieldAddress; 1075 if (mFieldIsObject) delete[] mFieldIsObject; 1076 if (mForEachSignatures) delete[] mForEachSignatures; 1077 if (mBoundAllocs) delete[] mBoundAllocs; 1078 if (mScriptSO) { 1079 dlclose(mScriptSO); 1080 } 1081 #endif 1082 } 1083 1084 Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const { 1085 if (!ptr) { 1086 return NULL; 1087 } 1088 1089 for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) { 1090 Allocation *a = mBoundAllocs[ct]; 1091 if (!a) continue; 1092 if (a->mHal.drvState.lod[0].mallocPtr == ptr) { 1093 return a; 1094 } 1095 } 1096 ALOGE("rsGetAllocation, failed to find %p", ptr); 1097 return NULL; 1098 } 1099 1100 void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation * ain, 1101 Allocation * aout, const void * usr, 1102 uint32_t usrLen, const RsScriptCall *sc) 1103 { 1104 } 1105 1106 void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation * ain, 1107 Allocation * aout, const void * usr, 1108 uint32_t usrLen, const RsScriptCall *sc) 1109 { 1110 } 1111 1112 1113 } 1114 } 1115