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