rsCpuScript.cpp revision b5215a52df4402a8a513c3dc65d06b9bd46e879d
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 inline bool is_skip_linkloader() { 249 return true; 250} 251 252static bool is_force_recompile() { 253#ifdef RS_SERVER 254 return false; 255#else 256 char buf[PROPERTY_VALUE_MAX]; 257 258 // Re-compile if floating point precision has been overridden. 259 property_get("debug.rs.precision", buf, ""); 260 if (buf[0] != '\0') { 261 return true; 262 } 263 264 // Re-compile if debug.rs.forcerecompile is set. 265 property_get("debug.rs.forcerecompile", buf, "0"); 266 if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) { 267 return true; 268 } else { 269 return false; 270 } 271#endif // RS_SERVER 272} 273 274const static char *BCC_EXE_PATH = "/system/bin/bcc"; 275 276static void setCompileArguments(std::vector<const char*>* args, 277 const std::string& bcFileName, 278 const char* cacheDir, const char* resName, 279 const char* core_lib, bool useRSDebugContext, 280 const char* bccPluginName) { 281 rsAssert(cacheDir && resName && core_lib); 282 args->push_back(BCC_EXE_PATH); 283 args->push_back("-unroll-runtime"); 284 args->push_back("-scalarize-load-store"); 285 args->push_back("-o"); 286 args->push_back(resName); 287 args->push_back("-output_path"); 288 args->push_back(cacheDir); 289 args->push_back("-bclib"); 290 args->push_back(core_lib); 291 args->push_back("-mtriple"); 292 args->push_back(DEFAULT_TARGET_TRIPLE_STRING); 293 294 // Enable workaround for A53 codegen by default. 295#if defined(__aarch64__) && !defined(DISABLE_A53_WORKAROUND) 296 args->push_back("-aarch64-fix-cortex-a53-835769"); 297#endif 298 299 // Execute the bcc compiler. 300 if (useRSDebugContext) { 301 args->push_back("-rs-debug-ctx"); 302 } else { 303 // Only load additional libraries for compiles that don't use 304 // the debug context. 305 if (bccPluginName && strlen(bccPluginName) > 0) { 306 args->push_back("-load"); 307 args->push_back(bccPluginName); 308 } 309 } 310 311 if (is_skip_linkloader()) { 312 args->push_back("-fPIC"); 313 args->push_back("-embedRSInfo"); 314 } 315 316 args->push_back(bcFileName.c_str()); 317 args->push_back(nullptr); 318} 319 320static bool compileBitcode(const std::string &bcFileName, 321 const char *bitcode, 322 size_t bitcodeSize, 323 const char **compileArguments, 324 const std::string &compileCommandLine) { 325 rsAssert(bitcode && bitcodeSize); 326 327 FILE *bcfile = fopen(bcFileName.c_str(), "w"); 328 if (!bcfile) { 329 ALOGE("Could not write to %s", bcFileName.c_str()); 330 return false; 331 } 332 size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile); 333 fclose(bcfile); 334 if (nwritten != bitcodeSize) { 335 ALOGE("Could not write %zu bytes to %s", bitcodeSize, 336 bcFileName.c_str()); 337 return false; 338 } 339 340 pid_t pid = fork(); 341 342 switch (pid) { 343 case -1: { // Error occurred (we attempt no recovery) 344 ALOGE("Couldn't fork for bcc compiler execution"); 345 return false; 346 } 347 case 0: { // Child process 348 ALOGV("Invoking BCC with: %s", compileCommandLine.c_str()); 349 execv(BCC_EXE_PATH, (char* const*)compileArguments); 350 351 ALOGE("execv() failed: %s", strerror(errno)); 352 abort(); 353 return false; 354 } 355 default: { // Parent process (actual driver) 356 // Wait on child process to finish compiling the source. 357 int status = 0; 358 pid_t w = waitpid(pid, &status, 0); 359 if (w == -1) { 360 ALOGE("Could not wait for bcc compiler"); 361 return false; 362 } 363 364 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 365 return true; 366 } 367 368 ALOGE("bcc compiler terminated unexpectedly"); 369 return false; 370 } 371 } 372} 373 374const static char *LD_EXE_PATH = "/system/bin/ld.mc"; 375 376static bool createSharedLib(const char *cacheDir, const char *resName) { 377 std::string sharedLibName = findSharedObjectName(cacheDir, resName); 378 std::string objFileName = cacheDir; 379 objFileName.append("/"); 380 objFileName.append(resName); 381 objFileName.append(".o"); 382 383 const char *compiler_rt = SYSLIBPATH"/libcompiler_rt.so"; 384 std::vector<const char *> args = { 385 LD_EXE_PATH, 386 "-shared", 387 "-nostdlib", 388 compiler_rt, 389 "-mtriple", DEFAULT_TARGET_TRIPLE_STRING, 390 "-L", SYSLIBPATH, 391 "-lRSDriver", "-lm", "-lc", 392 objFileName.c_str(), 393 "-o", sharedLibName.c_str(), 394 nullptr 395 }; 396 397 std::string cmdLineStr = bcc::getCommandLine(args.size()-1, args.data()); 398 399 pid_t pid = fork(); 400 401 switch (pid) { 402 case -1: { // Error occurred (we attempt no recovery) 403 ALOGE("Couldn't fork for linker (%s) execution", LD_EXE_PATH); 404 return false; 405 } 406 case 0: { // Child process 407 ALOGV("Invoking ld.mc with args '%s'", cmdLineStr.c_str()); 408 execv(LD_EXE_PATH, (char* const*) args.data()); 409 410 ALOGE("execv() failed: %s", strerror(errno)); 411 abort(); 412 return false; 413 } 414 default: { // Parent process (actual driver) 415 // Wait on child process to finish compiling the source. 416 int status = 0; 417 pid_t w = waitpid(pid, &status, 0); 418 if (w == -1) { 419 ALOGE("Could not wait for linker (%s)", LD_EXE_PATH); 420 return false; 421 } 422 423 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 424 return true; 425 } 426 427 ALOGE("Linker (%s) terminated unexpectedly", LD_EXE_PATH); 428 return false; 429 } 430 } 431} 432#endif // !defined(RS_COMPATIBILITY_LIB) 433} // namespace 434 435namespace android { 436namespace renderscript { 437 438#define MAXLINE 500 439#define MAKE_STR_HELPER(S) #S 440#define MAKE_STR(S) MAKE_STR_HELPER(S) 441#define EXPORT_VAR_STR "exportVarCount: " 442#define EXPORT_FUNC_STR "exportFuncCount: " 443#define EXPORT_FOREACH_STR "exportForEachCount: " 444#define OBJECT_SLOT_STR "objectSlotCount: " 445 446// Copy up to a newline or size chars from str -> s, updating str 447// Returns s when successful and nullptr when '\0' is finally reached. 448static char* strgets(char *s, int size, const char **ppstr) { 449 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) { 450 return nullptr; 451 } 452 453 int i; 454 for (i = 0; i < (size - 1); i++) { 455 s[i] = **ppstr; 456 (*ppstr)++; 457 if (s[i] == '\0') { 458 return s; 459 } else if (s[i] == '\n') { 460 s[i+1] = '\0'; 461 return s; 462 } 463 } 464 465 // size has been exceeded. 466 s[i] = '\0'; 467 468 return s; 469} 470 471RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) { 472 mCtx = ctx; 473 mScript = s; 474 475 mScriptSO = nullptr; 476 477 mInvokeFunctions = nullptr; 478 mForEachFunctions = nullptr; 479 mFieldAddress = nullptr; 480 mFieldIsObject = nullptr; 481 mForEachSignatures = nullptr; 482 483#ifndef RS_COMPATIBILITY_LIB 484 mCompilerDriver = nullptr; 485 mExecutable = nullptr; 486#endif 487 488 489 mRoot = nullptr; 490 mRootExpand = nullptr; 491 mInit = nullptr; 492 mFreeChildren = nullptr; 493 494 495 mBoundAllocs = nullptr; 496 mIntrinsicData = nullptr; 497 mIsThreadable = true; 498} 499 500bool RsdCpuScriptImpl::storeRSInfoFromSO() { 501 char line[MAXLINE]; 502 size_t varCount = 0; 503 size_t funcCount = 0; 504 size_t forEachCount = 0; 505 size_t objectSlotCount = 0; 506 507 mRoot = (RootFunc_t) dlsym(mScriptSO, "root"); 508 if (mRoot) { 509 //ALOGE("Found root(): %p", mRoot); 510 } 511 mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand"); 512 if (mRootExpand) { 513 //ALOGE("Found root.expand(): %p", mRootExpand); 514 } 515 mInit = (InvokeFunc_t) dlsym(mScriptSO, "init"); 516 if (mInit) { 517 //ALOGE("Found init(): %p", mInit); 518 } 519 mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor"); 520 if (mFreeChildren) { 521 //ALOGE("Found .rs.dtor(): %p", mFreeChildren); 522 } 523 524 const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info"); 525 if (rsInfo) { 526 //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo); 527 } 528 529 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 530 goto error; 531 } 532 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) { 533 ALOGE("Invalid export var count!: %s", line); 534 goto error; 535 } 536 537 mExportedVariableCount = varCount; 538 //ALOGE("varCount: %zu", varCount); 539 if (varCount > 0) { 540 // Start by creating/zeroing this member, since we don't want to 541 // accidentally clean up invalid pointers later (if we error out). 542 mFieldIsObject = new bool[varCount]; 543 if (mFieldIsObject == nullptr) { 544 goto error; 545 } 546 memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject)); 547 mFieldAddress = new void*[varCount]; 548 if (mFieldAddress == nullptr) { 549 goto error; 550 } 551 for (size_t i = 0; i < varCount; ++i) { 552 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 553 goto error; 554 } 555 char *c = strrchr(line, '\n'); 556 if (c) { 557 *c = '\0'; 558 } 559 mFieldAddress[i] = dlsym(mScriptSO, line); 560 if (mFieldAddress[i] == nullptr) { 561 ALOGE("Failed to find variable address for %s: %s", 562 line, dlerror()); 563 // Not a critical error if we don't find a global variable. 564 } 565 else { 566 //ALOGE("Found variable %s at %p", line, 567 //mFieldAddress[i]); 568 } 569 } 570 } 571 572 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 573 goto error; 574 } 575 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) { 576 ALOGE("Invalid export func count!: %s", line); 577 goto error; 578 } 579 580 mExportedFunctionCount = funcCount; 581 //ALOGE("funcCount: %zu", funcCount); 582 583 if (funcCount > 0) { 584 mInvokeFunctions = new InvokeFunc_t[funcCount]; 585 if (mInvokeFunctions == nullptr) { 586 goto error; 587 } 588 for (size_t i = 0; i < funcCount; ++i) { 589 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 590 goto error; 591 } 592 char *c = strrchr(line, '\n'); 593 if (c) { 594 *c = '\0'; 595 } 596 597 mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line); 598 if (mInvokeFunctions[i] == nullptr) { 599 ALOGE("Failed to get function address for %s(): %s", 600 line, dlerror()); 601 goto error; 602 } 603 else { 604 //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]); 605 } 606 } 607 } 608 609 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 610 goto error; 611 } 612 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) { 613 ALOGE("Invalid export forEach count!: %s", line); 614 goto error; 615 } 616 617 if (forEachCount > 0) { 618 619 mForEachSignatures = new uint32_t[forEachCount]; 620 if (mForEachSignatures == nullptr) { 621 goto error; 622 } 623 mForEachFunctions = new ForEachFunc_t[forEachCount]; 624 if (mForEachFunctions == nullptr) { 625 goto error; 626 } 627 for (size_t i = 0; i < forEachCount; ++i) { 628 unsigned int tmpSig = 0; 629 char tmpName[MAXLINE]; 630 631 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 632 goto error; 633 } 634 if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s", 635 &tmpSig, tmpName) != 2) { 636 ALOGE("Invalid export forEach!: %s", line); 637 goto error; 638 } 639 640 // Lookup the expanded ForEach kernel. 641 strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName)); 642 mForEachSignatures[i] = tmpSig; 643 mForEachFunctions[i] = 644 (ForEachFunc_t) dlsym(mScriptSO, tmpName); 645 if (i != 0 && mForEachFunctions[i] == nullptr) { 646 // Ignore missing root.expand functions. 647 // root() is always specified at location 0. 648 ALOGE("Failed to find forEach function address for %s: %s", 649 tmpName, dlerror()); 650 goto error; 651 } 652 else { 653 //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]); 654 } 655 } 656 } 657 658 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 659 goto error; 660 } 661 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) { 662 ALOGE("Invalid object slot count!: %s", line); 663 goto error; 664 } 665 666 if (objectSlotCount > 0) { 667 rsAssert(varCount > 0); 668 for (size_t i = 0; i < objectSlotCount; ++i) { 669 uint32_t varNum = 0; 670 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 671 goto error; 672 } 673 if (sscanf(line, "%u", &varNum) != 1) { 674 ALOGE("Invalid object slot!: %s", line); 675 goto error; 676 } 677 678 if (varNum < varCount) { 679 mFieldIsObject[varNum] = true; 680 } 681 } 682 } 683 684 if (varCount > 0) { 685 mBoundAllocs = new Allocation *[varCount]; 686 memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs)); 687 } 688 689 if (mScriptSO == (void*)1) { 690 //rsdLookupRuntimeStub(script, "acos"); 691 } 692 693 return true; 694 695error: 696 delete[] mInvokeFunctions; 697 delete[] mForEachFunctions; 698 delete[] mFieldAddress; 699 delete[] mFieldIsObject; 700 delete[] mForEachSignatures; 701 delete[] mBoundAllocs; 702 703 return false; 704} 705 706#ifndef RS_COMPATIBILITY_LIB 707bool RsdCpuScriptImpl::storeRSInfoFromObj(bcinfo::MetadataExtractor &bitcodeMetadata) { 708 709 mExecutable->setThreadable(mIsThreadable); 710 if (!mExecutable->syncInfo()) { 711 ALOGW("bcc: FAILS to synchronize the RS info file to the disk"); 712 } 713 714 mRoot = reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root")); 715 mRootExpand = 716 reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root.expand")); 717 mInit = reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress("init")); 718 mFreeChildren = 719 reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress(".rs.dtor")); 720 721 722 if (bitcodeMetadata.getExportVarCount()) { 723 mBoundAllocs = new Allocation *[bitcodeMetadata.getExportVarCount()]; 724 memset(mBoundAllocs, 0, sizeof(void *) * bitcodeMetadata.getExportVarCount()); 725 } 726 727 for (size_t i = 0; i < bitcodeMetadata.getExportForEachSignatureCount(); i++) { 728 char* name = new char[strlen(bitcodeMetadata.getExportForEachNameList()[i]) + 1]; 729 mExportedForEachFuncList.push_back( 730 std::make_pair(name, bitcodeMetadata.getExportForEachSignatureList()[i])); 731 } 732 733 return true; 734} 735#endif 736 737bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir, 738 uint8_t const *bitcode, size_t bitcodeSize, 739 uint32_t flags, char const *bccPluginName) { 740 //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc); 741 //ALOGE("rsdScriptInit %p %p", rsc, script); 742 743 mCtx->lockMutex(); 744#ifndef RS_COMPATIBILITY_LIB 745 bool useRSDebugContext = false; 746 747 mCompilerDriver = nullptr; 748 mExecutable = nullptr; 749 750 mCompilerDriver = new bcc::RSCompilerDriver(); 751 if (mCompilerDriver == nullptr) { 752 ALOGE("bcc: FAILS to create compiler driver (out of memory)"); 753 mCtx->unlockMutex(); 754 return false; 755 } 756 757 // Configure symbol resolvers (via compiler-rt and the RS runtime). 758 mRSRuntime.setLookupFunction(lookupRuntimeStub); 759 mRSRuntime.setContext(this); 760 mResolver.chainResolver(mCompilerRuntime); 761 mResolver.chainResolver(mRSRuntime); 762 763 // Run any compiler setup functions we have been provided with. 764 RSSetupCompilerCallback setupCompilerCallback = 765 mCtx->getSetupCompilerCallback(); 766 if (setupCompilerCallback != nullptr) { 767 setupCompilerCallback(mCompilerDriver); 768 } 769 770 bcinfo::MetadataExtractor bitcodeMetadata((const char *) bitcode, bitcodeSize); 771 if (!bitcodeMetadata.extract()) { 772 ALOGE("Could not extract metadata from bitcode"); 773 mCtx->unlockMutex(); 774 return false; 775 } 776 777 const char* core_lib = findCoreLib(bitcodeMetadata, (const char*)bitcode, bitcodeSize); 778 779 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) { 780 mCompilerDriver->setDebugContext(true); 781 useRSDebugContext = true; 782 } 783 784 std::string bcFileName(cacheDir); 785 bcFileName.append("/"); 786 bcFileName.append(resName); 787 bcFileName.append(".bc"); 788 789 std::vector<const char*> compileArguments; 790 setCompileArguments(&compileArguments, bcFileName, cacheDir, resName, core_lib, 791 useRSDebugContext, bccPluginName); 792 // The last argument of compileArguments ia a nullptr, so remove 1 from the size. 793 std::string compileCommandLine = 794 bcc::getCommandLine(compileArguments.size() - 1, compileArguments.data()); 795 796 if (is_skip_linkloader()) { 797 if (!is_force_recompile()) { 798 mScriptSO = loadSharedLibrary(cacheDir, resName); 799 } 800 } 801 else if (!is_force_recompile()) { 802 // Load the compiled script that's in the cache, if any. 803 mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode, 804 bitcodeSize, compileCommandLine.c_str(), 805 mResolver); 806 } 807 808 // If we can't, it's either not there or out of date. We compile the bit code and try loading 809 // again. 810 if (is_skip_linkloader()) { 811 if (mScriptSO == nullptr) { 812 if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize, 813 compileArguments.data(), compileCommandLine)) 814 { 815 ALOGE("bcc: FAILS to compile '%s'", resName); 816 mCtx->unlockMutex(); 817 return false; 818 } 819 820 if (!createSharedLib(cacheDir, resName)) { 821 ALOGE("Linker: Failed to link object file '%s'", resName); 822 mCtx->unlockMutex(); 823 return false; 824 } 825 826 mScriptSO = loadSharedLibrary(cacheDir, resName); 827 if (mScriptSO == nullptr) { 828 ALOGE("Unable to load '%s'", resName); 829 mCtx->unlockMutex(); 830 return false; 831 } 832 } 833 } 834 else if (mExecutable == nullptr) { 835 if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize, compileArguments.data(), 836 compileCommandLine)) { 837 ALOGE("bcc: FAILS to compile '%s'", resName); 838 mCtx->unlockMutex(); 839 return false; 840 } 841 mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode, 842 bitcodeSize, compileCommandLine.c_str(), 843 mResolver); 844 if (mExecutable == nullptr) { 845 ALOGE("bcc: FAILS to load freshly compiled executable for '%s'", resName); 846 mCtx->unlockMutex(); 847 return false; 848 } 849 } 850 851 // if using the shared object path, read RS symbol information 852 // from the .so. Otherwise, read from the object files 853 if (!is_skip_linkloader()) { 854 storeRSInfoFromObj(bitcodeMetadata); 855 } 856 else { 857 if ( !mScriptSO) { 858 goto error; 859 } 860 861 if ( !storeRSInfoFromSO()) { 862 goto error; 863 } 864 } 865#else // RS_COMPATIBILITY_LIB is defined 866 867 mScriptSO = loadSharedLibrary(cacheDir, resName); 868 869 if (!mScriptSO) { 870 goto error; 871 } 872 873 if (!storeRSInfoFromSO()) { 874 goto error; 875 } 876#endif 877 mCtx->unlockMutex(); 878 return true; 879 880error: 881 882 mCtx->unlockMutex(); 883 if (mScriptSO) { 884 dlclose(mScriptSO); 885 } 886 return false; 887} 888 889#ifndef RS_COMPATIBILITY_LIB 890 891const char* RsdCpuScriptImpl::findCoreLib(const bcinfo::MetadataExtractor& ME, const char* bitcode, 892 size_t bitcodeSize) { 893 const char* defaultLib = SYSLIBPATH"/libclcore.bc"; 894 895 // If we're debugging, use the debug library. 896 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) { 897 return SYSLIBPATH"/libclcore_debug.bc"; 898 } 899 900 // If a callback has been registered to specify a library, use that. 901 RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback(); 902 if (selectRTCallback != nullptr) { 903 return selectRTCallback((const char*)bitcode, bitcodeSize); 904 } 905 906 // Check for a platform specific library 907#if defined(ARCH_ARM_HAVE_NEON) && !defined(DISABLE_CLCORE_NEON) 908 enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision(); 909 if (prec == bcinfo::RS_FP_Relaxed) { 910 // NEON-capable ARMv7a devices can use an accelerated math library 911 // for all reduced precision scripts. 912 // ARMv8 does not use NEON, as ASIMD can be used with all precision 913 // levels. 914 return SYSLIBPATH"/libclcore_neon.bc"; 915 } else { 916 return defaultLib; 917 } 918#elif defined(__i386__) || defined(__x86_64__) 919 // x86 devices will use an optimized library. 920 return SYSLIBPATH"/libclcore_x86.bc"; 921#else 922 return defaultLib; 923#endif 924} 925 926#endif 927 928void RsdCpuScriptImpl::populateScript(Script *script) { 929#ifndef RS_COMPATIBILITY_LIB 930 // Copy info over to runtime 931 if (!is_skip_linkloader()) { 932 script->mHal.info.exportedFunctionCount = mExecutable->getExportFuncAddrs().size(); 933 script->mHal.info.exportedVariableCount = mExecutable->getExportVarAddrs().size(); 934 script->mHal.info.exportedForeachFuncList = &mExportedForEachFuncList[0]; 935 script->mHal.info.exportedPragmaCount = mExecutable->getPragmaKeys().size(); 936 script->mHal.info.exportedPragmaKeyList = 937 const_cast<const char**>(&mExecutable->getPragmaKeys().front()); 938 script->mHal.info.exportedPragmaValueList = 939 const_cast<const char**>(&mExecutable->getPragmaValues().front()); 940 941 if (mRootExpand) { 942 script->mHal.info.root = mRootExpand; 943 } else { 944 script->mHal.info.root = mRoot; 945 } 946 } 947 else { 948 // Copy info over to runtime 949 script->mHal.info.exportedFunctionCount = mExportedFunctionCount; 950 script->mHal.info.exportedVariableCount = mExportedVariableCount; 951 script->mHal.info.exportedPragmaCount = 0; 952 script->mHal.info.exportedPragmaKeyList = 0; 953 script->mHal.info.exportedPragmaValueList = 0; 954 955 // Bug, need to stash in metadata 956 if (mRootExpand) { 957 script->mHal.info.root = mRootExpand; 958 } else { 959 script->mHal.info.root = mRoot; 960 } 961 } 962#else 963 // Copy info over to runtime 964 script->mHal.info.exportedFunctionCount = mExportedFunctionCount; 965 script->mHal.info.exportedVariableCount = mExportedVariableCount; 966 script->mHal.info.exportedPragmaCount = 0; 967 script->mHal.info.exportedPragmaKeyList = 0; 968 script->mHal.info.exportedPragmaValueList = 0; 969 970 // Bug, need to stash in metadata 971 if (mRootExpand) { 972 script->mHal.info.root = mRootExpand; 973 } else { 974 script->mHal.info.root = mRoot; 975 } 976#endif 977} 978 979 980typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t); 981 982void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation ** ains, 983 uint32_t inLen, 984 Allocation * aout, 985 const void * usr, uint32_t usrLen, 986 const RsScriptCall *sc, 987 MTLaunchStruct *mtls) { 988 989 memset(mtls, 0, sizeof(MTLaunchStruct)); 990 991 for (int index = inLen; --index >= 0;) { 992 const Allocation* ain = ains[index]; 993 994 // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface 995 if (ain != nullptr && 996 (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == nullptr) { 997 998 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, 999 "rsForEach called with null in allocations"); 1000 return; 1001 } 1002 } 1003 1004 if (aout && 1005 (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == nullptr) { 1006 1007 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, 1008 "rsForEach called with null out allocations"); 1009 return; 1010 } 1011 1012 if (inLen > 0) { 1013 const Allocation *ain0 = ains[0]; 1014 const Type *inType = ain0->getType(); 1015 1016 mtls->fep.dimX = inType->getDimX(); 1017 mtls->fep.dimY = inType->getDimY(); 1018 mtls->fep.dimZ = inType->getDimZ(); 1019 1020 for (int Index = inLen; --Index >= 1;) { 1021 if (!ain0->hasSameDims(ains[Index])) { 1022 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, 1023 "Failed to launch kernel; dimensions of input and output allocations do not match."); 1024 1025 return; 1026 } 1027 } 1028 1029 } else if (aout != nullptr) { 1030 const Type *outType = aout->getType(); 1031 1032 mtls->fep.dimX = outType->getDimX(); 1033 mtls->fep.dimY = outType->getDimY(); 1034 mtls->fep.dimZ = outType->getDimZ(); 1035 1036 } else { 1037 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, 1038 "rsForEach called with null allocations"); 1039 return; 1040 } 1041 1042 if (inLen > 0 && aout != nullptr) { 1043 if (!ains[0]->hasSameDims(aout)) { 1044 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, 1045 "Failed to launch kernel; dimensions of input and output allocations do not match."); 1046 1047 return; 1048 } 1049 } 1050 1051 if (!sc || (sc->xEnd == 0)) { 1052 mtls->xEnd = mtls->fep.dimX; 1053 } else { 1054 rsAssert(sc->xStart < mtls->fep.dimX); 1055 rsAssert(sc->xEnd <= mtls->fep.dimX); 1056 rsAssert(sc->xStart < sc->xEnd); 1057 mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart); 1058 mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd); 1059 if (mtls->xStart >= mtls->xEnd) return; 1060 } 1061 1062 if (!sc || (sc->yEnd == 0)) { 1063 mtls->yEnd = mtls->fep.dimY; 1064 } else { 1065 rsAssert(sc->yStart < mtls->fep.dimY); 1066 rsAssert(sc->yEnd <= mtls->fep.dimY); 1067 rsAssert(sc->yStart < sc->yEnd); 1068 mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart); 1069 mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd); 1070 if (mtls->yStart >= mtls->yEnd) return; 1071 } 1072 1073 if (!sc || (sc->zEnd == 0)) { 1074 mtls->zEnd = mtls->fep.dimZ; 1075 } else { 1076 rsAssert(sc->zStart < mtls->fep.dimZ); 1077 rsAssert(sc->zEnd <= mtls->fep.dimZ); 1078 rsAssert(sc->zStart < sc->zEnd); 1079 mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart); 1080 mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd); 1081 if (mtls->zStart >= mtls->zEnd) return; 1082 } 1083 1084 mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd); 1085 mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd); 1086 mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd); 1087 mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd); 1088 1089 rsAssert(inLen == 0 || (ains[0]->getType()->getDimZ() == 0)); 1090 1091 mtls->rsc = mCtx; 1092 mtls->ains = ains; 1093 mtls->aout = aout; 1094 mtls->fep.usr = usr; 1095 mtls->fep.usrLen = usrLen; 1096 mtls->mSliceSize = 1; 1097 mtls->mSliceNum = 0; 1098 1099 mtls->fep.inPtrs = nullptr; 1100 mtls->fep.inStrides = nullptr; 1101 mtls->isThreadable = mIsThreadable; 1102 1103 if (inLen > 0) { 1104 1105 if (inLen <= RS_KERNEL_INPUT_THRESHOLD) { 1106 mtls->fep.inPtrs = (const uint8_t**)mtls->inPtrsBuff; 1107 mtls->fep.inStrides = mtls->inStridesBuff; 1108 } else { 1109 mtls->fep.heapAllocatedArrays = true; 1110 1111 mtls->fep.inPtrs = new const uint8_t*[inLen]; 1112 mtls->fep.inStrides = new StridePair[inLen]; 1113 } 1114 1115 mtls->fep.inLen = inLen; 1116 1117 for (int index = inLen; --index >= 0;) { 1118 const Allocation *ain = ains[index]; 1119 1120 mtls->fep.inPtrs[index] = 1121 (const uint8_t*)ain->mHal.drvState.lod[0].mallocPtr; 1122 1123 mtls->fep.inStrides[index].eStride = 1124 ain->getType()->getElementSizeBytes(); 1125 mtls->fep.inStrides[index].yStride = 1126 ain->mHal.drvState.lod[0].stride; 1127 } 1128 } 1129 1130 mtls->fep.outPtr = nullptr; 1131 mtls->fep.outStride.eStride = 0; 1132 mtls->fep.outStride.yStride = 0; 1133 if (aout != nullptr) { 1134 mtls->fep.outPtr = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr; 1135 1136 mtls->fep.outStride.eStride = aout->getType()->getElementSizeBytes(); 1137 mtls->fep.outStride.yStride = aout->mHal.drvState.lod[0].stride; 1138 } 1139} 1140 1141 1142void RsdCpuScriptImpl::invokeForEach(uint32_t slot, 1143 const Allocation ** ains, 1144 uint32_t inLen, 1145 Allocation * aout, 1146 const void * usr, 1147 uint32_t usrLen, 1148 const RsScriptCall *sc) { 1149 1150 MTLaunchStruct mtls; 1151 1152 forEachMtlsSetup(ains, inLen, aout, usr, usrLen, sc, &mtls); 1153 forEachKernelSetup(slot, &mtls); 1154 1155 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 1156 mCtx->launchThreads(ains, inLen, aout, sc, &mtls); 1157 mCtx->setTLS(oldTLS); 1158} 1159 1160void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) { 1161 mtls->script = this; 1162 mtls->fep.slot = slot; 1163#ifndef RS_COMPATIBILITY_LIB 1164 if (!is_skip_linkloader()) { 1165 rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size()); 1166 mtls->kernel = reinterpret_cast<ForEachFunc_t>( 1167 mExecutable->getExportForeachFuncAddrs()[slot]); 1168 rsAssert(mtls->kernel != nullptr); 1169 mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second; 1170 } 1171 else { 1172 mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]); 1173 rsAssert(mtls->kernel != nullptr); 1174 mtls->sig = mForEachSignatures[slot]; 1175 } 1176#else 1177 mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]); 1178 rsAssert(mtls->kernel != nullptr); 1179 mtls->sig = mForEachSignatures[slot]; 1180#endif 1181} 1182 1183int RsdCpuScriptImpl::invokeRoot() { 1184 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 1185 int ret = mRoot(); 1186 mCtx->setTLS(oldTLS); 1187 return ret; 1188} 1189 1190void RsdCpuScriptImpl::invokeInit() { 1191 if (mInit) { 1192 mInit(); 1193 } 1194} 1195 1196void RsdCpuScriptImpl::invokeFreeChildren() { 1197 if (mFreeChildren) { 1198 mFreeChildren(); 1199 } 1200} 1201 1202void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params, 1203 size_t paramLength) { 1204 //ALOGE("invoke %i %p %zu", slot, params, paramLength); 1205 void * ap = nullptr; 1206 1207#if defined(__x86_64__) 1208 // The invoked function could have input parameter of vector type for example float4 which 1209 // requires void* params to be 16 bytes aligned when using SSE instructions for x86_64 platform. 1210 // So try to align void* params before passing them into RS exported function. 1211 1212 if ((uint8_t)(uint64_t)params & 0x0F) { 1213 if ((ap = (void*)memalign(16, paramLength)) != nullptr) { 1214 memcpy(ap, params, paramLength); 1215 } else { 1216 ALOGE("x86_64: invokeFunction memalign error, still use params which is not 16 bytes aligned."); 1217 } 1218 } 1219#endif 1220 1221 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this); 1222#ifndef RS_COMPATIBILITY_LIB 1223 if (! is_skip_linkloader()) { 1224 reinterpret_cast<void (*)(const void *, uint32_t)>( 1225 mExecutable->getExportFuncAddrs()[slot])( 1226 ap? (const void *) ap : params, paramLength); 1227 } 1228 else { 1229 reinterpret_cast<void (*)(const void *, uint32_t)>( 1230 mInvokeFunctions[slot])(ap? (const void *) ap: params, paramLength); 1231 } 1232#else 1233 reinterpret_cast<void (*)(const void *, uint32_t)>( 1234 mInvokeFunctions[slot])(ap? (const void *) ap: params, paramLength); 1235#endif 1236 1237 mCtx->setTLS(oldTLS); 1238} 1239 1240void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) { 1241 //rsAssert(!script->mFieldIsObject[slot]); 1242 //ALOGE("setGlobalVar %i %p %zu", slot, data, dataLength); 1243 1244 //if (mIntrinsicID) { 1245 //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength); 1246 //return; 1247 //} 1248 1249#ifndef RS_COMPATIBILITY_LIB 1250 int32_t *destPtr = nullptr; 1251 if (!is_skip_linkloader()) { 1252 destPtr = reinterpret_cast<int32_t *>( 1253 mExecutable->getExportVarAddrs()[slot]); 1254 } 1255 else { 1256 destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1257 } 1258#else 1259 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1260#endif 1261 if (!destPtr) { 1262 //ALOGV("Calling setVar on slot = %i which is null", slot); 1263 return; 1264 } 1265 1266 memcpy(destPtr, data, dataLength); 1267} 1268 1269void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) { 1270 //rsAssert(!script->mFieldIsObject[slot]); 1271 //ALOGE("getGlobalVar %i %p %zu", slot, data, dataLength); 1272 1273#ifndef RS_COMPATIBILITY_LIB 1274 int32_t *srcPtr = nullptr; 1275 if (!is_skip_linkloader()) { 1276 srcPtr = reinterpret_cast<int32_t *>( 1277 mExecutable->getExportVarAddrs()[slot]); 1278 } 1279 else { 1280 srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1281 } 1282#else 1283 int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1284#endif 1285 if (!srcPtr) { 1286 //ALOGV("Calling setVar on slot = %i which is null", slot); 1287 return; 1288 } 1289 memcpy(data, srcPtr, dataLength); 1290} 1291 1292 1293void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength, 1294 const Element *elem, 1295 const uint32_t *dims, size_t dimLength) { 1296 1297#ifndef RS_COMPATIBILITY_LIB 1298 int32_t *destPtr = nullptr; 1299 if (!is_skip_linkloader()) { 1300 destPtr = reinterpret_cast<int32_t *>( 1301 mExecutable->getExportVarAddrs()[slot]); 1302 } 1303 else { 1304 destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1305 } 1306#else 1307 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1308#endif 1309 if (!destPtr) { 1310 //ALOGV("Calling setVar on slot = %i which is null", slot); 1311 return; 1312 } 1313 1314 // We want to look at dimension in terms of integer components, 1315 // but dimLength is given in terms of bytes. 1316 dimLength /= sizeof(int); 1317 1318 // Only a single dimension is currently supported. 1319 rsAssert(dimLength == 1); 1320 if (dimLength == 1) { 1321 // First do the increment loop. 1322 size_t stride = elem->getSizeBytes(); 1323 const char *cVal = reinterpret_cast<const char *>(data); 1324 for (uint32_t i = 0; i < dims[0]; i++) { 1325 elem->incRefs(cVal); 1326 cVal += stride; 1327 } 1328 1329 // Decrement loop comes after (to prevent race conditions). 1330 char *oldVal = reinterpret_cast<char *>(destPtr); 1331 for (uint32_t i = 0; i < dims[0]; i++) { 1332 elem->decRefs(oldVal); 1333 oldVal += stride; 1334 } 1335 } 1336 1337 memcpy(destPtr, data, dataLength); 1338} 1339 1340void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) { 1341 1342 //rsAssert(!script->mFieldIsObject[slot]); 1343 //ALOGE("setGlobalBind %i %p", slot, data); 1344 1345#ifndef RS_COMPATIBILITY_LIB 1346 int32_t *destPtr = nullptr; 1347 if (!is_skip_linkloader()) { 1348 destPtr = reinterpret_cast<int32_t *>( 1349 mExecutable->getExportVarAddrs()[slot]); 1350 } 1351 else { 1352 destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1353 } 1354#else 1355 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1356#endif 1357 if (!destPtr) { 1358 //ALOGV("Calling setVar on slot = %i which is null", slot); 1359 return; 1360 } 1361 1362 void *ptr = nullptr; 1363 mBoundAllocs[slot] = data; 1364 if (data) { 1365 ptr = data->mHal.drvState.lod[0].mallocPtr; 1366 } 1367 memcpy(destPtr, &ptr, sizeof(void *)); 1368} 1369 1370void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) { 1371 1372 //rsAssert(script->mFieldIsObject[slot]); 1373 //ALOGE("setGlobalObj %i %p", slot, data); 1374 1375#ifndef RS_COMPATIBILITY_LIB 1376 int32_t *destPtr = nullptr; 1377 if (!is_skip_linkloader()) { 1378 destPtr = reinterpret_cast<int32_t *>( 1379 mExecutable->getExportVarAddrs()[slot]); 1380 } 1381 else { 1382 destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1383 } 1384#else 1385 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]); 1386#endif 1387 1388 if (!destPtr) { 1389 //ALOGV("Calling setVar on slot = %i which is null", slot); 1390 return; 1391 } 1392 1393 rsrSetObject(mCtx->getContext(), (rs_object_base *)destPtr, data); 1394} 1395 1396RsdCpuScriptImpl::~RsdCpuScriptImpl() { 1397#ifndef RS_COMPATIBILITY_LIB 1398 if (mExecutable) { 1399 std::vector<void *>::const_iterator var_addr_iter = 1400 mExecutable->getExportVarAddrs().begin(); 1401 std::vector<void *>::const_iterator var_addr_end = 1402 mExecutable->getExportVarAddrs().end(); 1403 1404 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter = 1405 mExecutable->getInfo().getObjectSlots().begin(); 1406 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end = 1407 mExecutable->getInfo().getObjectSlots().end(); 1408 1409 while ((var_addr_iter != var_addr_end) && 1410 (is_object_iter != is_object_end)) { 1411 // The field address can be nullptr if the script-side has optimized 1412 // the corresponding global variable away. 1413 rs_object_base *obj_addr = 1414 reinterpret_cast<rs_object_base *>(*var_addr_iter); 1415 if (*is_object_iter) { 1416 if (*var_addr_iter != nullptr && mCtx->getContext() != nullptr) { 1417 rsrClearObject(mCtx->getContext(), obj_addr); 1418 } 1419 } 1420 var_addr_iter++; 1421 is_object_iter++; 1422 } 1423 } 1424 1425 if (mCompilerDriver) { 1426 delete mCompilerDriver; 1427 } 1428 if (mExecutable) { 1429 delete mExecutable; 1430 } 1431 if (mBoundAllocs) { 1432 delete[] mBoundAllocs; 1433 } 1434 1435 for (size_t i = 0; i < mExportedForEachFuncList.size(); i++) { 1436 delete[] mExportedForEachFuncList[i].first; 1437 } 1438 1439 if (mFieldIsObject) { 1440 for (size_t i = 0; i < mExportedVariableCount; ++i) { 1441 if (mFieldIsObject[i]) { 1442 if (mFieldAddress[i] != nullptr) { 1443 rs_object_base *obj_addr = 1444 reinterpret_cast<rs_object_base *>(mFieldAddress[i]); 1445 rsrClearObject(mCtx->getContext(), obj_addr); 1446 } 1447 } 1448 } 1449 } 1450 1451 if (is_skip_linkloader()) { 1452 if (mInvokeFunctions) delete[] mInvokeFunctions; 1453 if (mForEachFunctions) delete[] mForEachFunctions; 1454 if (mFieldAddress) delete[] mFieldAddress; 1455 if (mFieldIsObject) delete[] mFieldIsObject; 1456 if (mForEachSignatures) delete[] mForEachSignatures; 1457 } 1458 1459#else 1460 if (mFieldIsObject) { 1461 for (size_t i = 0; i < mExportedVariableCount; ++i) { 1462 if (mFieldIsObject[i]) { 1463 if (mFieldAddress[i] != nullptr) { 1464 rs_object_base *obj_addr = 1465 reinterpret_cast<rs_object_base *>(mFieldAddress[i]); 1466 rsrClearObject(mCtx->getContext(), obj_addr); 1467 } 1468 } 1469 } 1470 } 1471 1472 if (mInvokeFunctions) delete[] mInvokeFunctions; 1473 if (mForEachFunctions) delete[] mForEachFunctions; 1474 if (mFieldAddress) delete[] mFieldAddress; 1475 if (mFieldIsObject) delete[] mFieldIsObject; 1476 if (mForEachSignatures) delete[] mForEachSignatures; 1477 if (mBoundAllocs) delete[] mBoundAllocs; 1478 if (mScriptSO) { 1479 dlclose(mScriptSO); 1480 } 1481#endif 1482} 1483 1484Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const { 1485 if (!ptr) { 1486 return nullptr; 1487 } 1488 1489 for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) { 1490 Allocation *a = mBoundAllocs[ct]; 1491 if (!a) continue; 1492 if (a->mHal.drvState.lod[0].mallocPtr == ptr) { 1493 return a; 1494 } 1495 } 1496 ALOGE("rsGetAllocation, failed to find %p", ptr); 1497 return nullptr; 1498} 1499 1500void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation ** ains, 1501 uint32_t inLen, Allocation * aout, 1502 const void * usr, uint32_t usrLen, 1503 const RsScriptCall *sc) {} 1504 1505void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation ** ains, 1506 uint32_t inLen, Allocation * aout, 1507 const void * usr, uint32_t usrLen, 1508 const RsScriptCall *sc) {} 1509 1510 1511} 1512} 1513