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 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 // 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 193void 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 208ScriptCState::ScriptCState() { 209} 210 211ScriptCState::~ScriptCState() { 212} 213 214/* 215static 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 241extern const char rs_runtime_lib_bc[]; 242extern unsigned rs_runtime_lib_bc_size; 243#endif 244 245bool 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 382namespace android { 383namespace renderscript { 384 385RsScript 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