• 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 #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 
32 using namespace android;
33 using 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 
ScriptC(Context * rsc)40 ScriptC::ScriptC(Context *rsc) : Script(rsc) {
41 #if !defined(RS_COMPATIBILITY_LIB) && !defined(ANDROID_RS_SERIALIZE)
42     BT = NULL;
43 #endif
44 }
45 
~ScriptC()46 ScriptC::~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
createCacheDir(const char * cacheDir)60 bool 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 
setupScript(Context * rsc)98 void 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 
setupGLState(Context * rsc)115 void 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 
run(Context * rsc)132 uint32_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 
runForEach(Context * rsc,uint32_t slot,const Allocation * ain,Allocation * aout,const void * usr,size_t usrBytes,const RsScriptCall * sc)157 void 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 
runForEach(Context * rsc,uint32_t slot,const Allocation ** ains,size_t inLen,Allocation * aout,const void * usr,size_t usrBytes,const RsScriptCall * sc)187 void 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 
Invoke(Context * rsc,uint32_t slot,const void * data,size_t len)219 void 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 
runCompiler(Context * rsc,const char * resName,const char * cacheDir,const uint8_t * bitcode,size_t bitcodeLen)234 bool 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 
371 namespace android {
372 namespace renderscript {
373 
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)374 RsScript 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