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 
     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 
     33 using namespace android;
     34 using 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 
     41 ScriptC::ScriptC(Context *rsc) : Script(rsc) {
     42 #ifndef RS_COMPATIBILITY_LIB
     43 #ifndef ANDROID_RS_SERIALIZE
     44     BT = NULL;
     45 #endif
     46 #endif
     47 }
     48 
     49 ScriptC::~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
     65 bool 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 
    103 void 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 
    120 void 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 
    137 uint32_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 
    162 void 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 
    177 void 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 
    190 ScriptCState::ScriptCState() {
    191 }
    192 
    193 ScriptCState::~ScriptCState() {
    194 }
    195 
    196 /*
    197 static 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
    223 extern const char rs_runtime_lib_bc[];
    224 extern unsigned rs_runtime_lib_bc_size;
    225 #endif
    226 
    227 bool 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 
    364 namespace android {
    365 namespace renderscript {
    366 
    367 RsScript 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