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