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