rsScriptC.cpp revision 6847e73314e13aa02231268cca245a81eb0539ca
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 <string> 18 19#include "rsContext.h" 20#include "rsScriptC.h" 21 22#if !defined(RS_COMPATIBILITY_LIB) && !defined(ANDROID_RS_SERIALIZE) 23#include <bcinfo/BitcodeTranslator.h> 24#include <bcinfo/BitcodeWrapper.h> 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 34#ifdef USE_MINGW 35/* Define the default path separator for the platform. */ 36#define OS_PATH_SEPARATOR '\\' 37#define OS_PATH_SEPARATOR_STR "\\" 38 39#else /* not USE_MINGW */ 40 41/* Define the default path separator for the platform. */ 42#define OS_PATH_SEPARATOR '/' 43#define OS_PATH_SEPARATOR_STR "/" 44 45#endif 46 47using namespace android; 48using namespace android::renderscript; 49 50#define GET_TLS() Context::ScriptTLSStruct * tls = \ 51 (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \ 52 Context * rsc = tls->mContext; \ 53 ScriptC * sc = (ScriptC *) tls->mScript 54 55ScriptC::ScriptC(Context *rsc) : Script(rsc) { 56#if !defined(RS_COMPATIBILITY_LIB) && !defined(ANDROID_RS_SERIALIZE) 57 BT = NULL; 58#endif 59} 60 61ScriptC::~ScriptC() { 62#if !defined(RS_COMPATIBILITY_LIB) && !defined(ANDROID_RS_SERIALIZE) 63 if (BT) { 64 delete BT; 65 BT = NULL; 66 } 67#endif 68 if (mInitialized) { 69 mRSC->mHal.funcs.script.invokeFreeChildren(mRSC, this); 70 mRSC->mHal.funcs.script.destroy(mRSC, this); 71 } 72} 73 74#ifndef RS_COMPATIBILITY_LIB 75bool ScriptC::createCacheDir(const char *cacheDir) { 76 std::string currentDir; 77 const std::string cacheDirString(cacheDir); 78 79 struct stat statBuf; 80 int statReturn = stat(cacheDir, &statBuf); 81 if (!statReturn) { 82 return true; 83 } 84 85 // Start from the beginning of the cacheDirString. 86 int currPos = 0; 87 88 // Reserve space in currentDir for the entire cacheDir path. 89 currentDir.reserve(cacheDirString.length()); 90 91 while (currPos >= 0) { 92 /* 93 * The character at currPos should be a path separator. We need to look 94 * for the next one. 95 */ 96 int nextPos = cacheDirString.find(OS_PATH_SEPARATOR_STR, currPos + 1); 97 98 if (nextPos > 0) { 99 // A new path separator has been found. 100 currentDir += cacheDirString.substr(currPos, nextPos - currPos); 101 } else { 102 // There are no more path separators. 103 currentDir += cacheDirString.substr(currPos); 104 } 105 106 currPos = nextPos; 107 108 statReturn = stat(currentDir.c_str(), &statBuf); 109 110 if (statReturn) { 111 if (errno == ENOENT) { 112 if (mkdir(currentDir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) { 113 ALOGE("Couldn't create cache directory: %s", 114 currentDir.c_str()); 115 ALOGE("Error: %s", strerror(errno)); 116 return false; 117 } 118 } else { 119 ALOGE("Stat error: %s", strerror(errno)); 120 return false; 121 } 122 } 123 } 124 return true; 125} 126#endif 127 128void ScriptC::setupScript(Context *rsc) { 129#ifndef RS_SERVER 130 mEnviroment.mStartTimeMillis 131 = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)); 132#endif 133 134 for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) { 135 if (mSlots[ct].get() && !mTypes[ct].get()) { 136 mTypes[ct].set(mSlots[ct]->getType()); 137 } 138 139 if (!mTypes[ct].get()) 140 continue; 141 rsc->mHal.funcs.script.setGlobalBind(rsc, this, ct, mSlots[ct].get()); 142 } 143} 144 145void ScriptC::setupGLState(Context *rsc) { 146#ifndef RS_COMPATIBILITY_LIB 147 if (mEnviroment.mFragmentStore.get()) { 148 rsc->setProgramStore(mEnviroment.mFragmentStore.get()); 149 } 150 if (mEnviroment.mFragment.get()) { 151 rsc->setProgramFragment(mEnviroment.mFragment.get()); 152 } 153 if (mEnviroment.mVertex.get()) { 154 rsc->setProgramVertex(mEnviroment.mVertex.get()); 155 } 156 if (mEnviroment.mRaster.get()) { 157 rsc->setProgramRaster(mEnviroment.mRaster.get()); 158 } 159#endif 160} 161 162uint32_t ScriptC::run(Context *rsc) { 163 if (mHal.info.root == NULL) { 164 rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script"); 165 return 0; 166 } 167 168 setupGLState(rsc); 169 setupScript(rsc); 170 171 uint32_t ret = 0; 172 173 if (rsc->props.mLogScripts) { 174 ALOGV("%p ScriptC::run invoking root, ptr %p", rsc, mHal.info.root); 175 } 176 177 ret = rsc->mHal.funcs.script.invokeRoot(rsc, this); 178 179 if (rsc->props.mLogScripts) { 180 ALOGV("%p ScriptC::run invoking complete, ret=%i", rsc, ret); 181 } 182 183 return ret; 184} 185 186 187void ScriptC::runForEach(Context *rsc, 188 uint32_t slot, 189 const Allocation ** ains, 190 size_t inLen, 191 Allocation * aout, 192 const void * usr, 193 size_t usrBytes, 194 const RsScriptCall *sc) { 195 // Trace this function call. 196 // To avoid overhead we only build the string if tracing is actually 197 // enabled. 198 std::string *traceString = NULL; 199 const char *stringData = ""; 200 if (ATRACE_ENABLED()) { 201 traceString = new std::string("runForEach_"); 202 traceString->append(mHal.info.exportedForeachFuncList[slot].first); 203 stringData = traceString->c_str(); 204 } 205 ATRACE_NAME(stringData); 206 207 Context::PushState ps(rsc); 208 209 setupGLState(rsc); 210 setupScript(rsc); 211 212 if (rsc->mHal.funcs.script.invokeForEachMulti != NULL) { 213 rsc->mHal.funcs.script.invokeForEachMulti(rsc, this, slot, ains, inLen, 214 aout, usr, usrBytes, sc); 215 216 } else if (inLen == 1) { 217 rsc->mHal.funcs.script.invokeForEach(rsc, this, slot, ains[0], aout, 218 usr, usrBytes, sc); 219 220 } else { 221 rsc->setError(RS_ERROR_FATAL_DRIVER, 222 "Driver support for multi-input not present"); 223 } 224 225 if (traceString) { 226 delete traceString; 227 } 228} 229 230void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) { 231 ATRACE_CALL(); 232 233 if (slot >= mHal.info.exportedFunctionCount) { 234 rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script"); 235 return; 236 } 237 setupScript(rsc); 238 239 if (rsc->props.mLogScripts) { 240 ALOGV("%p ScriptC::Invoke invoking slot %i, ptr %p", rsc, slot, this); 241 } 242 rsc->mHal.funcs.script.invokeFunction(rsc, this, slot, data, len); 243} 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 285#endif 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