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 #include <string>
33
34 #ifdef USE_MINGW
35 /* Define the default path separator for the platform. */
36 #define OS_PATH_SEPARATOR '\\'
37 #define OS_PATH_SEPARATOR_STR "\\"
38
39 #else /* not USE_MINGW */
40
41 /* Define the default path separator for the platform. */
42 #define OS_PATH_SEPARATOR '/'
43 #define OS_PATH_SEPARATOR_STR "/"
44
45 #endif
46
47 using namespace android;
48 using namespace android::renderscript;
49
50 #define GET_TLS() Context::ScriptTLSStruct * tls = \
51 (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
52 Context * rsc = tls->mContext; \
53 ScriptC * sc = (ScriptC *) tls->mScript
54
ScriptC(Context * rsc)55 ScriptC::ScriptC(Context *rsc) : Script(rsc) {
56 #if !defined(RS_COMPATIBILITY_LIB) && !defined(ANDROID_RS_SERIALIZE)
57 BT = nullptr;
58 #endif
59 }
60
~ScriptC()61 ScriptC::~ScriptC() {
62 #if !defined(RS_COMPATIBILITY_LIB) && !defined(ANDROID_RS_SERIALIZE)
63 if (BT) {
64 delete BT;
65 BT = nullptr;
66 }
67 #endif
68 if (mInitialized) {
69 mRSC->mHal.funcs.script.invokeFreeChildren(mRSC, this);
70 mRSC->mHal.funcs.script.destroy(mRSC, this);
71 }
72 }
73
74 #ifndef RS_COMPATIBILITY_LIB
createCacheDir(const char * cacheDir)75 bool ScriptC::createCacheDir(const char *cacheDir) {
76 std::string currentDir;
77 const std::string cacheDirString(cacheDir);
78
79 struct stat statBuf;
80 int statReturn = stat(cacheDir, &statBuf);
81 if (!statReturn) {
82 return true;
83 }
84
85 // Start from the beginning of the cacheDirString.
86 int currPos = 0;
87
88 // Reserve space in currentDir for the entire cacheDir path.
89 currentDir.reserve(cacheDirString.length());
90
91 while (currPos >= 0) {
92 /*
93 * The character at currPos should be a path separator. We need to look
94 * for the next one.
95 */
96 int nextPos = cacheDirString.find(OS_PATH_SEPARATOR_STR, currPos + 1);
97
98 if (nextPos > 0) {
99 // A new path separator has been found.
100 currentDir += cacheDirString.substr(currPos, nextPos - currPos);
101 } else {
102 // There are no more path separators.
103 currentDir += cacheDirString.substr(currPos);
104 }
105
106 currPos = nextPos;
107
108 statReturn = stat(currentDir.c_str(), &statBuf);
109
110 if (statReturn) {
111 if (errno == ENOENT) {
112 if (mkdir(currentDir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) {
113 ALOGE("Couldn't create cache directory: %s",
114 currentDir.c_str());
115 ALOGE("Error: %s", strerror(errno));
116 return false;
117 }
118 } else {
119 ALOGE("Stat error: %s", strerror(errno));
120 return false;
121 }
122 }
123 }
124 return true;
125 }
126 #endif
127
setupScript(Context * rsc)128 void ScriptC::setupScript(Context *rsc) {
129 #ifndef RS_SERVER
130 mEnviroment.mStartTimeMillis
131 = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
132 #endif
133
134 for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) {
135 if (mSlots[ct].get() && !mTypes[ct].get()) {
136 mTypes[ct].set(mSlots[ct]->getType());
137 }
138
139 if (!mTypes[ct].get())
140 continue;
141 rsc->mHal.funcs.script.setGlobalBind(rsc, this, ct, mSlots[ct].get());
142 }
143 }
144
setupGLState(Context * rsc)145 void ScriptC::setupGLState(Context *rsc) {
146 #ifndef RS_COMPATIBILITY_LIB
147 if (mEnviroment.mFragmentStore.get()) {
148 rsc->setProgramStore(mEnviroment.mFragmentStore.get());
149 }
150 if (mEnviroment.mFragment.get()) {
151 rsc->setProgramFragment(mEnviroment.mFragment.get());
152 }
153 if (mEnviroment.mVertex.get()) {
154 rsc->setProgramVertex(mEnviroment.mVertex.get());
155 }
156 if (mEnviroment.mRaster.get()) {
157 rsc->setProgramRaster(mEnviroment.mRaster.get());
158 }
159 #endif
160 }
161
run(Context * rsc)162 uint32_t ScriptC::run(Context *rsc) {
163 if (mHal.info.root == nullptr) {
164 rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
165 return 0;
166 }
167
168 setupGLState(rsc);
169 setupScript(rsc);
170
171 uint32_t ret = 0;
172
173 if (rsc->props.mLogScripts) {
174 ALOGV("%p ScriptC::run invoking root, ptr %p", rsc, mHal.info.root);
175 }
176
177 ret = rsc->mHal.funcs.script.invokeRoot(rsc, this);
178
179 if (rsc->props.mLogScripts) {
180 ALOGV("%p ScriptC::run invoking complete, ret=%i", rsc, ret);
181 }
182
183 return ret;
184 }
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 // Make a copy of RsScriptCall and zero out extra fields that are absent
196 // in API levels below 23.
197 RsScriptCall sc_copy;
198 if (sc != nullptr && getApiLevel() < 23) {
199 memset(&sc_copy, 0, sizeof(sc_copy));
200 memcpy(&sc_copy, sc, 7*4);
201 sc = &sc_copy;
202 }
203
204 // Trace this function call.
205 // To avoid overhead we only build the string if tracing is actually
206 // enabled.
207 String8 *AString = NULL;
208 const char *String = "";
209 if (ATRACE_ENABLED()) {
210 AString = new String8("runForEach_");
211 AString->append(mHal.info.exportedForeachFuncList[slot].first);
212 String = AString->string();
213 }
214 ATRACE_NAME(String);
215 (void)String;
216 if (mRSC->hadFatalError()) return;
217
218 Context::PushState ps(rsc);
219
220 setupGLState(rsc);
221 setupScript(rsc);
222
223 if (rsc->mHal.funcs.script.invokeForEachMulti != nullptr) {
224 rsc->mHal.funcs.script.invokeForEachMulti(rsc, this, slot, ains, inLen,
225 aout, usr, usrBytes, sc);
226
227 } else if (inLen == 1) {
228 rsc->mHal.funcs.script.invokeForEach(rsc, this, slot, ains[0], aout,
229 usr, usrBytes, sc);
230
231 } else {
232 rsc->setError(RS_ERROR_FATAL_DRIVER,
233 "Driver support for multi-input not present");
234 }
235
236 if (AString) {
237 delete AString;
238 }
239 }
240
Invoke(Context * rsc,uint32_t slot,const void * data,size_t len)241 void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) {
242 ATRACE_CALL();
243
244 if (slot >= mHal.info.exportedFunctionCount) {
245 rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script");
246 return;
247 }
248 if (mRSC->hadFatalError()) return;
249
250 setupScript(rsc);
251
252 if (rsc->props.mLogScripts) {
253 ALOGV("%p ScriptC::Invoke invoking slot %i, ptr %p", rsc, slot, this);
254 }
255 rsc->mHal.funcs.script.invokeFunction(rsc, this, slot, data, len);
256 }
257
258 static const bool kDebugBitcode = false;
259
260 #ifndef RS_COMPATIBILITY_LIB
261 #ifndef ANDROID_RS_SERIALIZE
262
dumpBitcodeFile(const char * cacheDir,const char * resName,const char * suffix,const uint8_t * bitcode,size_t bitcodeLen)263 static bool dumpBitcodeFile(const char *cacheDir, const char *resName,
264 const char *suffix, const uint8_t *bitcode,
265 size_t bitcodeLen) {
266 std::string f(cacheDir);
267 f.append("/");
268 f.append(resName);
269 f.append("#");
270 f.append(suffix);
271 f.append(".bc");
272
273 if (!ScriptC::createCacheDir(cacheDir)) {
274 return false;
275 }
276
277 FILE *fp = fopen(f.c_str(), "w");
278 if (!fp) {
279 ALOGE("Could not open %s", f.c_str());
280 return false;
281 }
282
283 size_t nWritten = fwrite(bitcode, 1, bitcodeLen, fp);
284 fclose(fp);
285 if (nWritten != bitcodeLen) {
286 ALOGE("Could not write %s", f.c_str());
287 return false;
288 }
289 return true;
290 }
291
292 #endif // !ANDROID_RS_SERIALIZE
293 #endif // !RS_COMPATIBILITY_LIB
294
295
runCompiler(Context * rsc,const char * resName,const char * cacheDir,const uint8_t * bitcode,size_t bitcodeLen)296 bool ScriptC::runCompiler(Context *rsc,
297 const char *resName,
298 const char *cacheDir,
299 const uint8_t *bitcode,
300 size_t bitcodeLen) {
301 ATRACE_CALL();
302 //ALOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen);
303 #ifndef RS_COMPATIBILITY_LIB
304 #ifndef ANDROID_RS_SERIALIZE
305 uint32_t sdkVersion = 0;
306 bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeLen);
307 if (!bcWrapper.unwrap()) {
308 ALOGE("Bitcode is not in proper container format (raw or wrapper)");
309 return false;
310 }
311
312 if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
313 sdkVersion = bcWrapper.getTargetAPI();
314 }
315
316 if (sdkVersion == 0) {
317 // This signals that we didn't have a wrapper containing information
318 // about the bitcode.
319 sdkVersion = rsc->getTargetSdkVersion();
320 }
321
322 // Save off the sdkVersion, so that we can handle broken cases later.
323 // Bug 19734267
324 mApiLevel = sdkVersion;
325
326 if (BT) {
327 delete BT;
328 }
329 BT = new bcinfo::BitcodeTranslator((const char *)bitcode, bitcodeLen,
330 sdkVersion);
331 if (!BT->translate()) {
332 ALOGE("Failed to translate bitcode from version: %u", sdkVersion);
333 delete BT;
334 BT = nullptr;
335 return false;
336 }
337 bitcode = (const uint8_t *) BT->getTranslatedBitcode();
338 bitcodeLen = BT->getTranslatedBitcodeSize();
339
340 if (kDebugBitcode) {
341 if (!dumpBitcodeFile(cacheDir, resName, "after", bitcode, bitcodeLen)) {
342 return false;
343 }
344 }
345
346 #endif
347 if (!cacheDir) {
348 // MUST BE FIXED BEFORE ANYTHING USING C++ API IS RELEASED
349 cacheDir = getenv("EXTERNAL_STORAGE");
350 ALOGV("Cache dir changed to %s", cacheDir);
351 }
352
353 // ensure that cache dir exists
354 if (cacheDir && !createCacheDir(cacheDir)) {
355 return false;
356 }
357 #endif
358
359 if (!rsc->mHal.funcs.script.init(rsc, this, resName, cacheDir, bitcode, bitcodeLen, 0)) {
360 return false;
361 }
362
363 mInitialized = true;
364 #ifndef RS_COMPATIBILITY_LIB
365 mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
366 mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
367 mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore());
368 mEnviroment.mRaster.set(rsc->getDefaultProgramRaster());
369 #endif
370
371 rsc->mHal.funcs.script.invokeInit(rsc, this);
372
373 for (size_t i=0; i < mHal.info.exportedPragmaCount; ++i) {
374 const char * key = mHal.info.exportedPragmaKeyList[i];
375 const char * value = mHal.info.exportedPragmaValueList[i];
376 //ALOGE("pragma %s %s", keys[i], values[i]);
377 if (!strcmp(key, "version")) {
378 if (!strcmp(value, "1")) {
379 continue;
380 }
381 ALOGE("Invalid version pragma value: %s\n", value);
382 return false;
383 }
384
385 #ifndef RS_COMPATIBILITY_LIB
386 if (!strcmp(key, "stateVertex")) {
387 if (!strcmp(value, "default")) {
388 continue;
389 }
390 if (!strcmp(value, "parent")) {
391 mEnviroment.mVertex.clear();
392 continue;
393 }
394 ALOGE("Unrecognized value %s passed to stateVertex", value);
395 return false;
396 }
397
398 if (!strcmp(key, "stateRaster")) {
399 if (!strcmp(value, "default")) {
400 continue;
401 }
402 if (!strcmp(value, "parent")) {
403 mEnviroment.mRaster.clear();
404 continue;
405 }
406 ALOGE("Unrecognized value %s passed to stateRaster", value);
407 return false;
408 }
409
410 if (!strcmp(key, "stateFragment")) {
411 if (!strcmp(value, "default")) {
412 continue;
413 }
414 if (!strcmp(value, "parent")) {
415 mEnviroment.mFragment.clear();
416 continue;
417 }
418 ALOGE("Unrecognized value %s passed to stateFragment", value);
419 return false;
420 }
421
422 if (!strcmp(key, "stateStore")) {
423 if (!strcmp(value, "default")) {
424 continue;
425 }
426 if (!strcmp(value, "parent")) {
427 mEnviroment.mFragmentStore.clear();
428 continue;
429 }
430 ALOGE("Unrecognized value %s passed to stateStore", value);
431 return false;
432 }
433 #endif
434
435 }
436
437 mSlots = new ObjectBaseRef<Allocation>[mHal.info.exportedVariableCount];
438 mTypes = new ObjectBaseRef<const Type>[mHal.info.exportedVariableCount];
439
440 return true;
441 }
442
443 namespace android {
444 namespace renderscript {
445
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)446 RsScript rsi_ScriptCCreate(Context *rsc,
447 const char *resName, size_t resName_length,
448 const char *cacheDir, size_t cacheDir_length,
449 const char *text, size_t text_length)
450 {
451 ScriptC *s = new ScriptC(rsc);
452
453 if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, text_length)) {
454 // Error during compile, destroy s and return null.
455 ObjectBase::checkDelete(s);
456 return nullptr;
457 }
458
459 s->incUserRef();
460 return s;
461 }
462
463 }
464 }
465