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 #ifndef RS_COMPATIBILITY_LIB 21 #ifndef ANDROID_RS_SERIALIZE 22 #include <bcinfo/BitcodeTranslator.h> 23 #include <bcinfo/BitcodeWrapper.h> 24 #endif 25 #endif 26 27 #if !defined(RS_SERVER) && !defined(RS_COMPATIBILITY_LIB) 28 #include "utils/Timers.h" 29 #include "cutils/trace.h" 30 #endif 31 32 #include <sys/stat.h> 33 34 using namespace android; 35 using namespace android::renderscript; 36 37 #define GET_TLS() Context::ScriptTLSStruct * tls = \ 38 (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \ 39 Context * rsc = tls->mContext; \ 40 ScriptC * sc = (ScriptC *) tls->mScript 41 42 ScriptC::ScriptC(Context *rsc) : Script(rsc) { 43 #ifndef RS_COMPATIBILITY_LIB 44 #ifndef ANDROID_RS_SERIALIZE 45 BT = NULL; 46 #endif 47 #endif 48 } 49 50 ScriptC::~ScriptC() { 51 #ifndef RS_COMPATIBILITY_LIB 52 #ifndef ANDROID_RS_SERIALIZE 53 if (BT) { 54 delete BT; 55 BT = NULL; 56 } 57 #endif 58 #endif 59 if (mInitialized) { 60 mRSC->mHal.funcs.script.invokeFreeChildren(mRSC, this); 61 mRSC->mHal.funcs.script.destroy(mRSC, this); 62 } 63 } 64 65 #ifndef RS_COMPATIBILITY_LIB 66 bool ScriptC::createCacheDir(const char *cacheDir) { 67 String8 cacheDirString, currentDir; 68 struct stat statBuf; 69 int statReturn = stat(cacheDir, &statBuf); 70 if (!statReturn) { 71 return true; 72 } 73 74 // String8 path functions strip leading /'s 75 // insert if necessary 76 if (cacheDir[0] == '/') { 77 currentDir += "/"; 78 } 79 80 cacheDirString.setPathName(cacheDir); 81 82 while (cacheDirString.length()) { 83 currentDir += (cacheDirString.walkPath(&cacheDirString)); 84 statReturn = stat(currentDir.string(), &statBuf); 85 if (statReturn) { 86 if (errno == ENOENT) { 87 if (mkdir(currentDir.string(), S_IRUSR | S_IWUSR | S_IXUSR)) { 88 ALOGE("Couldn't create cache directory: %s", 89 currentDir.string()); 90 ALOGE("Error: %s", strerror(errno)); 91 return false; 92 } 93 } else { 94 ALOGE("Stat error: %s", strerror(errno)); 95 return false; 96 } 97 } 98 currentDir += "/"; 99 } 100 return true; 101 } 102 #endif 103 104 void ScriptC::setupScript(Context *rsc) { 105 #ifndef RS_SERVER 106 mEnviroment.mStartTimeMillis 107 = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)); 108 #endif 109 110 for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) { 111 if (mSlots[ct].get() && !mTypes[ct].get()) { 112 mTypes[ct].set(mSlots[ct]->getType()); 113 } 114 115 if (!mTypes[ct].get()) 116 continue; 117 rsc->mHal.funcs.script.setGlobalBind(rsc, this, ct, mSlots[ct].get()); 118 } 119 } 120 121 void ScriptC::setupGLState(Context *rsc) { 122 #ifndef RS_COMPATIBILITY_LIB 123 if (mEnviroment.mFragmentStore.get()) { 124 rsc->setProgramStore(mEnviroment.mFragmentStore.get()); 125 } 126 if (mEnviroment.mFragment.get()) { 127 rsc->setProgramFragment(mEnviroment.mFragment.get()); 128 } 129 if (mEnviroment.mVertex.get()) { 130 rsc->setProgramVertex(mEnviroment.mVertex.get()); 131 } 132 if (mEnviroment.mRaster.get()) { 133 rsc->setProgramRaster(mEnviroment.mRaster.get()); 134 } 135 #endif 136 } 137 138 uint32_t ScriptC::run(Context *rsc) { 139 if (mHal.info.root == NULL) { 140 rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script"); 141 return 0; 142 } 143 144 setupGLState(rsc); 145 setupScript(rsc); 146 147 uint32_t ret = 0; 148 149 if (rsc->props.mLogScripts) { 150 ALOGV("%p ScriptC::run invoking root, ptr %p", rsc, mHal.info.root); 151 } 152 153 ret = rsc->mHal.funcs.script.invokeRoot(rsc, this); 154 155 if (rsc->props.mLogScripts) { 156 ALOGV("%p ScriptC::run invoking complete, ret=%i", rsc, ret); 157 } 158 159 return ret; 160 } 161 162 163 void ScriptC::runForEach(Context *rsc, 164 uint32_t slot, 165 const Allocation * ain, 166 Allocation * aout, 167 const void * usr, 168 size_t usrBytes, 169 const RsScriptCall *sc) { 170 // Trace this function call. 171 // To avoid overhead, we only build the string, if tracing is actually 172 // enabled. 173 String8 *AString = NULL; 174 const char *String = ""; 175 if (ATRACE_ENABLED()) { 176 AString = new String8("runForEach_"); 177 AString->append(mHal.info.exportedForeachFuncList[slot].first); 178 String = AString->string(); 179 } 180 ATRACE_NAME(String); 181 (void)String; 182 183 Context::PushState ps(rsc); 184 185 setupGLState(rsc); 186 setupScript(rsc); 187 rsc->mHal.funcs.script.invokeForEach(rsc, this, slot, ain, aout, usr, usrBytes, sc); 188 189 if (AString) 190 delete AString; 191 } 192 193 void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) { 194 ATRACE_CALL(); 195 196 if (slot >= mHal.info.exportedFunctionCount) { 197 rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script"); 198 return; 199 } 200 setupScript(rsc); 201 202 if (rsc->props.mLogScripts) { 203 ALOGV("%p ScriptC::Invoke invoking slot %i, ptr %p", rsc, slot, this); 204 } 205 rsc->mHal.funcs.script.invokeFunction(rsc, this, slot, data, len); 206 } 207 208 ScriptCState::ScriptCState() { 209 } 210 211 ScriptCState::~ScriptCState() { 212 } 213 214 /* 215 static void* symbolLookup(void* pContext, char const* name) { 216 const ScriptCState::SymbolTable_t *sym; 217 ScriptC *s = (ScriptC *)pContext; 218 if (!strcmp(name, "__isThreadable")) { 219 return (void*) s->mHal.info.isThreadable; 220 } else if (!strcmp(name, "__clearThreadable")) { 221 s->mHal.info.isThreadable = false; 222 return NULL; 223 } 224 sym = ScriptCState::lookupSymbol(name); 225 if (!sym) { 226 sym = ScriptCState::lookupSymbolCL(name); 227 } 228 if (!sym) { 229 sym = ScriptCState::lookupSymbolGL(name); 230 } 231 if (sym) { 232 s->mHal.info.isThreadable &= sym->threadable; 233 return sym->mPtr; 234 } 235 ALOGE("ScriptC sym lookup failed for %s", name); 236 return NULL; 237 } 238 */ 239 240 #if 0 241 extern const char rs_runtime_lib_bc[]; 242 extern unsigned rs_runtime_lib_bc_size; 243 #endif 244 245 bool ScriptC::runCompiler(Context *rsc, 246 const char *resName, 247 const char *cacheDir, 248 const uint8_t *bitcode, 249 size_t bitcodeLen) { 250 ATRACE_CALL(); 251 //ALOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen); 252 #ifndef RS_COMPATIBILITY_LIB 253 #ifndef ANDROID_RS_SERIALIZE 254 uint32_t sdkVersion = 0; 255 bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeLen); 256 if (!bcWrapper.unwrap()) { 257 ALOGE("Bitcode is not in proper container format (raw or wrapper)"); 258 return false; 259 } 260 261 if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) { 262 sdkVersion = bcWrapper.getTargetAPI(); 263 } 264 265 if (sdkVersion == 0) { 266 // This signals that we didn't have a wrapper containing information 267 // about the bitcode. 268 sdkVersion = rsc->getTargetSdkVersion(); 269 } 270 271 if (BT) { 272 delete BT; 273 } 274 BT = new bcinfo::BitcodeTranslator((const char *)bitcode, bitcodeLen, 275 sdkVersion); 276 if (!BT->translate()) { 277 ALOGE("Failed to translate bitcode from version: %u", sdkVersion); 278 delete BT; 279 BT = NULL; 280 return false; 281 } 282 bitcode = (const uint8_t *) BT->getTranslatedBitcode(); 283 bitcodeLen = BT->getTranslatedBitcodeSize(); 284 #endif 285 286 if (!cacheDir) { 287 // MUST BE FIXED BEFORE ANYTHING USING C++ API IS RELEASED 288 cacheDir = getenv("EXTERNAL_STORAGE"); 289 ALOGV("Cache dir changed to %s", cacheDir); 290 } 291 292 // ensure that cache dir exists 293 if (cacheDir && !createCacheDir(cacheDir)) { 294 return false; 295 } 296 #endif 297 298 if (!rsc->mHal.funcs.script.init(rsc, this, resName, cacheDir, bitcode, bitcodeLen, 0)) { 299 return false; 300 } 301 302 mInitialized = true; 303 #ifndef RS_COMPATIBILITY_LIB 304 mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); 305 mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); 306 mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore()); 307 mEnviroment.mRaster.set(rsc->getDefaultProgramRaster()); 308 #endif 309 310 rsc->mHal.funcs.script.invokeInit(rsc, this); 311 312 for (size_t i=0; i < mHal.info.exportedPragmaCount; ++i) { 313 const char * key = mHal.info.exportedPragmaKeyList[i]; 314 const char * value = mHal.info.exportedPragmaValueList[i]; 315 //ALOGE("pragma %s %s", keys[i], values[i]); 316 if (!strcmp(key, "version")) { 317 if (!strcmp(value, "1")) { 318 continue; 319 } 320 ALOGE("Invalid version pragma value: %s\n", value); 321 return false; 322 } 323 324 #ifndef RS_COMPATIBILITY_LIB 325 if (!strcmp(key, "stateVertex")) { 326 if (!strcmp(value, "default")) { 327 continue; 328 } 329 if (!strcmp(value, "parent")) { 330 mEnviroment.mVertex.clear(); 331 continue; 332 } 333 ALOGE("Unrecognized value %s passed to stateVertex", value); 334 return false; 335 } 336 337 if (!strcmp(key, "stateRaster")) { 338 if (!strcmp(value, "default")) { 339 continue; 340 } 341 if (!strcmp(value, "parent")) { 342 mEnviroment.mRaster.clear(); 343 continue; 344 } 345 ALOGE("Unrecognized value %s passed to stateRaster", value); 346 return false; 347 } 348 349 if (!strcmp(key, "stateFragment")) { 350 if (!strcmp(value, "default")) { 351 continue; 352 } 353 if (!strcmp(value, "parent")) { 354 mEnviroment.mFragment.clear(); 355 continue; 356 } 357 ALOGE("Unrecognized value %s passed to stateFragment", value); 358 return false; 359 } 360 361 if (!strcmp(key, "stateStore")) { 362 if (!strcmp(value, "default")) { 363 continue; 364 } 365 if (!strcmp(value, "parent")) { 366 mEnviroment.mFragmentStore.clear(); 367 continue; 368 } 369 ALOGE("Unrecognized value %s passed to stateStore", value); 370 return false; 371 } 372 #endif 373 374 } 375 376 mSlots = new ObjectBaseRef<Allocation>[mHal.info.exportedVariableCount]; 377 mTypes = new ObjectBaseRef<const Type>[mHal.info.exportedVariableCount]; 378 379 return true; 380 } 381 382 namespace android { 383 namespace renderscript { 384 385 RsScript rsi_ScriptCCreate(Context *rsc, 386 const char *resName, size_t resName_length, 387 const char *cacheDir, size_t cacheDir_length, 388 const char *text, size_t text_length) 389 { 390 ScriptC *s = new ScriptC(rsc); 391 392 if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, text_length)) { 393 // Error during compile, destroy s and return null. 394 ObjectBase::checkDelete(s); 395 return NULL; 396 } 397 398 s->incUserRef(); 399 return s; 400 } 401 402 } 403 } 404