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