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