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