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