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