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