123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- /*
- * Copyright (C) 2009-2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "rsContext.h"
- #include "rsScriptC.h"
- #if !defined(RS_COMPATIBILITY_LIB) && !defined(ANDROID_RS_SERIALIZE)
- #include <bcinfo/BitcodeTranslator.h>
- #include <bcinfo/BitcodeWrapper.h>
- #endif
- #include <sys/stat.h>
- #include <sstream>
- #include <string>
- #ifdef _WIN32
- /* Define the default path separator for the platform. */
- #define OS_PATH_SEPARATOR '\\'
- #define OS_PATH_SEPARATOR_STR "\\"
- #else /* not _WIN32 */
- /* Define the default path separator for the platform. */
- #define OS_PATH_SEPARATOR '/'
- #define OS_PATH_SEPARATOR_STR "/"
- #endif
- using android::renderscript::ScriptC;
- #define GET_TLS() Context::ScriptTLSStruct * tls = \
- (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
- Context * rsc = tls->mContext; \
- ScriptC * sc = (ScriptC *) tls->mScript
- ScriptC::ScriptC(Context *rsc) : Script(rsc) {
- }
- ScriptC::~ScriptC() {
- if (mInitialized) {
- mRSC->mHal.funcs.script.invokeFreeChildren(mRSC, this);
- mRSC->mHal.funcs.script.destroy(mRSC, this);
- }
- }
- #ifndef RS_COMPATIBILITY_LIB
- bool ScriptC::createCacheDir(const char *cacheDir) {
- std::string currentDir;
- const std::string cacheDirString(cacheDir);
- struct stat statBuf;
- int statReturn = stat(cacheDir, &statBuf);
- if (!statReturn) {
- return true;
- }
- // Start from the beginning of the cacheDirString.
- int currPos = 0;
- // Reserve space in currentDir for the entire cacheDir path.
- currentDir.reserve(cacheDirString.length());
- while (currPos >= 0) {
- /*
- * The character at currPos should be a path separator. We need to look
- * for the next one.
- */
- int nextPos = cacheDirString.find(OS_PATH_SEPARATOR, currPos + 1);
- if (nextPos > 0) {
- // A new path separator has been found.
- currentDir += cacheDirString.substr(currPos, nextPos - currPos);
- } else {
- // There are no more path separators.
- currentDir += cacheDirString.substr(currPos);
- }
- currPos = nextPos;
- statReturn = stat(currentDir.c_str(), &statBuf);
- if (statReturn) {
- if (errno == ENOENT) {
- if (mkdir(currentDir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) {
- ALOGE("Couldn't create cache directory: %s",
- currentDir.c_str());
- ALOGE("Error: %s", strerror(errno));
- return false;
- }
- } else {
- ALOGE("Stat error: %s", strerror(errno));
- return false;
- }
- }
- }
- return true;
- }
- #endif
- void ScriptC::setupScript(Context *rsc) {
- mEnviroment.mStartTimeMillis
- = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
- for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) {
- if (mSlots[ct].get() && !mTypes[ct].get()) {
- mTypes[ct].set(mSlots[ct]->getType());
- }
- if (!mTypes[ct].get())
- continue;
- rsc->mHal.funcs.script.setGlobalBind(rsc, this, ct, mSlots[ct].get());
- }
- }
- void ScriptC::setupGLState(Context *rsc) {
- #if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
- if (mEnviroment.mFragmentStore.get()) {
- rsc->setProgramStore(mEnviroment.mFragmentStore.get());
- }
- if (mEnviroment.mFragment.get()) {
- rsc->setProgramFragment(mEnviroment.mFragment.get());
- }
- if (mEnviroment.mVertex.get()) {
- rsc->setProgramVertex(mEnviroment.mVertex.get());
- }
- if (mEnviroment.mRaster.get()) {
- rsc->setProgramRaster(mEnviroment.mRaster.get());
- }
- #endif
- }
- uint32_t ScriptC::run(Context *rsc) {
- if (mHal.info.root == nullptr) {
- rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
- return 0;
- }
- setupGLState(rsc);
- setupScript(rsc);
- uint32_t ret = 0;
- if (rsc->props.mLogScripts) {
- ALOGV("%p ScriptC::run invoking root, ptr %p", rsc, mHal.info.root);
- }
- ret = rsc->mHal.funcs.script.invokeRoot(rsc, this);
- if (rsc->props.mLogScripts) {
- ALOGV("%p ScriptC::run invoking complete, ret=%i", rsc, ret);
- }
- return ret;
- }
- void ScriptC::runForEach(Context *rsc,
- uint32_t slot,
- const Allocation ** ains,
- size_t inLen,
- Allocation * aout,
- const void * usr,
- size_t usrBytes,
- const RsScriptCall *sc) {
- if (slot >= mHal.info.exportedForEachCount) {
- rsc->setError(RS_ERROR_BAD_SCRIPT,
- "The forEach kernel index is out of bounds");
- return;
- }
- // Trace this function call.
- // To avoid overhead we only build the string if tracing is actually
- // enabled.
- std::stringstream ss;
- if (ATRACE_ENABLED()) {
- ss << "runForEach slot[" << slot << "]";
- }
- std::string msgStr(ss.str());
- ATRACE_NAME(msgStr.c_str());
- if (mRSC->hadFatalError()) return;
- Context::PushState ps(rsc);
- setupGLState(rsc);
- setupScript(rsc);
- if (rsc->props.mLogScripts) {
- ALOGV("%p ScriptC::runForEach invoking slot %i, ptr %p", rsc, slot, this);
- }
- if (rsc->mHal.funcs.script.invokeForEachMulti != nullptr) {
- rsc->mHal.funcs.script.invokeForEachMulti(rsc, this, slot, ains, inLen,
- aout, usr, usrBytes, sc);
- } else if (inLen == 1) {
- rsc->mHal.funcs.script.invokeForEach(rsc, this, slot, ains[0], aout,
- usr, usrBytes, sc);
- } else {
- rsc->setError(RS_ERROR_FATAL_DRIVER,
- "Driver support for multi-input not present");
- }
- }
- void ScriptC::runReduce(Context *rsc, uint32_t slot,
- const Allocation ** ains, size_t inLen,
- Allocation *aout, const RsScriptCall *sc) {
- // TODO: Record the name of the kernel in the tracing information.
- ATRACE_CALL();
- if (slot >= mHal.info.exportedReduceCount) {
- rsc->setError(RS_ERROR_BAD_SCRIPT, "The general reduce kernel index is out of bounds");
- return;
- }
- if (mRSC->hadFatalError()) return;
- setupScript(rsc);
- if (rsc->props.mLogScripts) {
- ALOGV("%p ScriptC::runReduce invoking slot %i, ptr %p", rsc, slot, this);
- }
- rsc->mHal.funcs.script.invokeReduce(rsc, this, slot, ains, inLen, aout, sc);
- }
- void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) {
- ATRACE_CALL();
- if (slot >= mHal.info.exportedFunctionCount) {
- rsc->setError(RS_ERROR_BAD_SCRIPT, "The invokable index is out of bounds");
- return;
- }
- if (mRSC->hadFatalError()) return;
- setupScript(rsc);
- if (rsc->props.mLogScripts) {
- ALOGV("%p ScriptC::Invoke invoking slot %i, ptr %p", rsc, slot, this);
- }
- rsc->mHal.funcs.script.invokeFunction(rsc, this, slot, data, len);
- }
- static const bool kDebugBitcode = false;
- #ifndef RS_COMPATIBILITY_LIB
- static bool dumpBitcodeFile(const char *cacheDir, const char *resName,
- const char *suffix, const uint8_t *bitcode,
- size_t bitcodeLen) {
- std::string f(cacheDir);
- f.append("/");
- f.append(resName);
- f.append("#");
- f.append(suffix);
- f.append(".bc");
- if (!ScriptC::createCacheDir(cacheDir)) {
- return false;
- }
- FILE *fp = fopen(f.c_str(), "we");
- if (!fp) {
- ALOGE("Could not open %s", f.c_str());
- return false;
- }
- size_t nWritten = fwrite(bitcode, 1, bitcodeLen, fp);
- fclose(fp);
- if (nWritten != bitcodeLen) {
- ALOGE("Could not write %s", f.c_str());
- return false;
- }
- return true;
- }
- #endif // !RS_COMPATIBILITY_LIB
- bool ScriptC::runCompiler(Context *rsc,
- const char *resName,
- const char *cacheDir,
- const uint8_t *bitcode,
- size_t bitcodeLen) {
- ATRACE_CALL();
- //ALOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen);
- #ifndef RS_COMPATIBILITY_LIB
- uint32_t sdkVersion = 0;
- bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeLen);
- if (!bcWrapper.unwrap()) {
- ALOGE("Bitcode is not in proper container format (raw or wrapper)");
- return false;
- }
- if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
- sdkVersion = bcWrapper.getTargetAPI();
- }
- if (sdkVersion == 0) {
- // This signals that we didn't have a wrapper containing information
- // about the bitcode.
- sdkVersion = rsc->getTargetSdkVersion();
- }
- // Save off the sdkVersion, so that we can handle broken cases later.
- // Bug 19734267
- mApiLevel = sdkVersion;
- bcinfo::BitcodeTranslator BT((const char *)bitcode, bitcodeLen,
- sdkVersion);
- if (!BT.translate()) {
- ALOGE("Failed to translate bitcode from version: %u", sdkVersion);
- return false;
- }
- bitcode = (const uint8_t *) BT.getTranslatedBitcode();
- bitcodeLen = BT.getTranslatedBitcodeSize();
- if (kDebugBitcode) {
- if (!dumpBitcodeFile(cacheDir, resName, "after", bitcode, bitcodeLen)) {
- return false;
- }
- }
- // Set the optimization level of bcc to be the same as the
- // optimization level used to compile the bitcode.
- rsc->setOptLevel(bcWrapper.getOptimizationLevel());
- if (!cacheDir) {
- // MUST BE FIXED BEFORE ANYTHING USING C++ API IS RELEASED
- cacheDir = getenv("EXTERNAL_STORAGE");
- ALOGV("Cache dir changed to %s", cacheDir);
- }
- // ensure that cache dir exists
- if (cacheDir && !createCacheDir(cacheDir)) {
- return false;
- }
- #endif
- if (!rsc->mHal.funcs.script.init(rsc, this, resName, cacheDir, bitcode, bitcodeLen, 0)) {
- return false;
- }
- mInitialized = true;
- #if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
- mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
- mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
- mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore());
- mEnviroment.mRaster.set(rsc->getDefaultProgramRaster());
- #endif
- rsc->mHal.funcs.script.invokeInit(rsc, this);
- for (size_t i=0; i < mHal.info.exportedPragmaCount; ++i) {
- const char * key = mHal.info.exportedPragmaKeyList[i];
- const char * value = mHal.info.exportedPragmaValueList[i];
- //ALOGE("pragma %s %s", keys[i], values[i]);
- if (!strcmp(key, "version")) {
- if (!strcmp(value, "1")) {
- continue;
- }
- ALOGE("Invalid version pragma value: %s\n", value);
- return false;
- }
- #if !defined(RS_VENDOR_LIB) && !defined(RS_COMPATIBILITY_LIB)
- if (!strcmp(key, "stateVertex")) {
- if (!strcmp(value, "default")) {
- continue;
- }
- if (!strcmp(value, "parent")) {
- mEnviroment.mVertex.clear();
- continue;
- }
- ALOGE("Unrecognized value %s passed to stateVertex", value);
- return false;
- }
- if (!strcmp(key, "stateRaster")) {
- if (!strcmp(value, "default")) {
- continue;
- }
- if (!strcmp(value, "parent")) {
- mEnviroment.mRaster.clear();
- continue;
- }
- ALOGE("Unrecognized value %s passed to stateRaster", value);
- return false;
- }
- if (!strcmp(key, "stateFragment")) {
- if (!strcmp(value, "default")) {
- continue;
- }
- if (!strcmp(value, "parent")) {
- mEnviroment.mFragment.clear();
- continue;
- }
- ALOGE("Unrecognized value %s passed to stateFragment", value);
- return false;
- }
- if (!strcmp(key, "stateStore")) {
- if (!strcmp(value, "default")) {
- continue;
- }
- if (!strcmp(value, "parent")) {
- mEnviroment.mFragmentStore.clear();
- continue;
- }
- ALOGE("Unrecognized value %s passed to stateStore", value);
- return false;
- }
- #endif
- }
- mSlots = new ObjectBaseRef<Allocation>[mHal.info.exportedVariableCount];
- mTypes = new ObjectBaseRef<const Type>[mHal.info.exportedVariableCount];
- return true;
- }
- namespace android {
- namespace renderscript {
- RsScript rsi_ScriptCCreate(Context *rsc,
- const char *resName, size_t resName_length,
- const char *cacheDir, size_t cacheDir_length,
- const char *text, size_t text_length)
- {
- ScriptC *s = new ScriptC(rsc);
- if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, text_length)) {
- // Error during compile, destroy s and return null.
- ObjectBase::checkDelete(s);
- return nullptr;
- }
- s->incUserRef();
- return s;
- }
- } // namespace renderscript
- } // namespace android
|