rsCpuScript.cpp revision dc0d8f7c0f1f43f25c34fbc04656ad578f6e953b
1/* 2 * Copyright (C) 2011-2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "rsCpuCore.h" 18#include "rsCpuScript.h" 19 20#ifdef RS_COMPATIBILITY_LIB 21 #include <stdio.h> 22 #include <sys/stat.h> 23 #include <unistd.h> 24#else 25 #include <bcc/BCCContext.h> 26 #include <bcc/Config/Config.h> 27 #include <bcc/Renderscript/RSCompilerDriver.h> 28 #include <bcc/Renderscript/RSExecutable.h> 29 #include <bcc/Renderscript/RSInfo.h> 30 #include <bcinfo/MetadataExtractor.h> 31 #include <cutils/properties.h> 32 33 #include <sys/types.h> 34 #include <sys/wait.h> 35 #include <unistd.h> 36 37 #include <string> 38 #include <vector> 39#endif 40 41#include <set> 42#include <string> 43#include <dlfcn.h> 44#include <stdlib.h> 45#include <string.h> 46#include <fstream> 47#include <iostream> 48 49#ifdef __LP64__ 50#define SYSLIBPATH "/system/lib64" 51#else 52#define SYSLIBPATH "/system/lib" 53#endif 54 55namespace { 56 57// Create a len length string containing random characters from [A-Za-z0-9]. 58static std::string getRandomString(size_t len) { 59 char buf[len + 1]; 60 for (size_t i = 0; i < len; i++) { 61 uint32_t r = arc4random() & 0xffff; 62 r %= 62; 63 if (r < 26) { 64 // lowercase 65 buf[i] = 'a' + r; 66 } else if (r < 52) { 67 // uppercase 68 buf[i] = 'A' + (r - 26); 69 } else { 70 // Use a number 71 buf[i] = '0' + (r - 52); 72 } 73 } 74 buf[len] = '\0'; 75 return std::string(buf); 76} 77 78// Check if a path exists and attempt to create it if it doesn't. 79static bool ensureCacheDirExists(const char *path) { 80 if (access(path, R_OK | W_OK | X_OK) == 0) { 81 // Done if we can rwx the directory 82 return true; 83 } 84 if (mkdir(path, 0700) == 0) { 85 return true; 86 } 87 return false; 88} 89 90// Copy the file named \p srcFile to \p dstFile. 91// Return 0 on success and -1 if anything wasn't copied. 92static int copyFile(const char *dstFile, const char *srcFile) { 93 std::ifstream srcStream(srcFile); 94 if (!srcStream) { 95 ALOGE("Could not verify or read source file: %s", srcFile); 96 return -1; 97 } 98 std::ofstream dstStream(dstFile); 99 if (!dstStream) { 100 ALOGE("Could not verify or write destination file: %s", dstFile); 101 return -1; 102 } 103 dstStream << srcStream.rdbuf(); 104 if (!dstStream) { 105 ALOGE("Could not write destination file: %s", dstFile); 106 return -1; 107 } 108 109 srcStream.close(); 110 dstStream.close(); 111 112 return 0; 113} 114 115#define RS_CACHE_DIR "com.android.renderscript.cache" 116 117// Attempt to load the shared library from origName, but then fall back to 118// creating a copy of the shared library if necessary (to ensure instancing). 119// This function returns the dlopen()-ed handle if successful. 120static void *loadSOHelper(const char *origName, const char *cacheDir, 121 const char *resName) { 122 // Keep track of which .so libraries have been loaded. Once a library is 123 // in the set (per-process granularity), we must instead make a copy of 124 // the original shared object (randomly named .so file) and load that one 125 // instead. If we don't do this, we end up aliasing global data between 126 // the various Script instances (which are supposed to be completely 127 // independent). 128 static std::set<std::string> LoadedLibraries; 129 130 void *loaded = nullptr; 131 132 // Skip everything if we don't even have the original library available. 133 if (access(origName, F_OK) != 0) { 134 return nullptr; 135 } 136 137 // Common path is that we have not loaded this Script/library before. 138 if (LoadedLibraries.find(origName) == LoadedLibraries.end()) { 139 loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL); 140 if (loaded) { 141 LoadedLibraries.insert(origName); 142 } 143 return loaded; 144 } 145 146 std::string newName(cacheDir); 147 148 // Append RS_CACHE_DIR only if it is not found in cacheDir 149 // In driver mode, RS_CACHE_DIR is already appended to cacheDir. 150 if (newName.find(RS_CACHE_DIR) == std::string::npos) { 151 newName.append("/" RS_CACHE_DIR "/"); 152 } 153 154 if (!ensureCacheDirExists(newName.c_str())) { 155 ALOGE("Could not verify or create cache dir: %s", cacheDir); 156 return nullptr; 157 } 158 159 // Construct an appropriately randomized filename for the copy. 160 newName.append("librs."); 161 newName.append(resName); 162 newName.append("#"); 163 newName.append(getRandomString(6)); // 62^6 potential filename variants. 164 newName.append(".so"); 165 166 int r = copyFile(newName.c_str(), origName); 167 if (r != 0) { 168 ALOGE("Could not create copy %s -> %s", origName, newName.c_str()); 169 return nullptr; 170 } 171 loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL); 172 r = unlink(newName.c_str()); 173 if (r != 0) { 174 ALOGE("Could not unlink copy %s", newName.c_str()); 175 } 176 if (loaded) { 177 LoadedLibraries.insert(newName.c_str()); 178 } 179 180 return loaded; 181} 182 183static std::string findSharedObjectName(const char *cacheDir, 184 const char *resName) { 185 186#ifndef RS_SERVER 187 std::string scriptSOName(cacheDir); 188#ifdef RS_COMPATIBILITY_LIB 189 size_t cutPos = scriptSOName.rfind("cache"); 190 if (cutPos != std::string::npos) { 191 scriptSOName.erase(cutPos); 192 } else { 193 ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir); 194 } 195 scriptSOName.append("/lib/librs."); 196#else 197 scriptSOName.append("/librs."); 198#endif 199 200#else 201 std::string scriptSOName("lib"); 202#endif 203 scriptSOName.append(resName); 204 scriptSOName.append(".so"); 205 206 return scriptSOName; 207} 208 209// Load the shared library referred to by cacheDir and resName. If we have 210// already loaded this library, we instead create a new copy (in the 211// cache dir) and then load that. We then immediately destroy the copy. 212// This is required behavior to implement script instancing for the support 213// library, since shared objects are loaded and de-duped by name only. 214static void *loadSharedLibrary(const char *cacheDir, const char *resName) { 215 void *loaded = nullptr; 216 217 std::string scriptSOName = findSharedObjectName(cacheDir, resName); 218 219 // We should check if we can load the library from the standard app 220 // location for shared libraries first. 221 loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName); 222 223 if (loaded == nullptr) { 224 ALOGE("Unable to open shared library (%s): %s", 225 scriptSOName.c_str(), dlerror()); 226 227 // One final attempt to find the library in "/system/lib". 228 // We do this to allow bundled applications to use the compatibility 229 // library fallback path. Those applications don't have a private 230 // library path, so they need to install to the system directly. 231 // Note that this is really just a testing path. 232 std::string scriptSONameSystem("/system/lib/librs."); 233 scriptSONameSystem.append(resName); 234 scriptSONameSystem.append(".so"); 235 loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir, 236 resName); 237 if (loaded == nullptr) { 238 ALOGE("Unable to open system shared library (%s): %s", 239 scriptSONameSystem.c_str(), dlerror()); 240 } 241 } 242 243 return loaded; 244} 245 246#ifndef RS_COMPATIBILITY_LIB 247 248static bool is_skip_linkloader() { 249 char buf[PROPERTY_VALUE_MAX]; 250 static bool initialized = false; 251 static bool prop = false; 252 253 if (initialized) { 254 return prop; 255 } 256 257 property_get("rs.skip.linkloader", buf, ""); 258 prop = (buf[0] != '\0'); 259 initialized = true; 260 261 if (prop) { 262 ALOGV("Skipping linkloader"); 263 } 264 else { 265 ALOGV("Default path: using linkloader"); 266 } 267 return prop; 268} 269 270static bool is_force_recompile() { 271#ifdef RS_SERVER 272 return false; 273#else 274 char buf[PROPERTY_VALUE_MAX]; 275 276 // Re-compile if floating point precision has been overridden. 277 property_get("debug.rs.precision", buf, ""); 278 if (buf[0] != '\0') { 279 return true; 280 } 281 282 // Re-compile if debug.rs.forcerecompile is set. 283 property_get("debug.rs.forcerecompile", buf, "0"); 284 if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) { 285 return true; 286 } else { 287 return false; 288 } 289#endif // RS_SERVER 290} 291 292const static char *BCC_EXE_PATH = "/system/bin/bcc"; 293 294static void setCompileArguments(std::vector<const char*>* args, 295 const std::string& bcFileName, 296 const char* cacheDir, const char* resName, 297 const char* core_lib, bool useRSDebugContext, 298 const char* bccPluginName) { 299 rsAssert(cacheDir && resName && core_lib); 300 args->push_back(BCC_EXE_PATH); 301 args->push_back("-unroll-runtime"); 302 args->push_back("-scalarize-load-store"); 303 args->push_back("-o"); 304 args->push_back(resName); 305 args->push_back("-output_path"); 306 args->push_back(cacheDir); 307 args->push_back("-bclib"); 308 args->push_back(core_lib); 309 args->push_back("-mtriple"); 310 args->push_back(DEFAULT_TARGET_TRIPLE_STRING); 311 312 // Enable workaround for A53 codegen by default. 313#if defined(__aarch64__) && !defined(DISABLE_A53_WORKAROUND) 314 args->push_back("-aarch64-fix-cortex-a53-835769"); 315#endif 316 317 // Execute the bcc compiler. 318 if (useRSDebugContext) { 319 args->push_back("-rs-debug-ctx"); 320 } else { 321 // Only load additional libraries for compiles that don't use 322 // the debug context. 323 if (bccPluginName && strlen(bccPluginName) > 0) { 324 args->push_back("-load"); 325 args->push_back(bccPluginName); 326 } 327 } 328 329 if (is_skip_linkloader()) { 330 args->push_back("-fPIC"); 331 args->push_back("-embedRSInfo"); 332 } 333 334 args->push_back(bcFileName.c_str()); 335 args->push_back(nullptr); 336} 337 338static bool compileBitcode(const std::string &bcFileName, 339 const char *bitcode, 340 size_t bitcodeSize, 341 const char **compileArguments, 342 const std::string &compileCommandLine) { 343 rsAssert(bitcode && bitcodeSize); 344 345 FILE *bcfile = fopen(bcFileName.c_str(), "w"); 346 if (!bcfile) { 347 ALOGE("Could not write to %s", bcFileName.c_str()); 348 return false; 349 } 350 size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile); 351 fclose(bcfile); 352 if (nwritten != bitcodeSize) { 353 ALOGE("Could not write %zu bytes to %s", bitcodeSize, 354 bcFileName.c_str()); 355 return false; 356 } 357 358 pid_t pid = fork(); 359 360 switch (pid) { 361 case -1: { // Error occurred (we attempt no recovery) 362 ALOGE("Couldn't fork for bcc compiler execution"); 363 return false; 364 } 365 case 0: { // Child process 366 ALOGV("Invoking BCC with: %s", compileCommandLine.c_str()); 367 execv(BCC_EXE_PATH, (char* const*)compileArguments); 368 369 ALOGE("execv() failed: %s", strerror(errno)); 370 abort(); 371 return false; 372 } 373 default: { // Parent process (actual driver) 374 // Wait on child process to finish compiling the source. 375 int status = 0; 376 pid_t w = waitpid(pid, &status, 0); 377 if (w == -1) { 378 ALOGE("Could not wait for bcc compiler"); 379 return false; 380 } 381 382 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 383 return true; 384 } 385 386 ALOGE("bcc compiler terminated unexpectedly"); 387 return false; 388 } 389 } 390} 391 392const static char *LD_EXE_PATH = "/system/bin/ld.mc"; 393 394static bool createSharedLib(const char *cacheDir, const char *resName) { 395 std::string sharedLibName = findSharedObjectName(cacheDir, resName); 396 std::string objFileName = cacheDir; 397 objFileName.append("/"); 398 objFileName.append(resName); 399 objFileName.append(".o"); 400 401 const char *compiler_rt = SYSLIBPATH"/libcompiler_rt.so"; 402 std::vector<const char *> args = { 403 LD_EXE_PATH, 404 "-shared", 405 "-nostdlib", 406 compiler_rt, 407 "-mtriple", DEFAULT_TARGET_TRIPLE_STRING, 408 "-L", SYSLIBPATH, 409 "-lRSDriver", "-lm", "-lc", 410 objFileName.c_str(), 411 "-o", sharedLibName.c_str(), 412 nullptr 413 }; 414 415 std::string cmdLineStr = bcc::getCommandLine(args.size()-1, args.data()); 416 417 pid_t pid = fork(); 418 419 switch (pid) { 420 case -1: { // Error occurred (we attempt no recovery) 421 ALOGE("Couldn't fork for linker (%s) execution", LD_EXE_PATH); 422 return false; 423 } 424 case 0: { // Child process 425 ALOGV("Invoking ld.mc with args '%s'", cmdLineStr.c_str()); 426 execv(LD_EXE_PATH, (char* const*) args.data()); 427 428 ALOGE("execv() failed: %s", strerror(errno)); 429 abort(); 430 return false; 431 } 432 default: { // Parent process (actual driver) 433 // Wait on child process to finish compiling the source. 434 int status = 0; 435 pid_t w = waitpid(pid, &status, 0); 436 if (w == -1) { 437 ALOGE("Could not wait for linker (%s)", LD_EXE_PATH); 438 return false; 439 } 440 441 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 442 return true; 443 } 444 445 ALOGE("Linker (%s) terminated unexpectedly", LD_EXE_PATH); 446 return false; 447 } 448 } 449} 450#endif // !defined(RS_COMPATIBILITY_LIB) 451} // namespace 452 453namespace android { 454namespace renderscript { 455 456#define MAXLINE 500 457#define MAKE_STR_HELPER(S) #S 458#define MAKE_STR(S) MAKE_STR_HELPER(S) 459#define EXPORT_VAR_STR "exportVarCount: " 460#define EXPORT_FUNC_STR "exportFuncCount: " 461#define EXPORT_FOREACH_STR "exportForEachCount: " 462#define OBJECT_SLOT_STR "objectSlotCount: " 463 464// Copy up to a newline or size chars from str -> s, updating str 465// Returns s when successful and nullptr when '\0' is finally reached. 466static char* strgets(char *s, int size, const char **ppstr) { 467 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) { 468 return nullptr; 469 } 470 471 int i; 472 for (i = 0; i < (size - 1); i++) { 473 s[i] = **ppstr; 474 (*ppstr)++; 475 if (s[i] == '\0') { 476 return s; 477 } else if (s[i] == '\n') { 478 s[i+1] = '\0'; 479 return s; 480 } 481 } 482 483 // size has been exceeded. 484 s[i] = '\0'; 485 486 return s; 487} 488 489RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) { 490 mCtx = ctx; 491 mScript = s; 492 493 mScriptSO = nullptr; 494 495 mInvokeFunctions = nullptr; 496 mForEachFunctions = nullptr; 497 mFieldAddress = nullptr; 498 mFieldIsObject = nullptr; 499 mForEachSignatures = nullptr; 500 501#ifndef RS_COMPATIBILITY_LIB 502 mCompilerDriver = nullptr; 503 mExecutable = nullptr; 504#endif 505 506 507 mRoot = nullptr; 508 mRootExpand = nullptr; 509 mInit = nullptr; 510 mFreeChildren = nullptr; 511 512 513 mBoundAllocs = nullptr; 514 mIntrinsicData = nullptr; 515 mIsThreadable = true; 516} 517 518bool RsdCpuScriptImpl::storeRSInfoFromSO() { 519 char line[MAXLINE]; 520 size_t varCount = 0; 521 size_t funcCount = 0; 522 size_t forEachCount = 0; 523 size_t objectSlotCount = 0; 524 525 mRoot = (RootFunc_t) dlsym(mScriptSO, "root"); 526 if (mRoot) { 527 //ALOGE("Found root(): %p", mRoot); 528 } 529 mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand"); 530 if (mRootExpand) { 531 //ALOGE("Found root.expand(): %p", mRootExpand); 532 } 533 mInit = (InvokeFunc_t) dlsym(mScriptSO, "init"); 534 if (mInit) { 535 //ALOGE("Found init(): %p", mInit); 536 } 537 mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor"); 538 if (mFreeChildren) { 539 //ALOGE("Found .rs.dtor(): %p", mFreeChildren); 540 } 541 542 const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info"); 543 if (rsInfo) { 544 //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo); 545 } 546 547 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 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 == nullptr) { 562 goto error; 563 } 564 memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject)); 565 mFieldAddress = new void*[varCount]; 566 if (mFieldAddress == nullptr) { 567 goto error; 568 } 569 for (size_t i = 0; i < varCount; ++i) { 570 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 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] == nullptr) { 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 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 591 goto error; 592 } 593 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) { 594 ALOGE("Invalid export func count!: %s", line); 595 goto error; 596 } 597 598 mExportedFunctionCount = funcCount; 599 //ALOGE("funcCount: %zu", funcCount); 600 601 if (funcCount > 0) { 602 mInvokeFunctions = new InvokeFunc_t[funcCount]; 603 if (mInvokeFunctions == nullptr) { 604 goto error; 605 } 606 for (size_t i = 0; i < funcCount; ++i) { 607 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 608 goto error; 609 } 610 char *c = strrchr(line, '\n'); 611 if (c) { 612 *c = '\0'; 613 } 614 615 mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line); 616 if (mInvokeFunctions[i] == nullptr) { 617 ALOGE("Failed to get function address for %s(): %s", 618 line, dlerror()); 619 goto error; 620 } 621 else { 622 //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]); 623 } 624 } 625 } 626 627 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 628 goto error; 629 } 630 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) { 631 ALOGE("Invalid export forEach count!: %s", line); 632 goto error; 633 } 634 635 if (forEachCount > 0) { 636 637 mForEachSignatures = new uint32_t[forEachCount]; 638 if (mForEachSignatures == nullptr) { 639 goto error; 640 } 641 mForEachFunctions = new ForEachFunc_t[forEachCount]; 642 if (mForEachFunctions == nullptr) { 643 goto error; 644 } 645 for (size_t i = 0; i < forEachCount; ++i) { 646 unsigned int tmpSig = 0; 647 char tmpName[MAXLINE]; 648 649 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 650 goto error; 651 } 652 if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s", 653 &tmpSig, tmpName) != 2) { 654 ALOGE("Invalid export forEach!: %s", line); 655 goto error; 656 } 657 658 // Lookup the expanded ForEach kernel. 659 strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName)); 660 mForEachSignatures[i] = tmpSig; 661 mForEachFunctions[i] = 662 (ForEachFunc_t) dlsym(mScriptSO, tmpName); 663 if (i != 0 && mForEachFunctions[i] == nullptr) { 664 // Ignore missing root.expand functions. 665 // root() is always specified at location 0. 666 ALOGE("Failed to find forEach function address for %s: %s", 667 tmpName, dlerror()); 668 goto error; 669 } 670 else { 671 //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]); 672 } 673 } 674 } 675 676 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 677 goto error; 678 } 679 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) { 680 ALOGE("Invalid object slot count!: %s", line); 681 goto error; 682 } 683 684 if (objectSlotCount > 0) { 685 rsAssert(varCount > 0); 686 for (size_t i = 0; i < objectSlotCount; ++i) { 687 uint32_t varNum = 0; 688 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 689 goto error; 690 } 691 if (sscanf(line, "%u", &varNum) != 1) { 692 ALOGE("Invalid object slot!: %s", line); 693 goto error; 694 } 695 696 if (varNum < varCount) { 697 mFieldIsObject[varNum] = true; 698 } 699 } 700 } 701 702 if (varCount > 0) { 703 mBoundAllocs = new Allocation *[varCount]; 704 memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs)); 705 } 706 707 if (mScriptSO == (void*)1) { 708 //rsdLookupRuntimeStub(script, "acos"); 709 } 710 711 return true; 712 713error: 714 delete[] mInvokeFunctions; 715 delete[] mForEachFunctions; 716 delete[] mFieldAddress; 717 delete[] mFieldIsObject; 718 delete[] mForEachSignatures; 719 delete[] mBoundAllocs; 720 721 return false; 722} 723 724#ifndef RS_COMPATIBILITY_LIB 725bool RsdCpuScriptImpl::storeRSInfoFromObj(bcinfo::MetadataExtractor &bitcodeMetadata) { 726 727 mExecutable->setThreadable(mIsThreadable); 728 if (!mExecutable->syncInfo()) { 729 ALOGW("bcc: FAILS to synchronize the RS info file to the disk"); 730 } 731 732 mRoot = reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root")); 733 mRootExpand = 734 reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root.expand")); 735 mInit = reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress("init")); 736 mFreeChildren = 737 reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress(".rs.dtor")); 738 739 740 if (bitcodeMetadata.getExportVarCount()) { 741 mBoundAllocs = new Allocation *[bitcodeMetadata.getExportVarCount()]; 742 memset(mBoundAllocs, 0, sizeof(void *) * bitcodeMetadata.getExportVarCount()); 743 } 744 745 for (size_t i = 0; i < bitcodeMetadata.getExportForEachSignatureCount(); i++) { 746 char* name = new char[strlen(bitcodeMetadata.getExportForEachNameList()[i]) + 1]; 747 mExportedForEachFuncList.push_back( 748 std::make_pair(name, bitcodeMetadata.getExportForEachSignatureList()[i])); 749 } 750 751 return true; 752} 753#endif 754 755bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir, 756 uint8_t const *bitcode, size_t bitcodeSize, 757 uint32_t flags, char const *bccPluginName) { 758 //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc); 759 //ALOGE("rsdScriptInit %p %p", rsc, script); 760 761 mCtx->lockMutex(); 762#ifndef RS_COMPATIBILITY_LIB 763 bool useRSDebugContext = false; 764 765 mCompilerDriver = nullptr; 766 mExecutable = nullptr; 767 768 mCompilerDriver = new bcc::RSCompilerDriver(); 769 if (mCompilerDriver == nullptr) { 770 ALOGE("bcc: FAILS to create compiler driver (out of memory)"); 771 mCtx->unlockMutex(); 772 return false; 773 } 774 775 // Configure symbol resolvers (via compiler-rt and the RS runtime). 776 mRSRuntime.setLookupFunction(lookupRuntimeStub); 777 mRSRuntime.setContext(this); 778 mResolver.chainResolver(mCompilerRuntime); 779 mResolver.chainResolver(mRSRuntime); 780 781 // Run any compiler setup functions we have been provided with. 782 RSSetupCompilerCallback setupCompilerCallback = 783 mCtx->getSetupCompilerCallback(); 784 if (setupCompilerCallback != nullptr) { 785 setupCompilerCallback(mCompilerDriver); 786 } 787 788 bcinfo::MetadataExtractor bitcodeMetadata((const char *) bitcode, bitcodeSize); 789 if (!bitcodeMetadata.extract()) { 790 ALOGE("Could not extract metadata from bitcode"); 791 mCtx->unlockMutex(); 792 return false; 793 } 794 795 const char* core_lib = findCoreLib(bitcodeMetadata, (const char*)bitcode, bitcodeSize); 796 797 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) { 798 mCompilerDriver->setDebugContext(true); 799 useRSDebugContext = true; 800 } 801 802 std::string bcFileName(cacheDir); 803 bcFileName.append("/"); 804 bcFileName.append(resName); 805 bcFileName.append(".bc"); 806 807 std::vector<const char*> compileArguments; 808 setCompileArguments(&compileArguments, bcFileName, cacheDir, resName, core_lib, 809 useRSDebugContext, bccPluginName); 810 // The last argument of compileArguments ia a nullptr, so remove 1 from the size. 811 std::string compileCommandLine = 812 bcc::getCommandLine(compileArguments.size() - 1, compileArguments.data()); 813 814 if (is_skip_linkloader()) { 815 if (!is_force_recompile()) { 816 mScriptSO = loadSharedLibrary(cacheDir, resName); 817 } 818 } 819 else if (!is_force_recompile()) { 820 // Load the compiled script that's in the cache, if any. 821 mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode, 822 bitcodeSize, compileCommandLine.c_str(), 823 mResolver); 824 } 825 826 // If we can't, it's either not there or out of date. We compile the bit code and try loading 827 // again. 828 if (is_skip_linkloader()) { 829 if (mScriptSO == nullptr) { 830 if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize, 831 compileArguments.data(), compileCommandLine)) 832 { 833 ALOGE("bcc: FAILS to compile '%s'", resName); 834 mCtx->unlockMutex(); 835 return false; 836 } 837 838 if (!createSharedLib(cacheDir, resName)) { 839 ALOGE("Linker: Failed to link object file '%s'", resName); 840 mCtx->unlockMutex(); 841 return false; 842 } 843 844 mScriptSO = loadSharedLibrary(cacheDir, resName); 845 if (mScriptSO == nullptr) { 846 ALOGE("Unable to load '%s'", resName); 847 mCtx->unlockMutex(); 848 return false; 849 } 850 } 851 } 852 else if (mExecutable == nullptr) { 853 if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize, compileArguments.data(), 854 compileCommandLine)) { 855 ALOGE("bcc: FAILS to compile '%s'", resName); 856 mCtx->unlockMutex(); 857 return false; 858 } 859 mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode, 860 bitcodeSize, compileCommandLine.c_str(), 861 mResolver); 862 if (mExecutable == nullptr) { 863 ALOGE("bcc: FAILS to load freshly compiled executable for '%s'", resName); 864 mCtx->unlockMutex(); 865 return false; 866 } 867 } 868 869 // if using the shared object path, read RS symbol information 870 // from the .so. Otherwise, read from the object files 871 if (!is_skip_linkloader()) { 872 storeRSInfoFromObj(bitcodeMetadata); 873 } 874 else { 875 if ( !mScriptSO) { 876 goto error; 877 } 878 879 if ( !storeRSInfoFromSO()) { 880 goto error; 881 } 882 } 883#else // RS_COMPATIBILITY_LIB is defined 884 885 mScriptSO = loadSharedLibrary(cacheDir, resName); 886 887 if (!mScriptSO) { 888 goto error; 889 } 890 891 if (!storeRSInfoFromSO()) { 892 goto error; 893 } 894#endif 895 mCtx->unlockMutex(); 896 return true; 897 898error: 899 900 mCtx->unlockMutex(); 901 if (mScriptSO) { 902 dlclose(mScriptSO); 903 } 904 return false; 905} 906 907#ifndef RS_COMPATIBILITY_LIB 908 909const char* RsdCpuScriptImpl::findCoreLib(const bcinfo::MetadataExtractor& ME, const char* bitcode, 910 size_t bitcodeSize) { 911 const char* defaultLib = SYSLIBPATH"/libclcore.bc"; 912 913 // If we're debugging, use the debug library. 914 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) { 915 return SYSLIBPATH"/libclcore_debug.bc"; 916 } 917 918 // If a callback has been registered to specify a library, use that. 919 RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback(); 920 if (selectRTCallback != nullptr) { 921 return selectRTCallback((const char*)bitcode, bitcodeSize); 922 } 923 924 // Check for a platform specific library 925#if defined(ARCH_ARM_HAVE_NEON) && !defined(DISABLE_CLCORE_NEON) 926 enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision(); 927 if (prec == bcinfo::RS_FP_Relaxed) { 928 // NEON-capable ARMv7a devices can use an accelerated math library 929 // for all reduced precision scripts. 930 // ARMv8 does not use NEON, as ASIMD can be used with all precision 931 // levels. 932 return SYSLIBPATH"/libclcore_neon.bc"; 933 } else { 934 return defaultLib; 935 } 936#elif defined(__i386__) || defined(__x86_64__) 937 // x86 devices will use an optimized library. 938 return SYSLIBPATH"/libclcore_x86.bc"; 939#else 940 return defaultLib; 941#endif 942} 943 944#endif 945 946void RsdCpuScriptImpl::populateScript(Script *script) { 947#ifndef RS_COMPATIBILITY_LIB 948 // Copy info over to runtime 949 if (!is_skip_linkloader()) { 950 script->mHal.info.exportedFunctionCount = mExecutable->getExportFuncAddrs().size(); 951 script->mHal.info.exportedVariableCount = mExecutable->getExportVarAddrs().size(); 952 script->mHal.info.exportedForeachFuncList = &mExportedForEachFuncList[0]; 953 script->mHal.info.exportedPragmaCount = mExecutable->getPragmaKeys().size(); 954 script->mHal.info.exportedPragmaKeyList = 955 const_cast<const char**>(&mExecutable->getPragmaKeys().front()); 956 script->mHal.info.exportedPragmaValueList = 957 const_cast<const char**>(&mExecutable->getPragmaValues().front()); 958 959 if (mRootExpand) { 960 script->mHal.info.root = mRootExpand; 961 } else { 962 script->mHal.info.root = mRoot; 963 } 964 } 965 else { 966 // Copy info over to runtime 967 script->mHal.info.exportedFunctionCount = mExportedFunctionCount; 968 script->mHal.info.exportedVariableCount = mExportedVariableCount; 969 script->mHal.info.exportedPragmaCount = 0; 970 script->mHal.info.exportedPragmaKeyList = 0; 971 script->mHal.info.exportedPragmaValueList = 0; 972 973 // Bug, need to stash in metadata 974 if (mRootExpand) { 975 script->mHal.info.root = mRootExpand; 976 } else { 977 script->mHal.info.root = mRoot; 978 } 979 } 980#else 981 // Copy info over to runtime 982 script->mHal.info.exportedFunctionCount = mExportedFunctionCount; 983 script->mHal.info.exportedVariableCount = mExportedVariableCount; 984 script->mHal.info.exportedPragmaCount = 0; 985 script->mHal.info.exportedPragmaKeyList = 0; 986 script->mHal.info.exportedPragmaValueList = 0; 987 988 // Bug, need to stash in metadata 989 if (mRootExpand) { 990 script->mHal.info.root = mRootExpand; 991 } else { 992 script->mHal.info.root = mRoot; 993 } 994#endif 995} 996 997 998typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t); 999 1000void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation ** ains, 1001 uint32_t inLen, 1002 Allocation * aout, 1003 const void * usr, uint32_t usrLen, 1004 const RsScriptCall *sc, 1005 MTLaunchStruct *mtls) { 1006 1007 memset(mtls, 0, sizeof(MTLaunchStruct)); 1008 1009 for (int index = inLen; --index >= 0;) { 1010 const Allocation* ain = ains[index]; 1011 1012 // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface 1013 if (ain != nullptr && 1014 (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == nullptr) { 1015 1016 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, 1017 "rsForEach called with null in allocations"); 1018 return; 1019 } 1020 } 1021 1022 if (aout && 1023 (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == nullptr) { 1024 1025 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, 1026 "rsForEach called with null out allocations"); 1027 return; 1028 } 1029 1030 if (inLen > 0) { 1031 const Allocation *ain0 = ains[0]; 1032 const Type *inType = ain0->getType(); 1033 1034 mtls->fep.dimX = inType->getDimX(); 1035 mtls->fep.dimY = inType->getDimY(); 1036 mtls->fep.dimZ = inType->getDimZ(); 1037 1038 for (int Index = inLen; --Index >= 1;) { 1039 if (!ain0->hasSameDims(ains[Index])) { 1040 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, 1041 "Failed to launch kernel; dimensions of input and output allocations do not match."); 1042 1043 return; 1044 } 1045 } 1046 1047 } else if (aout != nullptr) { 1048 const Type *outType = aout->getType(); 1049 1050 mtls->fep.dimX = outType->getDimX(); 1051 mtls->fep.dimY = outType->getDimY(); 1052 mtls->fep.dimZ = outType->getDimZ(); 1053 1054 } else { 1055 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, 1056 "rsForEach called with null allocations"); 1057 return; 1058 } 1059 1060 if (inLen > 0 && aout != nullptr) { 1061 if (!ains[0]->hasSameDims(aout)) { 1062 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, 1063 "Failed to launch kernel; dimensions of input and output allocations do not match."); 1064 1065 return; 1066 } 1067 } 1068 1069 if (!sc || (sc->xEnd == 0)) { 1070 mtls->xEnd = mtls->fep.dimX; 1071 } else { 1072 rsAssert(sc->xStart < mtls->fep.dimX); 1073 rsAssert(sc->xEnd <= mtls->fep.dimX); 1074 rsAssert(sc->xStart < sc->xEnd); 1075 mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart); 1076 mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd); 1077 if (mtls->xStart >= mtls->xEnd) return; 1078 } 1079 1080 if (!sc || (sc->yEnd == 0)) { 1081 mtls->yEnd = mtls->fep.dimY; 1082 } else { 1083 rsAssert(sc->yStart < mtls->fep.dimY); 1084 rsAssert(sc->yEnd <= mtls->fep.dimY); 1085 rsAssert(sc->yStart < sc->yEnd); 1086 mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart); 1087 mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd); 1088 if (mtls->yStart >= mtls->yEnd) return; 1089 } 1090 1091 if (!sc || (sc->zEnd == 0)) { 1092 mtls->zEnd = mtls->fep.dimZ; 1093 } else { 1094 rsAssert(sc->zStart < mtls->fep.dimZ); 1095 rsAssert(sc->zEnd <= mtls->fep.dimZ); 1096 rsAssert(sc->zStart < sc->zEnd); 1097 mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart); 1098 mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd); 1099 if (mtls->zStart >= mtls->zEnd) return; 1100 } 1101 1102 mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd); 1103 mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd); 1104 mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd); 1105 mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd); 1106 1107 rsAssert(inLen == 0 || (ains[0]->getType()->getDimZ() == 0)); 1108 1109 mtls->rsc = mCtx; 1110 mtls->ains = ains; 1111 mtls->aout = aout; 1112 mtls->fep.usr = usr; 1113 mtls->fep.usrLen = usrLen; 1114 mtls->mSliceSize = 1; 1115 mtls->mSliceNum = 0; 1116 1117 mtls->fep.inPtrs = nullptr; 1118 mtls->fep.inStrides = nullptr; 1119 mtls->isThreadable = mIsThreadable; 1120 1121 if (inLen > 0) { 1122 1123 if (inLen <= RS_KERNEL_INPUT_THRESHOLD) { 1124 mtls->fep.inPtrs = (const uint8_t**)mtls->inPtrsBuff; 1125 mtls->fep.inStrides = mtls->inStridesBuff; 1126 } else { 1127 mtls->fep.heapAllocatedArrays = true; 1128 1129 mtls->fep.inPtrs = new const uint8_t*[inLen]; 1130 mtls->fep.inStrides = new StridePair[inLen]; 1131 } 1132 1133 mtls->fep.inLen = inLen; 1134 1135 for (int index = inLen; --index >= 0;) { 1136 const Allocation *ain = ains[index]; 1137 1138 mtls->fep.inPtrs[index] = 1139 (const uint8_t*)ain->mHal.drvState.lod[0].mallocPtr; 1140 1141 mtls->fep.inStrides[index].eStride = 1142 ain->getType()->getElementSizeBytes(); 1143 mtls->fep.inStrides[index].yStride = 1144 ain->mHal.drvState.lod[0].stride; 1145 } 1146 } 1147 1148 mtls->fep.outPtr = nullptr; 1149 mtls->fep.outStride.eStride = 0; 1150 mtls->fep.outStride.yStride = 0; 1151 if (aout != nullptr) { 1152 mtls->fep.outPtr = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr; 1153 1154 mtls->fep.outStride.eStride = aout->getType()->getElementSizeBytes(); 1155 mtls->fep.outStride.yStride = aout->mHal.drvState.lod[0].stride; 1156 } 1157} 1158 1159 1160void RsdCpuScriptImpl::invokeForEach(uint32_t slot, 1161 const Allocation ** ains, 1162 uint32_t inLen, 1163 Allocation * aout, 1164 const void * usr, 1165 uint32_t usrLen, 1166 const RsScriptCall *sc) { 1167 1168 MTLaunchStruct mtls; 1169 1170 forEachMtlsSetup(ains, inLen, aout, usr, usrLen, sc, &mtls); 1171 forEachKernelSetup(slot, &mtls); 1172 1173 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 1174 mCtx->launchThreads(ains, inLen, aout, sc, &mtls); 1175 mCtx->setTLS(oldTLS); 1176} 1177 1178void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) { 1179 mtls->script = this; 1180 mtls->fep.slot = slot; 1181#ifndef RS_COMPATIBILITY_LIB 1182 if (!is_skip_linkloader()) { 1183 rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size()); 1184 mtls->kernel = reinterpret_cast<ForEachFunc_t>( 1185 mExecutable->getExportForeachFuncAddrs()[slot]); 1186 rsAssert(mtls->kernel != nullptr); 1187 mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second; 1188 } 1189 else { 1190 mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]); 1191 rsAssert(mtls->kernel != nullptr); 1192 mtls->sig = mForEachSignatures[slot]; 1193 } 1194#else 1195 mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]); 1196 rsAssert(mtls->kernel != nullptr); 1197 mtls->sig = mForEachSignatures[slot]; 1198#endif 1199} 1200 1201int RsdCpuScriptImpl::invokeRoot() { 1202 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 1203 int ret = mRoot(); 1204 mCtx->setTLS(oldTLS); 1205 return ret; 1206} 1207 1208void RsdCpuScriptImpl::invokeInit() { 1209 if (mInit) { 1210 mInit(); 1211 } 1212} 1213 1214void RsdCpuScriptImpl::invokeFreeChildren() { 1215 if (mFreeChildren) { 1216 mFreeChildren(); 1217 } 1218} 1219 1220void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params, 1221 size_t paramLength) { 1222 //ALOGE("invoke %i %p %zu", slot, params, paramLength); 1223 void * ap = nullptr; 1224 1225#if defined(__x86_64__) 1226 // The invoked function could have input parameter of vector type for example float4 which 1227 // requires void* params to be 16 bytes aligned when using SSE instructions for x86_64 platform. 1228 // So try to align void* params before passing them into RS exported function. 1229 1230 if ((uint8_t)(uint64_t)params & 0x0F) { 1231 if ((ap = (void*)memalign(16, paramLength)) != nullptr) { 1232 memcpy(ap, params, paramLength); 1233 } else { 1234 ALOGE("x86_64: invokeFunction memalign error, still use params which is not 16 bytes aligned."); 1235 } 1236 } 1237#endif 1238 1239 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 1240#ifndef RS_COMPATIBILITY_LIB 1241 if (! is_skip_linkloader()) { 1242 reinterpret_cast<void (*)(const void *, uint32_t)>( 1243 mExecutable->getExportFuncAddrs()[slot])( 1244 ap? (const void *) ap : params, paramLength); 1245 } 1246 else { 1247 reinterpret_cast<void (*)(const void *, uint32_t)>( 1248 mInvokeFunctions[slot])(ap? (const void *) ap: params, paramLength); 1249 } 1250#else 1251 reinterpret_cast<void (*)(const void *, uint32_t)>( 1252 mInvokeFunctions[slot])(ap? (const void *) ap: params, paramLength); 1253#endif 1254 1255 mCtx->setTLS(oldTLS); 1256} 1257 1258void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) { 1259 //rsAssert(!script->mFieldIsObject[slot]); 1260 //ALOGE("setGlobalVar %i %p %zu", slot, data, dataLength); 1261 1262 //if (mIntrinsicID) { 1263 //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength); 1264 //return; 1265 //} 1266 1267#ifndef RS_COMPATIBILITY_LIB 1268 int32_t *destPtr = nullptr; 1269 if (!is_skip_linkloader()) { 1270 destPtr = reinterpret_cast<int32_t *>( 1271 mExecutable->getExportVarAddrs()[slot]); 1272 } 1273 else { 1274 destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1275 } 1276#else 1277 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1278#endif 1279 if (!destPtr) { 1280 //ALOGV("Calling setVar on slot = %i which is null", slot); 1281 return; 1282 } 1283 1284 memcpy(destPtr, data, dataLength); 1285} 1286 1287void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) { 1288 //rsAssert(!script->mFieldIsObject[slot]); 1289 //ALOGE("getGlobalVar %i %p %zu", slot, data, dataLength); 1290 1291#ifndef RS_COMPATIBILITY_LIB 1292 int32_t *srcPtr = nullptr; 1293 if (!is_skip_linkloader()) { 1294 srcPtr = reinterpret_cast<int32_t *>( 1295 mExecutable->getExportVarAddrs()[slot]); 1296 } 1297 else { 1298 srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1299 } 1300#else 1301 int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1302#endif 1303 if (!srcPtr) { 1304 //ALOGV("Calling setVar on slot = %i which is null", slot); 1305 return; 1306 } 1307 memcpy(data, srcPtr, dataLength); 1308} 1309 1310 1311void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength, 1312 const Element *elem, 1313 const uint32_t *dims, size_t dimLength) { 1314 1315#ifndef RS_COMPATIBILITY_LIB 1316 int32_t *destPtr = nullptr; 1317 if (!is_skip_linkloader()) { 1318 destPtr = reinterpret_cast<int32_t *>( 1319 mExecutable->getExportVarAddrs()[slot]); 1320 } 1321 else { 1322 destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1323 } 1324#else 1325 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1326#endif 1327 if (!destPtr) { 1328 //ALOGV("Calling setVar on slot = %i which is null", slot); 1329 return; 1330 } 1331 1332 // We want to look at dimension in terms of integer components, 1333 // but dimLength is given in terms of bytes. 1334 dimLength /= sizeof(int); 1335 1336 // Only a single dimension is currently supported. 1337 rsAssert(dimLength == 1); 1338 if (dimLength == 1) { 1339 // First do the increment loop. 1340 size_t stride = elem->getSizeBytes(); 1341 const char *cVal = reinterpret_cast<const char *>(data); 1342 for (uint32_t i = 0; i < dims[0]; i++) { 1343 elem->incRefs(cVal); 1344 cVal += stride; 1345 } 1346 1347 // Decrement loop comes after (to prevent race conditions). 1348 char *oldVal = reinterpret_cast<char *>(destPtr); 1349 for (uint32_t i = 0; i < dims[0]; i++) { 1350 elem->decRefs(oldVal); 1351 oldVal += stride; 1352 } 1353 } 1354 1355 memcpy(destPtr, data, dataLength); 1356} 1357 1358void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) { 1359 1360 //rsAssert(!script->mFieldIsObject[slot]); 1361 //ALOGE("setGlobalBind %i %p", slot, data); 1362 1363#ifndef RS_COMPATIBILITY_LIB 1364 int32_t *destPtr = nullptr; 1365 if (!is_skip_linkloader()) { 1366 destPtr = reinterpret_cast<int32_t *>( 1367 mExecutable->getExportVarAddrs()[slot]); 1368 } 1369 else { 1370 destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1371 } 1372#else 1373 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1374#endif 1375 if (!destPtr) { 1376 //ALOGV("Calling setVar on slot = %i which is null", slot); 1377 return; 1378 } 1379 1380 void *ptr = nullptr; 1381 mBoundAllocs[slot] = data; 1382 if (data) { 1383 ptr = data->mHal.drvState.lod[0].mallocPtr; 1384 } 1385 memcpy(destPtr, &ptr, sizeof(void *)); 1386} 1387 1388void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) { 1389 1390 //rsAssert(script->mFieldIsObject[slot]); 1391 //ALOGE("setGlobalObj %i %p", slot, data); 1392 1393#ifndef RS_COMPATIBILITY_LIB 1394 int32_t *destPtr = nullptr; 1395 if (!is_skip_linkloader()) { 1396 destPtr = reinterpret_cast<int32_t *>( 1397 mExecutable->getExportVarAddrs()[slot]); 1398 } 1399 else { 1400 destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1401 } 1402#else 1403 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1404#endif 1405 1406 if (!destPtr) { 1407 //ALOGV("Calling setVar on slot = %i which is null", slot); 1408 return; 1409 } 1410 1411 rsrSetObject(mCtx->getContext(), (rs_object_base *)destPtr, data); 1412} 1413 1414RsdCpuScriptImpl::~RsdCpuScriptImpl() { 1415#ifndef RS_COMPATIBILITY_LIB 1416 if (mExecutable) { 1417 std::vector<void *>::const_iterator var_addr_iter = 1418 mExecutable->getExportVarAddrs().begin(); 1419 std::vector<void *>::const_iterator var_addr_end = 1420 mExecutable->getExportVarAddrs().end(); 1421 1422 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter = 1423 mExecutable->getInfo().getObjectSlots().begin(); 1424 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end = 1425 mExecutable->getInfo().getObjectSlots().end(); 1426 1427 while ((var_addr_iter != var_addr_end) && 1428 (is_object_iter != is_object_end)) { 1429 // The field address can be nullptr if the script-side has optimized 1430 // the corresponding global variable away. 1431 rs_object_base *obj_addr = 1432 reinterpret_cast<rs_object_base *>(*var_addr_iter); 1433 if (*is_object_iter) { 1434 if (*var_addr_iter != nullptr && mCtx->getContext() != nullptr) { 1435 rsrClearObject(mCtx->getContext(), obj_addr); 1436 } 1437 } 1438 var_addr_iter++; 1439 is_object_iter++; 1440 } 1441 } 1442 1443 if (mCompilerDriver) { 1444 delete mCompilerDriver; 1445 } 1446 if (mExecutable) { 1447 delete mExecutable; 1448 } 1449 if (mBoundAllocs) { 1450 delete[] mBoundAllocs; 1451 } 1452 1453 for (size_t i = 0; i < mExportedForEachFuncList.size(); i++) { 1454 delete[] mExportedForEachFuncList[i].first; 1455 } 1456 1457 if (mFieldIsObject) { 1458 for (size_t i = 0; i < mExportedVariableCount; ++i) { 1459 if (mFieldIsObject[i]) { 1460 if (mFieldAddress[i] != nullptr) { 1461 rs_object_base *obj_addr = 1462 reinterpret_cast<rs_object_base *>(mFieldAddress[i]); 1463 rsrClearObject(mCtx->getContext(), obj_addr); 1464 } 1465 } 1466 } 1467 } 1468 1469 if (is_skip_linkloader()) { 1470 if (mInvokeFunctions) delete[] mInvokeFunctions; 1471 if (mForEachFunctions) delete[] mForEachFunctions; 1472 if (mFieldAddress) delete[] mFieldAddress; 1473 if (mFieldIsObject) delete[] mFieldIsObject; 1474 if (mForEachSignatures) delete[] mForEachSignatures; 1475 } 1476 1477#else 1478 if (mFieldIsObject) { 1479 for (size_t i = 0; i < mExportedVariableCount; ++i) { 1480 if (mFieldIsObject[i]) { 1481 if (mFieldAddress[i] != nullptr) { 1482 rs_object_base *obj_addr = 1483 reinterpret_cast<rs_object_base *>(mFieldAddress[i]); 1484 rsrClearObject(mCtx->getContext(), obj_addr); 1485 } 1486 } 1487 } 1488 } 1489 1490 if (mInvokeFunctions) delete[] mInvokeFunctions; 1491 if (mForEachFunctions) delete[] mForEachFunctions; 1492 if (mFieldAddress) delete[] mFieldAddress; 1493 if (mFieldIsObject) delete[] mFieldIsObject; 1494 if (mForEachSignatures) delete[] mForEachSignatures; 1495 if (mBoundAllocs) delete[] mBoundAllocs; 1496 if (mScriptSO) { 1497 dlclose(mScriptSO); 1498 } 1499#endif 1500} 1501 1502Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const { 1503 if (!ptr) { 1504 return nullptr; 1505 } 1506 1507 for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) { 1508 Allocation *a = mBoundAllocs[ct]; 1509 if (!a) continue; 1510 if (a->mHal.drvState.lod[0].mallocPtr == ptr) { 1511 return a; 1512 } 1513 } 1514 ALOGE("rsGetAllocation, failed to find %p", ptr); 1515 return nullptr; 1516} 1517 1518void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation ** ains, 1519 uint32_t inLen, Allocation * aout, 1520 const void * usr, uint32_t usrLen, 1521 const RsScriptCall *sc) {} 1522 1523void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation ** ains, 1524 uint32_t inLen, Allocation * aout, 1525 const void * usr, uint32_t usrLen, 1526 const RsScriptCall *sc) {} 1527 1528 1529} 1530} 1531