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