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