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