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