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