rsCpuScript.cpp revision 005113297b19ed256b6db9d6bc293ed9266899fc
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 219//#define EXTERNAL_BCC_COMPILER 1 220#ifdef EXTERNAL_BCC_COMPILER 221const static char *BCC_EXE_PATH = "/system/bin/bcc"; 222 223static bool compileBitcode(const char *cacheDir, 224 const char *resName, 225 const char *bitcode, 226 size_t bitcodeSize, 227 const char *core_lib, 228 bool useRSDebugContext, 229 const char *bccPluginName) { 230 rsAssert(cacheDir && resName && bitcode && bitcodeSize && core_lib); 231 232 android::String8 bcFilename(cacheDir); 233 bcFilename.append("/"); 234 bcFilename.append(resName); 235 bcFilename.append(".bc"); 236 FILE *bcfile = fopen(bcFilename.string(), "w"); 237 if (!bcfile) { 238 ALOGE("Could not write to %s", bcFilename.string()); 239 return false; 240 } 241 size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile); 242 fclose(bcfile); 243 if (nwritten != bitcodeSize) { 244 ALOGE("Could not write %zu bytes to %s", bitcodeSize, 245 bcFilename.string()); 246 return false; 247 } 248 249 pid_t pid = fork(); 250 251 switch (pid) { 252 case -1: { // Error occurred (we attempt no recovery) 253 ALOGE("Couldn't fork for bcc compiler execution"); 254 return false; 255 } 256 case 0: { // Child process 257 std::vector<std::string> args; 258 args.push_back(BCC_EXE_PATH); 259 args.push_back("-o"); 260 args.push_back(resName); 261 args.push_back("-output_path"); 262 args.push_back(cacheDir); 263 args.push_back("-bclib"); 264 args.push_back(core_lib); 265 266 // Execute the bcc compiler. 267 if (useRSDebugContext) { 268 args.push_back("-rs-debug-ctx"); 269 } else { 270 // Only load additional libraries for compiles that don't use 271 // the debug context. 272 if (bccPluginName && strlen(bccPluginName) > 0) { 273 args.push_back("-load"); 274 args.push_back(bccPluginName); 275 } 276 } 277 278 args.push_back(bcFilename.string()); 279 280 const char **cargs = new const char *[args.size() + 1]; 281 for (uint32_t i = 0; i < args.size(); i++) { 282 cargs[i] = args[i].c_str(); 283 } 284 cargs[args.size()] = NULL; 285 286 execv(BCC_EXE_PATH, (char *const *)cargs); 287 288 delete [] cargs; 289 ALOGE("execv() failed: %s", strerror(errno)); 290 abort(); 291 return false; 292 } 293 default: { // Parent process (actual driver) 294 // Wait on child process to finish compiling the source. 295 int status = 0; 296 pid_t w = waitpid(pid, &status, 0); 297 if (w == -1) { 298 ALOGE("Could not wait for bcc compiler"); 299 return false; 300 } 301 302 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 303 return true; 304 } 305 306 ALOGE("bcc compiler terminated unexpectedly"); 307 return false; 308 } 309 } 310} 311#endif // EXTERNAL_BCC_COMPILER 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 mCompilerDriver->setRSRuntimeLookupFunction(lookupRuntimeStub); 422 mCompilerDriver->setRSRuntimeLookupContext(this); 423 424 // Run any compiler setup functions we have been provided with. 425 RSSetupCompilerCallback setupCompilerCallback = 426 mCtx->getSetupCompilerCallback(); 427 if (setupCompilerCallback != NULL) { 428 setupCompilerCallback(mCompilerDriver); 429 } 430 431 const char *core_lib = bcc::RSInfo::LibCLCorePath; 432 433 bcinfo::MetadataExtractor ME((const char *) bitcode, bitcodeSize); 434 if (!ME.extract()) { 435 ALOGE("Could not extract metadata from bitcode"); 436 return false; 437 } 438 439 enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision(); 440 switch (prec) { 441 case bcinfo::RS_FP_Imprecise: 442 case bcinfo::RS_FP_Relaxed: 443#if defined(ARCH_ARM_HAVE_NEON) 444 // NEON-capable devices can use an accelerated math library for all 445 // reduced precision scripts. 446 core_lib = bcc::RSInfo::LibCLCoreNEONPath; 447#endif 448 break; 449 case bcinfo::RS_FP_Full: 450 break; 451 default: 452 ALOGE("Unknown precision for bitcode"); 453 return false; 454 } 455 456#if defined(__i386__) 457 // x86 devices will use an optimized library. 458 core_lib = bcc::RSInfo::LibCLCoreX86Path; 459#endif 460 461 RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback(); 462 if (selectRTCallback != NULL) { 463 core_lib = selectRTCallback((const char *)bitcode, bitcodeSize); 464 } 465 466 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) { 467 // Use the libclcore_debug.bc instead of the default library. 468 core_lib = bcc::RSInfo::LibCLCoreDebugPath; 469 mCompilerDriver->setDebugContext(true); 470 useRSDebugContext = true; 471 // Skip the cache lookup 472 } else if (!is_force_recompile()) { 473 // Attempt to just load the script from cache first if we can. 474 exec = mCompilerDriver->loadScript(cacheDir, resName, 475 (const char *)bitcode, bitcodeSize); 476 } 477 478 if (exec == NULL) { 479#ifdef EXTERNAL_BCC_COMPILER 480 bool built = compileBitcode(cacheDir, resName, (const char *)bitcode, 481 bitcodeSize, core_lib, useRSDebugContext, 482 bccPluginName); 483#else 484 bool built = mCompilerDriver->build(*mCompilerContext, cacheDir, 485 resName, (const char *)bitcode, 486 bitcodeSize, core_lib, 487 mCtx->getLinkRuntimeCallback()); 488#endif // EXTERNAL_BCC_COMPILER 489 if (built) { 490 exec = mCompilerDriver->loadScript(cacheDir, resName, 491 (const char *)bitcode, 492 bitcodeSize); 493 } 494 } 495 496 if (exec == NULL) { 497 ALOGE("bcc: FAILS to prepare executable for '%s'", resName); 498 mCtx->unlockMutex(); 499 return false; 500 } 501 502 mExecutable = exec; 503 504 exec->setThreadable(mIsThreadable); 505 if (!exec->syncInfo()) { 506 ALOGW("bcc: FAILS to synchronize the RS info file to the disk"); 507 } 508 509 mRoot = reinterpret_cast<int (*)()>(exec->getSymbolAddress("root")); 510 mRootExpand = 511 reinterpret_cast<int (*)()>(exec->getSymbolAddress("root.expand")); 512 mInit = reinterpret_cast<void (*)()>(exec->getSymbolAddress("init")); 513 mFreeChildren = 514 reinterpret_cast<void (*)()>(exec->getSymbolAddress(".rs.dtor")); 515 516 517 const bcc::RSInfo *info = &mExecutable->getInfo(); 518 if (info->getExportVarNames().size()) { 519 mBoundAllocs = new Allocation *[info->getExportVarNames().size()]; 520 memset(mBoundAllocs, 0, sizeof(void *) * info->getExportVarNames().size()); 521 } 522 523#else 524 525 mScriptSO = loadSharedLibrary(cacheDir, resName); 526 527 if (mScriptSO) { 528 char line[MAXLINE]; 529 mRoot = (RootFunc_t) dlsym(mScriptSO, "root"); 530 if (mRoot) { 531 //ALOGE("Found root(): %p", mRoot); 532 } 533 mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand"); 534 if (mRootExpand) { 535 //ALOGE("Found root.expand(): %p", mRootExpand); 536 } 537 mInit = (InvokeFunc_t) dlsym(mScriptSO, "init"); 538 if (mInit) { 539 //ALOGE("Found init(): %p", mInit); 540 } 541 mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor"); 542 if (mFreeChildren) { 543 //ALOGE("Found .rs.dtor(): %p", mFreeChildren); 544 } 545 546 const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info"); 547 if (rsInfo) { 548 //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo); 549 } 550 551 size_t varCount = 0; 552 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 553 goto error; 554 } 555 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) { 556 ALOGE("Invalid export var count!: %s", line); 557 goto error; 558 } 559 560 mExportedVariableCount = varCount; 561 //ALOGE("varCount: %zu", varCount); 562 if (varCount > 0) { 563 // Start by creating/zeroing this member, since we don't want to 564 // accidentally clean up invalid pointers later (if we error out). 565 mFieldIsObject = new bool[varCount]; 566 if (mFieldIsObject == NULL) { 567 goto error; 568 } 569 memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject)); 570 mFieldAddress = new void*[varCount]; 571 if (mFieldAddress == NULL) { 572 goto error; 573 } 574 for (size_t i = 0; i < varCount; ++i) { 575 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 576 goto error; 577 } 578 char *c = strrchr(line, '\n'); 579 if (c) { 580 *c = '\0'; 581 } 582 mFieldAddress[i] = dlsym(mScriptSO, line); 583 if (mFieldAddress[i] == NULL) { 584 ALOGE("Failed to find variable address for %s: %s", 585 line, dlerror()); 586 // Not a critical error if we don't find a global variable. 587 } 588 else { 589 //ALOGE("Found variable %s at %p", line, 590 //mFieldAddress[i]); 591 } 592 } 593 } 594 595 size_t funcCount = 0; 596 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 597 goto error; 598 } 599 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) { 600 ALOGE("Invalid export func count!: %s", line); 601 goto error; 602 } 603 604 mExportedFunctionCount = funcCount; 605 //ALOGE("funcCount: %zu", funcCount); 606 607 if (funcCount > 0) { 608 mInvokeFunctions = new InvokeFunc_t[funcCount]; 609 if (mInvokeFunctions == NULL) { 610 goto error; 611 } 612 for (size_t i = 0; i < funcCount; ++i) { 613 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 614 goto error; 615 } 616 char *c = strrchr(line, '\n'); 617 if (c) { 618 *c = '\0'; 619 } 620 621 mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line); 622 if (mInvokeFunctions[i] == NULL) { 623 ALOGE("Failed to get function address for %s(): %s", 624 line, dlerror()); 625 goto error; 626 } 627 else { 628 //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]); 629 } 630 } 631 } 632 633 size_t forEachCount = 0; 634 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 635 goto error; 636 } 637 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) { 638 ALOGE("Invalid export forEach count!: %s", line); 639 goto error; 640 } 641 642 if (forEachCount > 0) { 643 644 mForEachSignatures = new uint32_t[forEachCount]; 645 if (mForEachSignatures == NULL) { 646 goto error; 647 } 648 mForEachFunctions = new ForEachFunc_t[forEachCount]; 649 if (mForEachFunctions == NULL) { 650 goto error; 651 } 652 for (size_t i = 0; i < forEachCount; ++i) { 653 unsigned int tmpSig = 0; 654 char tmpName[MAXLINE]; 655 656 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 657 goto error; 658 } 659 if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s", 660 &tmpSig, tmpName) != 2) { 661 ALOGE("Invalid export forEach!: %s", line); 662 goto error; 663 } 664 665 // Lookup the expanded ForEach kernel. 666 strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName)); 667 mForEachSignatures[i] = tmpSig; 668 mForEachFunctions[i] = 669 (ForEachFunc_t) dlsym(mScriptSO, tmpName); 670 if (i != 0 && mForEachFunctions[i] == NULL) { 671 // Ignore missing root.expand functions. 672 // root() is always specified at location 0. 673 ALOGE("Failed to find forEach function address for %s: %s", 674 tmpName, dlerror()); 675 goto error; 676 } 677 else { 678 //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]); 679 } 680 } 681 } 682 683 size_t objectSlotCount = 0; 684 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 685 goto error; 686 } 687 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) { 688 ALOGE("Invalid object slot count!: %s", line); 689 goto error; 690 } 691 692 if (objectSlotCount > 0) { 693 rsAssert(varCount > 0); 694 for (size_t i = 0; i < objectSlotCount; ++i) { 695 uint32_t varNum = 0; 696 if (strgets(line, MAXLINE, &rsInfo) == NULL) { 697 goto error; 698 } 699 if (sscanf(line, "%u", &varNum) != 1) { 700 ALOGE("Invalid object slot!: %s", line); 701 goto error; 702 } 703 704 if (varNum < varCount) { 705 mFieldIsObject[varNum] = true; 706 } 707 } 708 } 709 710 if (varCount > 0) { 711 mBoundAllocs = new Allocation *[varCount]; 712 memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs)); 713 } 714 715 if (mScriptSO == (void*)1) { 716 //rsdLookupRuntimeStub(script, "acos"); 717 } 718 } else { 719 goto error; 720 } 721#endif 722#endif // FAKE_ARM64_BUILD 723 mCtx->unlockMutex(); 724 return true; 725 726#ifdef RS_COMPATIBILITY_LIB 727error: 728 729 mCtx->unlockMutex(); 730 delete[] mInvokeFunctions; 731 delete[] mForEachFunctions; 732 delete[] mFieldAddress; 733 delete[] mFieldIsObject; 734 delete[] mForEachSignatures; 735 delete[] mBoundAllocs; 736 if (mScriptSO) { 737 dlclose(mScriptSO); 738 } 739 return false; 740#endif 741} 742 743void RsdCpuScriptImpl::populateScript(Script *script) { 744#ifndef FAKE_ARM64_BUILD 745#ifndef RS_COMPATIBILITY_LIB 746 const bcc::RSInfo *info = &mExecutable->getInfo(); 747 748 // Copy info over to runtime 749 script->mHal.info.exportedFunctionCount = info->getExportFuncNames().size(); 750 script->mHal.info.exportedVariableCount = info->getExportVarNames().size(); 751 script->mHal.info.exportedForeachFuncList = info->getExportForeachFuncs().array(); 752 script->mHal.info.exportedPragmaCount = info->getPragmas().size(); 753 script->mHal.info.exportedPragmaKeyList = 754 const_cast<const char**>(mExecutable->getPragmaKeys().array()); 755 script->mHal.info.exportedPragmaValueList = 756 const_cast<const char**>(mExecutable->getPragmaValues().array()); 757 758 if (mRootExpand) { 759 script->mHal.info.root = mRootExpand; 760 } else { 761 script->mHal.info.root = mRoot; 762 } 763#else 764 // Copy info over to runtime 765 script->mHal.info.exportedFunctionCount = mExportedFunctionCount; 766 script->mHal.info.exportedVariableCount = mExportedVariableCount; 767 script->mHal.info.exportedPragmaCount = 0; 768 script->mHal.info.exportedPragmaKeyList = 0; 769 script->mHal.info.exportedPragmaValueList = 0; 770 771 // Bug, need to stash in metadata 772 if (mRootExpand) { 773 script->mHal.info.root = mRootExpand; 774 } else { 775 script->mHal.info.root = mRoot; 776 } 777#endif 778#endif 779} 780 781 782typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t); 783 784void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation * ain, Allocation * aout, 785 const void * usr, uint32_t usrLen, 786 const RsScriptCall *sc, 787 MTLaunchStruct *mtls) { 788 789 memset(mtls, 0, sizeof(MTLaunchStruct)); 790 791 // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface 792 if (ain && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) { 793 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null in allocations"); 794 return; 795 } 796 if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) { 797 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null out allocations"); 798 return; 799 } 800 801 if (ain) { 802 mtls->fep.dimX = ain->getType()->getDimX(); 803 mtls->fep.dimY = ain->getType()->getDimY(); 804 mtls->fep.dimZ = ain->getType()->getDimZ(); 805 //mtls->dimArray = ain->getType()->getDimArray(); 806 } else if (aout) { 807 mtls->fep.dimX = aout->getType()->getDimX(); 808 mtls->fep.dimY = aout->getType()->getDimY(); 809 mtls->fep.dimZ = aout->getType()->getDimZ(); 810 //mtls->dimArray = aout->getType()->getDimArray(); 811 } else { 812 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations"); 813 return; 814 } 815 816 if (!sc || (sc->xEnd == 0)) { 817 mtls->xEnd = mtls->fep.dimX; 818 } else { 819 rsAssert(sc->xStart < mtls->fep.dimX); 820 rsAssert(sc->xEnd <= mtls->fep.dimX); 821 rsAssert(sc->xStart < sc->xEnd); 822 mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart); 823 mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd); 824 if (mtls->xStart >= mtls->xEnd) return; 825 } 826 827 if (!sc || (sc->yEnd == 0)) { 828 mtls->yEnd = mtls->fep.dimY; 829 } else { 830 rsAssert(sc->yStart < mtls->fep.dimY); 831 rsAssert(sc->yEnd <= mtls->fep.dimY); 832 rsAssert(sc->yStart < sc->yEnd); 833 mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart); 834 mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd); 835 if (mtls->yStart >= mtls->yEnd) return; 836 } 837 838 if (!sc || (sc->zEnd == 0)) { 839 mtls->zEnd = mtls->fep.dimZ; 840 } else { 841 rsAssert(sc->zStart < mtls->fep.dimZ); 842 rsAssert(sc->zEnd <= mtls->fep.dimZ); 843 rsAssert(sc->zStart < sc->zEnd); 844 mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart); 845 mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd); 846 if (mtls->zStart >= mtls->zEnd) return; 847 } 848 849 mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd); 850 mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd); 851 mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd); 852 mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd); 853 854 rsAssert(!ain || (ain->getType()->getDimZ() == 0)); 855 856 mtls->rsc = mCtx; 857 mtls->ain = ain; 858 mtls->aout = aout; 859 mtls->fep.usr = usr; 860 mtls->fep.usrLen = usrLen; 861 mtls->mSliceSize = 1; 862 mtls->mSliceNum = 0; 863 864 mtls->fep.ptrIn = NULL; 865 mtls->fep.eStrideIn = 0; 866 mtls->isThreadable = mIsThreadable; 867 868 if (ain) { 869 mtls->fep.ptrIn = (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr; 870 mtls->fep.eStrideIn = ain->getType()->getElementSizeBytes(); 871 mtls->fep.yStrideIn = ain->mHal.drvState.lod[0].stride; 872 } 873 874 mtls->fep.ptrOut = NULL; 875 mtls->fep.eStrideOut = 0; 876 if (aout) { 877 mtls->fep.ptrOut = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr; 878 mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes(); 879 mtls->fep.yStrideOut = aout->mHal.drvState.lod[0].stride; 880 } 881} 882 883 884void RsdCpuScriptImpl::invokeForEach(uint32_t slot, 885 const Allocation * ain, 886 Allocation * aout, 887 const void * usr, 888 uint32_t usrLen, 889 const RsScriptCall *sc) { 890 891 MTLaunchStruct mtls; 892 forEachMtlsSetup(ain, aout, usr, usrLen, sc, &mtls); 893 forEachKernelSetup(slot, &mtls); 894 895 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 896 mCtx->launchThreads(ain, aout, sc, &mtls); 897 mCtx->setTLS(oldTLS); 898} 899 900void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) { 901 mtls->script = this; 902 mtls->fep.slot = slot; 903#ifndef FAKE_ARM64_BUILD 904#ifndef RS_COMPATIBILITY_LIB 905 rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size()); 906 mtls->kernel = reinterpret_cast<ForEachFunc_t>( 907 mExecutable->getExportForeachFuncAddrs()[slot]); 908 rsAssert(mtls->kernel != NULL); 909 mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second; 910#else 911 mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]); 912 rsAssert(mtls->kernel != NULL); 913 mtls->sig = mForEachSignatures[slot]; 914#endif 915#endif 916} 917 918int RsdCpuScriptImpl::invokeRoot() { 919 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 920#ifndef FAKE_ARM64_BUILD 921 int ret = mRoot(); 922#else 923 int ret = 0; 924#endif 925 mCtx->setTLS(oldTLS); 926 return ret; 927} 928 929void RsdCpuScriptImpl::invokeInit() { 930#ifndef FAKE_ARM64_BUILD 931 if (mInit) { 932 mInit(); 933 } 934#endif 935} 936 937void RsdCpuScriptImpl::invokeFreeChildren() { 938#ifndef FAKE_ARM64_BUILD 939 if (mFreeChildren) { 940 mFreeChildren(); 941 } 942#endif 943} 944 945void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params, 946 size_t paramLength) { 947 //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength); 948 949 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 950#ifndef FAKE_ARM64_BUILD 951 reinterpret_cast<void (*)(const void *, uint32_t)>( 952#ifndef RS_COMPATIBILITY_LIB 953 mExecutable->getExportFuncAddrs()[slot])(params, paramLength); 954#else 955 mInvokeFunctions[slot])(params, paramLength); 956#endif 957#endif 958 mCtx->setTLS(oldTLS); 959} 960 961void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) { 962 //rsAssert(!script->mFieldIsObject[slot]); 963 //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength); 964 965 //if (mIntrinsicID) { 966 //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength); 967 //return; 968 //} 969 970#ifndef FAKE_ARM64_BUILD 971#ifndef RS_COMPATIBILITY_LIB 972 int32_t *destPtr = reinterpret_cast<int32_t *>( 973 mExecutable->getExportVarAddrs()[slot]); 974#else 975 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 976#endif 977#else 978 int32_t *destPtr = NULL; 979#endif 980 if (!destPtr) { 981 //ALOGV("Calling setVar on slot = %i which is null", slot); 982 return; 983 } 984 985 memcpy(destPtr, data, dataLength); 986} 987 988void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) { 989 //rsAssert(!script->mFieldIsObject[slot]); 990 //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength); 991 992#ifndef FAKE_ARM64_BUILD 993#ifndef RS_COMPATIBILITY_LIB 994 int32_t *srcPtr = reinterpret_cast<int32_t *>( 995 mExecutable->getExportVarAddrs()[slot]); 996#else 997 int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 998#endif 999#else 1000 int32_t *srcPtr = NULL; 1001#endif 1002 if (!srcPtr) { 1003 //ALOGV("Calling setVar on slot = %i which is null", slot); 1004 return; 1005 } 1006 memcpy(data, srcPtr, dataLength); 1007} 1008 1009 1010void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength, 1011 const Element *elem, 1012 const size_t *dims, size_t dimLength) { 1013 1014#ifndef FAKE_ARM64_BUILD 1015#ifndef RS_COMPATIBILITY_LIB 1016 int32_t *destPtr = reinterpret_cast<int32_t *>( 1017 mExecutable->getExportVarAddrs()[slot]); 1018#else 1019 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1020#endif 1021#else 1022 int32_t *destPtr = NULL; 1023#endif 1024 if (!destPtr) { 1025 //ALOGV("Calling setVar on slot = %i which is null", slot); 1026 return; 1027 } 1028 1029 // We want to look at dimension in terms of integer components, 1030 // but dimLength is given in terms of bytes. 1031 dimLength /= sizeof(int); 1032 1033 // Only a single dimension is currently supported. 1034 rsAssert(dimLength == 1); 1035 if (dimLength == 1) { 1036 // First do the increment loop. 1037 size_t stride = elem->getSizeBytes(); 1038 const char *cVal = reinterpret_cast<const char *>(data); 1039 for (size_t i = 0; i < dims[0]; i++) { 1040 elem->incRefs(cVal); 1041 cVal += stride; 1042 } 1043 1044 // Decrement loop comes after (to prevent race conditions). 1045 char *oldVal = reinterpret_cast<char *>(destPtr); 1046 for (size_t i = 0; i < dims[0]; i++) { 1047 elem->decRefs(oldVal); 1048 oldVal += stride; 1049 } 1050 } 1051 1052 memcpy(destPtr, data, dataLength); 1053} 1054 1055void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) { 1056 1057 //rsAssert(!script->mFieldIsObject[slot]); 1058 //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data); 1059 1060#ifndef FAKE_ARM64_BUILD 1061#ifndef RS_COMPATIBILITY_LIB 1062 int32_t *destPtr = reinterpret_cast<int32_t *>( 1063 mExecutable->getExportVarAddrs()[slot]); 1064#else 1065 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1066#endif 1067#else 1068 int32_t *destPtr = NULL; 1069#endif 1070 if (!destPtr) { 1071 //ALOGV("Calling setVar on slot = %i which is null", slot); 1072 return; 1073 } 1074 1075 void *ptr = NULL; 1076 mBoundAllocs[slot] = data; 1077 if(data) { 1078 ptr = data->mHal.drvState.lod[0].mallocPtr; 1079 } 1080 memcpy(destPtr, &ptr, sizeof(void *)); 1081} 1082 1083void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) { 1084 1085 //rsAssert(script->mFieldIsObject[slot]); 1086 //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data); 1087 1088 //if (mIntrinsicID) { 1089 //mIntrinsicFuncs.setVarObj(dc, script, drv->mIntrinsicData, slot, alloc); 1090 //return; 1091 //} 1092 1093#ifndef FAKE_ARM64_BUILD 1094#ifndef RS_COMPATIBILITY_LIB 1095 int32_t *destPtr = reinterpret_cast<int32_t *>( 1096 mExecutable->getExportVarAddrs()[slot]); 1097#else 1098 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1099#endif 1100#else 1101 int32_t *destPtr = NULL; 1102#endif 1103 1104 1105 if (!destPtr) { 1106 //ALOGV("Calling setVar on slot = %i which is null", slot); 1107 return; 1108 } 1109 1110 rsrSetObject(mCtx->getContext(), (ObjectBase **)destPtr, data); 1111} 1112 1113RsdCpuScriptImpl::~RsdCpuScriptImpl() { 1114#ifndef FAKE_ARM64_BUILD 1115#ifndef RS_COMPATIBILITY_LIB 1116 if (mExecutable) { 1117 Vector<void *>::const_iterator var_addr_iter = 1118 mExecutable->getExportVarAddrs().begin(); 1119 Vector<void *>::const_iterator var_addr_end = 1120 mExecutable->getExportVarAddrs().end(); 1121 1122 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter = 1123 mExecutable->getInfo().getObjectSlots().begin(); 1124 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end = 1125 mExecutable->getInfo().getObjectSlots().end(); 1126 1127 while ((var_addr_iter != var_addr_end) && 1128 (is_object_iter != is_object_end)) { 1129 // The field address can be NULL if the script-side has optimized 1130 // the corresponding global variable away. 1131 ObjectBase **obj_addr = 1132 reinterpret_cast<ObjectBase **>(*var_addr_iter); 1133 if (*is_object_iter) { 1134 if (*var_addr_iter != NULL) { 1135 rsrClearObject(mCtx->getContext(), obj_addr); 1136 } 1137 } 1138 var_addr_iter++; 1139 is_object_iter++; 1140 } 1141 } 1142 1143 if (mCompilerContext) { 1144 delete mCompilerContext; 1145 } 1146 if (mCompilerDriver) { 1147 delete mCompilerDriver; 1148 } 1149 if (mExecutable) { 1150 delete mExecutable; 1151 } 1152 if (mBoundAllocs) { 1153 delete[] mBoundAllocs; 1154 } 1155#else 1156 if (mFieldIsObject) { 1157 for (size_t i = 0; i < mExportedVariableCount; ++i) { 1158 if (mFieldIsObject[i]) { 1159 if (mFieldAddress[i] != NULL) { 1160 ObjectBase **obj_addr = 1161 reinterpret_cast<ObjectBase **>(mFieldAddress[i]); 1162 rsrClearObject(mCtx->getContext(), obj_addr); 1163 } 1164 } 1165 } 1166 } 1167 1168 if (mInvokeFunctions) delete[] mInvokeFunctions; 1169 if (mForEachFunctions) delete[] mForEachFunctions; 1170 if (mFieldAddress) delete[] mFieldAddress; 1171 if (mFieldIsObject) delete[] mFieldIsObject; 1172 if (mForEachSignatures) delete[] mForEachSignatures; 1173 if (mBoundAllocs) delete[] mBoundAllocs; 1174 if (mScriptSO) { 1175 dlclose(mScriptSO); 1176 } 1177#endif 1178#endif 1179} 1180 1181Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const { 1182 if (!ptr) { 1183 return NULL; 1184 } 1185 1186 for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) { 1187 Allocation *a = mBoundAllocs[ct]; 1188 if (!a) continue; 1189 if (a->mHal.drvState.lod[0].mallocPtr == ptr) { 1190 return a; 1191 } 1192 } 1193 ALOGE("rsGetAllocation, failed to find %p", ptr); 1194 return NULL; 1195} 1196 1197void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation * ain, 1198 Allocation * aout, const void * usr, 1199 uint32_t usrLen, const RsScriptCall *sc) 1200{ 1201} 1202 1203void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation * ain, 1204 Allocation * aout, const void * usr, 1205 uint32_t usrLen, const RsScriptCall *sc) 1206{ 1207} 1208 1209 1210} 1211} 1212