1 /* 2 * Copyright (C) 2009-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 "rsContext.h" 18 #include "rsScriptC.h" 19 20 #if !defined(RS_COMPATIBILITY_LIB) && !defined(ANDROID_RS_SERIALIZE) 21 #include <bcinfo/BitcodeTranslator.h> 22 #include <bcinfo/BitcodeWrapper.h> 23 #endif 24 25 #include <sys/stat.h> 26 27 #include <sstream> 28 #include <string> 29 30 #ifdef _WIN32 31 /* Define the default path separator for the platform. */ 32 #define OS_PATH_SEPARATOR '\\' 33 #define OS_PATH_SEPARATOR_STR "\\" 34 35 #else /* not _WIN32 */ 36 37 /* Define the default path separator for the platform. */ 38 #define OS_PATH_SEPARATOR '/' 39 #define OS_PATH_SEPARATOR_STR "/" 40 41 #endif 42 43 using android::renderscript::ScriptC; 44 45 #define GET_TLS() Context::ScriptTLSStruct * tls = \ 46 (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \ 47 Context * rsc = tls->mContext; \ 48 ScriptC * sc = (ScriptC *) tls->mScript 49 50 ScriptC::ScriptC(Context *rsc) : Script(rsc) { 51 } 52 53 ScriptC::~ScriptC() { 54 if (mInitialized) { 55 mRSC->mHal.funcs.script.invokeFreeChildren(mRSC, this); 56 mRSC->mHal.funcs.script.destroy(mRSC, this); 57 } 58 } 59 60 #ifndef RS_COMPATIBILITY_LIB 61 bool ScriptC::createCacheDir(const char *cacheDir) { 62 std::string currentDir; 63 const std::string cacheDirString(cacheDir); 64 65 struct stat statBuf; 66 int statReturn = stat(cacheDir, &statBuf); 67 if (!statReturn) { 68 return true; 69 } 70 71 // Start from the beginning of the cacheDirString. 72 int currPos = 0; 73 74 // Reserve space in currentDir for the entire cacheDir path. 75 currentDir.reserve(cacheDirString.length()); 76 77 while (currPos >= 0) { 78 /* 79 * The character at currPos should be a path separator. We need to look 80 * for the next one. 81 */ 82 int nextPos = cacheDirString.find(OS_PATH_SEPARATOR, currPos + 1); 83 84 if (nextPos > 0) { 85 // A new path separator has been found. 86 currentDir += cacheDirString.substr(currPos, nextPos - currPos); 87 } else { 88 // There are no more path separators. 89 currentDir += cacheDirString.substr(currPos); 90 } 91 92 currPos = nextPos; 93 94 statReturn = stat(currentDir.c_str(), &statBuf); 95 96 if (statReturn) { 97 if (errno == ENOENT) { 98 if (mkdir(currentDir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) { 99 ALOGE("Couldn't create cache directory: %s", 100 currentDir.c_str()); 101 ALOGE("Error: %s", strerror(errno)); 102 return false; 103 } 104 } else { 105 ALOGE("Stat error: %s", strerror(errno)); 106 return false; 107 } 108 } 109 } 110 return true; 111 } 112 #endif 113 114 void ScriptC::setupScript(Context *rsc) { 115 mEnviroment.mStartTimeMillis 116 = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)); 117 118 for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) { 119 if (mSlots[ct].get() && !mTypes[ct].get()) { 120 mTypes[ct].set(mSlots[ct]->getType()); 121 } 122 123 if (!mTypes[ct].get()) 124 continue; 125 rsc->mHal.funcs.script.setGlobalBind(rsc, this, ct, mSlots[ct].get()); 126 } 127 } 128 129 void ScriptC::setupGLState(Context *rsc) { 130 #if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB) 131 if (mEnviroment.mFragmentStore.get()) { 132 rsc->setProgramStore(mEnviroment.mFragmentStore.get()); 133 } 134 if (mEnviroment.mFragment.get()) { 135 rsc->setProgramFragment(mEnviroment.mFragment.get()); 136 } 137 if (mEnviroment.mVertex.get()) { 138 rsc->setProgramVertex(mEnviroment.mVertex.get()); 139 } 140 if (mEnviroment.mRaster.get()) { 141 rsc->setProgramRaster(mEnviroment.mRaster.get()); 142 } 143 #endif 144 } 145 146 uint32_t ScriptC::run(Context *rsc) { 147 if (mHal.info.root == nullptr) { 148 rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script"); 149 return 0; 150 } 151 152 setupGLState(rsc); 153 setupScript(rsc); 154 155 uint32_t ret = 0; 156 157 if (rsc->props.mLogScripts) { 158 ALOGV("%p ScriptC::run invoking root, ptr %p", rsc, mHal.info.root); 159 } 160 161 ret = rsc->mHal.funcs.script.invokeRoot(rsc, this); 162 163 if (rsc->props.mLogScripts) { 164 ALOGV("%p ScriptC::run invoking complete, ret=%i", rsc, ret); 165 } 166 167 return ret; 168 } 169 170 171 void ScriptC::runForEach(Context *rsc, 172 uint32_t slot, 173 const Allocation ** ains, 174 size_t inLen, 175 Allocation * aout, 176 const void * usr, 177 size_t usrBytes, 178 const RsScriptCall *sc) { 179 if (slot >= mHal.info.exportedForEachCount) { 180 rsc->setError(RS_ERROR_BAD_SCRIPT, 181 "The forEach kernel index is out of bounds"); 182 return; 183 } 184 185 // Trace this function call. 186 // To avoid overhead we only build the string if tracing is actually 187 // enabled. 188 std::stringstream ss; 189 if (ATRACE_ENABLED()) { 190 ss << "runForEach slot[" << slot << "]"; 191 } 192 std::string msgStr(ss.str()); 193 ATRACE_NAME(msgStr.c_str()); 194 195 if (mRSC->hadFatalError()) return; 196 197 Context::PushState ps(rsc); 198 199 setupGLState(rsc); 200 setupScript(rsc); 201 202 if (rsc->props.mLogScripts) { 203 ALOGV("%p ScriptC::runForEach invoking slot %i, ptr %p", rsc, slot, this); 204 } 205 206 if (rsc->mHal.funcs.script.invokeForEachMulti != nullptr) { 207 rsc->mHal.funcs.script.invokeForEachMulti(rsc, this, slot, ains, inLen, 208 aout, usr, usrBytes, sc); 209 210 } else if (inLen == 1) { 211 rsc->mHal.funcs.script.invokeForEach(rsc, this, slot, ains[0], aout, 212 usr, usrBytes, sc); 213 214 } else { 215 rsc->setError(RS_ERROR_FATAL_DRIVER, 216 "Driver support for multi-input not present"); 217 } 218 } 219 220 void ScriptC::runReduce(Context *rsc, uint32_t slot, 221 const Allocation ** ains, size_t inLen, 222 Allocation *aout, const RsScriptCall *sc) { 223 // TODO: Record the name of the kernel in the tracing information. 224 ATRACE_CALL(); 225 226 if (slot >= mHal.info.exportedReduceCount) { 227 rsc->setError(RS_ERROR_BAD_SCRIPT, "The general reduce kernel index is out of bounds"); 228 return; 229 } 230 if (mRSC->hadFatalError()) return; 231 232 setupScript(rsc); 233 234 if (rsc->props.mLogScripts) { 235 ALOGV("%p ScriptC::runReduce invoking slot %i, ptr %p", rsc, slot, this); 236 } 237 238 rsc->mHal.funcs.script.invokeReduce(rsc, this, slot, ains, inLen, aout, sc); 239 } 240 241 void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) { 242 ATRACE_CALL(); 243 244 if (slot >= mHal.info.exportedFunctionCount) { 245 rsc->setError(RS_ERROR_BAD_SCRIPT, "The invokable index is out of bounds"); 246 return; 247 } 248 if (mRSC->hadFatalError()) return; 249 250 setupScript(rsc); 251 252 if (rsc->props.mLogScripts) { 253 ALOGV("%p ScriptC::Invoke invoking slot %i, ptr %p", rsc, slot, this); 254 } 255 rsc->mHal.funcs.script.invokeFunction(rsc, this, slot, data, len); 256 } 257 258 static const bool kDebugBitcode = false; 259 260 #ifndef RS_COMPATIBILITY_LIB 261 262 static bool dumpBitcodeFile(const char *cacheDir, const char *resName, 263 const char *suffix, const uint8_t *bitcode, 264 size_t bitcodeLen) { 265 std::string f(cacheDir); 266 f.append("/"); 267 f.append(resName); 268 f.append("#"); 269 f.append(suffix); 270 f.append(".bc"); 271 272 if (!ScriptC::createCacheDir(cacheDir)) { 273 return false; 274 } 275 276 FILE *fp = fopen(f.c_str(), "we"); 277 if (!fp) { 278 ALOGE("Could not open %s", f.c_str()); 279 return false; 280 } 281 282 size_t nWritten = fwrite(bitcode, 1, bitcodeLen, fp); 283 fclose(fp); 284 if (nWritten != bitcodeLen) { 285 ALOGE("Could not write %s", f.c_str()); 286 return false; 287 } 288 return true; 289 } 290 291 #endif // !RS_COMPATIBILITY_LIB 292 293 294 bool ScriptC::runCompiler(Context *rsc, 295 const char *resName, 296 const char *cacheDir, 297 const uint8_t *bitcode, 298 size_t bitcodeLen) { 299 ATRACE_CALL(); 300 //ALOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen); 301 #ifndef RS_COMPATIBILITY_LIB 302 uint32_t sdkVersion = 0; 303 bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeLen); 304 if (!bcWrapper.unwrap()) { 305 ALOGE("Bitcode is not in proper container format (raw or wrapper)"); 306 return false; 307 } 308 309 if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) { 310 sdkVersion = bcWrapper.getTargetAPI(); 311 } 312 313 if (sdkVersion == 0) { 314 // This signals that we didn't have a wrapper containing information 315 // about the bitcode. 316 sdkVersion = rsc->getTargetSdkVersion(); 317 } 318 319 // Save off the sdkVersion, so that we can handle broken cases later. 320 // Bug 19734267 321 mApiLevel = sdkVersion; 322 323 bcinfo::BitcodeTranslator BT((const char *)bitcode, bitcodeLen, 324 sdkVersion); 325 if (!BT.translate()) { 326 ALOGE("Failed to translate bitcode from version: %u", sdkVersion); 327 return false; 328 } 329 bitcode = (const uint8_t *) BT.getTranslatedBitcode(); 330 bitcodeLen = BT.getTranslatedBitcodeSize(); 331 332 if (kDebugBitcode) { 333 if (!dumpBitcodeFile(cacheDir, resName, "after", bitcode, bitcodeLen)) { 334 return false; 335 } 336 } 337 338 339 // Set the optimization level of bcc to be the same as the 340 // optimization level used to compile the bitcode. 341 rsc->setOptLevel(bcWrapper.getOptimizationLevel()); 342 343 if (!cacheDir) { 344 // MUST BE FIXED BEFORE ANYTHING USING C++ API IS RELEASED 345 cacheDir = getenv("EXTERNAL_STORAGE"); 346 ALOGV("Cache dir changed to %s", cacheDir); 347 } 348 349 // ensure that cache dir exists 350 if (cacheDir && !createCacheDir(cacheDir)) { 351 return false; 352 } 353 #endif 354 355 if (!rsc->mHal.funcs.script.init(rsc, this, resName, cacheDir, bitcode, bitcodeLen, 0)) { 356 return false; 357 } 358 359 mInitialized = true; 360 #if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB) 361 mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); 362 mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); 363 mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore()); 364 mEnviroment.mRaster.set(rsc->getDefaultProgramRaster()); 365 #endif 366 367 rsc->mHal.funcs.script.invokeInit(rsc, this); 368 369 for (size_t i=0; i < mHal.info.exportedPragmaCount; ++i) { 370 const char * key = mHal.info.exportedPragmaKeyList[i]; 371 const char * value = mHal.info.exportedPragmaValueList[i]; 372 //ALOGE("pragma %s %s", keys[i], values[i]); 373 if (!strcmp(key, "version")) { 374 if (!strcmp(value, "1")) { 375 continue; 376 } 377 ALOGE("Invalid version pragma value: %s\n", value); 378 return false; 379 } 380 381 #if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB) 382 if (!strcmp(key, "stateVertex")) { 383 if (!strcmp(value, "default")) { 384 continue; 385 } 386 if (!strcmp(value, "parent")) { 387 mEnviroment.mVertex.clear(); 388 continue; 389 } 390 ALOGE("Unrecognized value %s passed to stateVertex", value); 391 return false; 392 } 393 394 if (!strcmp(key, "stateRaster")) { 395 if (!strcmp(value, "default")) { 396 continue; 397 } 398 if (!strcmp(value, "parent")) { 399 mEnviroment.mRaster.clear(); 400 continue; 401 } 402 ALOGE("Unrecognized value %s passed to stateRaster", value); 403 return false; 404 } 405 406 if (!strcmp(key, "stateFragment")) { 407 if (!strcmp(value, "default")) { 408 continue; 409 } 410 if (!strcmp(value, "parent")) { 411 mEnviroment.mFragment.clear(); 412 continue; 413 } 414 ALOGE("Unrecognized value %s passed to stateFragment", value); 415 return false; 416 } 417 418 if (!strcmp(key, "stateStore")) { 419 if (!strcmp(value, "default")) { 420 continue; 421 } 422 if (!strcmp(value, "parent")) { 423 mEnviroment.mFragmentStore.clear(); 424 continue; 425 } 426 ALOGE("Unrecognized value %s passed to stateStore", value); 427 return false; 428 } 429 #endif 430 431 } 432 433 mSlots = new ObjectBaseRef<Allocation>[mHal.info.exportedVariableCount]; 434 mTypes = new ObjectBaseRef<const Type>[mHal.info.exportedVariableCount]; 435 436 return true; 437 } 438 439 namespace android { 440 namespace renderscript { 441 442 RsScript rsi_ScriptCCreate(Context *rsc, 443 const char *resName, size_t resName_length, 444 const char *cacheDir, size_t cacheDir_length, 445 const char *text, size_t text_length) 446 { 447 ScriptC *s = new ScriptC(rsc); 448 449 if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, text_length)) { 450 // Error during compile, destroy s and return null. 451 ObjectBase::checkDelete(s); 452 return nullptr; 453 } 454 455 s->incUserRef(); 456 return s; 457 } 458 459 } // namespace renderscript 460 } // namespace android 461