rsScriptC.cpp revision 0b575de8ed0b628d84d256f5846500b0385979bd
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 <sys/stat.h> 33 34using namespace android; 35using 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 42ScriptC::ScriptC(Context *rsc) : Script(rsc) { 43#ifndef RS_COMPATIBILITY_LIB 44#ifndef ANDROID_RS_SERIALIZE 45 BT = NULL; 46#endif 47#endif 48} 49 50ScriptC::~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 66bool 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 104void 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 121void 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 138uint32_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 163void 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 171 Context::PushState ps(rsc); 172 173 setupGLState(rsc); 174 setupScript(rsc); 175 rsc->mHal.funcs.script.invokeForEach(rsc, this, slot, ain, aout, usr, usrBytes, sc); 176} 177 178void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) { 179 if (slot >= mHal.info.exportedFunctionCount) { 180 rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script"); 181 return; 182 } 183 setupScript(rsc); 184 185 if (rsc->props.mLogScripts) { 186 ALOGV("%p ScriptC::Invoke invoking slot %i, ptr %p", rsc, slot, this); 187 } 188 rsc->mHal.funcs.script.invokeFunction(rsc, this, slot, data, len); 189} 190 191ScriptCState::ScriptCState() { 192} 193 194ScriptCState::~ScriptCState() { 195} 196 197/* 198static void* symbolLookup(void* pContext, char const* name) { 199 const ScriptCState::SymbolTable_t *sym; 200 ScriptC *s = (ScriptC *)pContext; 201 if (!strcmp(name, "__isThreadable")) { 202 return (void*) s->mHal.info.isThreadable; 203 } else if (!strcmp(name, "__clearThreadable")) { 204 s->mHal.info.isThreadable = false; 205 return NULL; 206 } 207 sym = ScriptCState::lookupSymbol(name); 208 if (!sym) { 209 sym = ScriptCState::lookupSymbolCL(name); 210 } 211 if (!sym) { 212 sym = ScriptCState::lookupSymbolGL(name); 213 } 214 if (sym) { 215 s->mHal.info.isThreadable &= sym->threadable; 216 return sym->mPtr; 217 } 218 ALOGE("ScriptC sym lookup failed for %s", name); 219 return NULL; 220} 221*/ 222 223#if 0 224extern const char rs_runtime_lib_bc[]; 225extern unsigned rs_runtime_lib_bc_size; 226#endif 227 228bool ScriptC::runCompiler(Context *rsc, 229 const char *resName, 230 const char *cacheDir, 231 const uint8_t *bitcode, 232 size_t bitcodeLen) { 233 234 //ALOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen); 235#ifndef RS_COMPATIBILITY_LIB 236#ifndef ANDROID_RS_SERIALIZE 237 uint32_t sdkVersion = 0; 238 bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeLen); 239 if (!bcWrapper.unwrap()) { 240 ALOGE("Bitcode is not in proper container format (raw or wrapper)"); 241 return false; 242 } 243 244 if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) { 245 sdkVersion = bcWrapper.getTargetAPI(); 246 } 247 248 if (sdkVersion == 0) { 249 // This signals that we didn't have a wrapper containing information 250 // about the bitcode. 251 sdkVersion = rsc->getTargetSdkVersion(); 252 } 253 254 if (BT) { 255 delete BT; 256 } 257 BT = new bcinfo::BitcodeTranslator((const char *)bitcode, bitcodeLen, 258 sdkVersion); 259 if (!BT->translate()) { 260 ALOGE("Failed to translate bitcode from version: %u", sdkVersion); 261 delete BT; 262 BT = NULL; 263 return false; 264 } 265 bitcode = (const uint8_t *) BT->getTranslatedBitcode(); 266 bitcodeLen = BT->getTranslatedBitcodeSize(); 267#endif 268 269 if (!cacheDir) { 270 // MUST BE FIXED BEFORE ANYTHING USING C++ API IS RELEASED 271 cacheDir = getenv("EXTERNAL_STORAGE"); 272 ALOGV("Cache dir changed to %s", cacheDir); 273 } 274 275 // ensure that cache dir exists 276 if (cacheDir && !createCacheDir(cacheDir)) { 277 return false; 278 } 279#endif 280 281 if (!rsc->mHal.funcs.script.init(rsc, this, resName, cacheDir, bitcode, bitcodeLen, 0)) { 282 return false; 283 } 284 285 mInitialized = true; 286#ifndef RS_COMPATIBILITY_LIB 287 mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); 288 mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); 289 mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore()); 290 mEnviroment.mRaster.set(rsc->getDefaultProgramRaster()); 291#endif 292 293 rsc->mHal.funcs.script.invokeInit(rsc, this); 294 295 for (size_t i=0; i < mHal.info.exportedPragmaCount; ++i) { 296 const char * key = mHal.info.exportedPragmaKeyList[i]; 297 const char * value = mHal.info.exportedPragmaValueList[i]; 298 //ALOGE("pragma %s %s", keys[i], values[i]); 299 if (!strcmp(key, "version")) { 300 if (!strcmp(value, "1")) { 301 continue; 302 } 303 ALOGE("Invalid version pragma value: %s\n", value); 304 return false; 305 } 306 307#ifndef RS_COMPATIBILITY_LIB 308 if (!strcmp(key, "stateVertex")) { 309 if (!strcmp(value, "default")) { 310 continue; 311 } 312 if (!strcmp(value, "parent")) { 313 mEnviroment.mVertex.clear(); 314 continue; 315 } 316 ALOGE("Unrecognized value %s passed to stateVertex", value); 317 return false; 318 } 319 320 if (!strcmp(key, "stateRaster")) { 321 if (!strcmp(value, "default")) { 322 continue; 323 } 324 if (!strcmp(value, "parent")) { 325 mEnviroment.mRaster.clear(); 326 continue; 327 } 328 ALOGE("Unrecognized value %s passed to stateRaster", value); 329 return false; 330 } 331 332 if (!strcmp(key, "stateFragment")) { 333 if (!strcmp(value, "default")) { 334 continue; 335 } 336 if (!strcmp(value, "parent")) { 337 mEnviroment.mFragment.clear(); 338 continue; 339 } 340 ALOGE("Unrecognized value %s passed to stateFragment", value); 341 return false; 342 } 343 344 if (!strcmp(key, "stateStore")) { 345 if (!strcmp(value, "default")) { 346 continue; 347 } 348 if (!strcmp(value, "parent")) { 349 mEnviroment.mFragmentStore.clear(); 350 continue; 351 } 352 ALOGE("Unrecognized value %s passed to stateStore", value); 353 return false; 354 } 355#endif 356 357 } 358 359 mSlots = new ObjectBaseRef<Allocation>[mHal.info.exportedVariableCount]; 360 mTypes = new ObjectBaseRef<const Type>[mHal.info.exportedVariableCount]; 361 362 return true; 363} 364 365namespace android { 366namespace renderscript { 367 368RsScript rsi_ScriptCCreate(Context *rsc, 369 const char *resName, size_t resName_length, 370 const char *cacheDir, size_t cacheDir_length, 371 const char *text, size_t text_length) 372{ 373 ScriptC *s = new ScriptC(rsc); 374 375 if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, text_length)) { 376 // Error during compile, destroy s and return null. 377 ObjectBase::checkDelete(s); 378 return NULL; 379 } 380 381 s->incUserRef(); 382 return s; 383} 384 385} 386} 387