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