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