• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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