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