blob: 06693261709435e5eb9fc7d486642b9801766692 [file] [log] [blame]
Jason Sams709a0972012-11-15 18:18:04 -08001/*
2 * Copyright (C) 2011-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
Jason Sams709a0972012-11-15 18:18:04 -080017#include "rsCpuCore.h"
Jason Sams709a0972012-11-15 18:18:04 -080018#include "rsCpuScript.h"
Jason Sams709a0972012-11-15 18:18:04 -080019
Jason Sams110f1812013-03-14 16:02:18 -070020#ifdef RS_COMPATIBILITY_LIB
Stephen Hinesc2c11cc2013-07-19 01:07:42 -070021 #include <set>
22 #include <string>
Jason Sams110f1812013-03-14 16:02:18 -070023 #include <dlfcn.h>
24 #include <stdio.h>
Stephen Hinesc2c11cc2013-07-19 01:07:42 -070025 #include <stdlib.h>
Jason Sams110f1812013-03-14 16:02:18 -070026 #include <string.h>
Stephen Hinesc2c11cc2013-07-19 01:07:42 -070027 #include <unistd.h>
Jason Sams110f1812013-03-14 16:02:18 -070028#else
29 #include <bcc/BCCContext.h>
30 #include <bcc/Renderscript/RSCompilerDriver.h>
31 #include <bcc/Renderscript/RSExecutable.h>
32 #include <bcc/Renderscript/RSInfo.h>
Stephen Hinesb58d9ad2013-06-19 19:26:19 -070033 #include <bcinfo/MetadataExtractor.h>
Stephen Hinesba17ae42013-06-05 17:18:04 -070034 #include <cutils/properties.h>
Stephen Hinesb58d9ad2013-06-19 19:26:19 -070035
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include <unistd.h>
Jason Sams110f1812013-03-14 16:02:18 -070039#endif
Jason Sams709a0972012-11-15 18:18:04 -080040
Stephen Hinesba17ae42013-06-05 17:18:04 -070041namespace {
Stephen Hinesc2c11cc2013-07-19 01:07:42 -070042#ifdef RS_COMPATIBILITY_LIB
43
44// Create a len length string containing random characters from [A-Za-z0-9].
45static std::string getRandomString(size_t len) {
46 char buf[len + 1];
47 for (size_t i = 0; i < len; i++) {
48 uint32_t r = arc4random() & 0xffff;
49 r %= 62;
50 if (r < 26) {
51 // lowercase
52 buf[i] = 'a' + r;
53 } else if (r < 52) {
54 // uppercase
55 buf[i] = 'A' + (r - 26);
56 } else {
57 // Use a number
58 buf[i] = '0' + (r - 52);
59 }
60 }
61 buf[len] = '\0';
62 return std::string(buf);
63}
64
65// Attempt to load the shared library from origName, but then fall back to
66// creating the symlinked shared library if necessary (to ensure instancing).
67// This function returns the dlopen()-ed handle if successful.
68static void *loadSOHelper(const char *origName, const char *cacheDir,
69 const char *resName) {
70 // Keep track of which .so libraries have been loaded. Once a library is
71 // in the set (per-process granularity), we must instead make a symlink to
72 // the original shared object (randomly named .so file) and load that one
73 // instead. If we don't do this, we end up aliasing global data between
74 // the various Script instances (which are supposed to be completely
75 // independent).
76 static std::set<std::string> LoadedLibraries;
77
78 void *loaded = NULL;
79
80 // Skip everything if we don't even have the original library available.
81 if (access(origName, F_OK) != 0) {
82 return NULL;
83 }
84
85 // Common path is that we have not loaded this Script/library before.
86 if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
87 loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
88 if (loaded) {
89 LoadedLibraries.insert(origName);
90 }
91 return loaded;
92 }
93
94 // Construct an appropriately randomized filename for the symlink.
95 std::string newName(cacheDir);
96 newName.append("/com.android.renderscript.cache/librs.");
97 newName.append(resName);
98 newName.append("#");
99 newName.append(getRandomString(6)); // 62^6 potential filename variants.
100 newName.append(".so");
101
102 int r = symlink(origName, newName.c_str());
103 if (r != 0) {
104 ALOGE("Could not create symlink %s -> %s", newName.c_str(), origName);
105 return NULL;
106 }
107 loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
108 r = unlink(newName.c_str());
109 if (r != 0) {
110 ALOGE("Could not unlink symlink %s", newName.c_str());
111 }
112 if (loaded) {
113 LoadedLibraries.insert(newName.c_str());
114 }
115
116 return loaded;
117}
118
119// Load the shared library referred to by cacheDir and resName. If we have
120// already loaded this library, we instead create a new symlink (in the
121// cache dir) and then load that. We then immediately destroy the symlink.
122// This is required behavior to implement script instancing for the support
123// library, since shared objects are loaded and de-duped by name only.
124static void *loadSharedLibrary(const char *cacheDir, const char *resName) {
125 void *loaded = NULL;
126 //arc4random_stir();
127#ifndef RS_SERVER
128 std::string scriptSOName(cacheDir);
129 size_t cutPos = scriptSOName.rfind("cache");
130 if (cutPos != std::string::npos) {
131 scriptSOName.erase(cutPos);
132 } else {
133 ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir);
134 }
135 scriptSOName.append("/lib/librs.");
136#else
137 std::string scriptSOName("lib");
138#endif
139 scriptSOName.append(resName);
140 scriptSOName.append(".so");
141
142 // We should check if we can load the library from the standard app
143 // location for shared libraries first.
144 loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName);
145
146 if (loaded == NULL) {
147 ALOGE("Unable to open shared library (%s): %s",
148 scriptSOName.c_str(), dlerror());
149
150 // One final attempt to find the library in "/system/lib".
151 // We do this to allow bundled applications to use the compatibility
152 // library fallback path. Those applications don't have a private
153 // library path, so they need to install to the system directly.
154 // Note that this is really just a testing path.
155 android::String8 scriptSONameSystem("/system/lib/librs.");
156 scriptSONameSystem.append(resName);
157 scriptSONameSystem.append(".so");
158 loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir,
159 resName);
160 if (loaded == NULL) {
161 ALOGE("Unable to open system shared library (%s): %s",
162 scriptSONameSystem.c_str(), dlerror());
163 }
164 }
165
166 return loaded;
167}
168
169
170#else
Stephen Hinesba17ae42013-06-05 17:18:04 -0700171static bool is_force_recompile() {
172#ifdef RS_SERVER
173 return false;
174#else
175 char buf[PROPERTY_VALUE_MAX];
176
177 // Re-compile if floating point precision has been overridden.
178 property_get("debug.rs.precision", buf, "");
179 if (buf[0] != '\0') {
180 return true;
181 }
182
183 // Re-compile if debug.rs.forcerecompile is set.
184 property_get("debug.rs.forcerecompile", buf, "0");
185 if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
186 return true;
187 } else {
188 return false;
189 }
190#endif // RS_SERVER
191}
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700192
193//#define EXTERNAL_BCC_COMPILER 1
194#ifdef EXTERNAL_BCC_COMPILER
195const static char *BCC_EXE_PATH = "/system/bin/bcc";
196
197static bool compileBitcode(const char *cacheDir,
198 const char *resName,
199 const char *bitcode,
200 size_t bitcodeSize,
201 const char *core_lib) {
202 rsAssert(cacheDir && resName && bitcode && bitcodeSize && core_lib);
203
204 android::String8 bcFilename(cacheDir);
205 bcFilename.append("/");
206 bcFilename.append(resName);
207 bcFilename.append(".bc");
208 FILE *bcfile = fopen(bcFilename.string(), "w");
209 if (!bcfile) {
210 ALOGE("Could not write to %s", bcFilename.string());
211 return false;
212 }
213 size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile);
214 fclose(bcfile);
215 if (nwritten != bitcodeSize) {
216 ALOGE("Could not write %zu bytes to %s", bitcodeSize,
217 bcFilename.string());
218 return false;
219 }
220
221 pid_t pid = fork();
222 switch (pid) {
223 case -1: { // Error occurred (we attempt no recovery)
224 ALOGE("Couldn't fork for bcc compiler execution");
225 return false;
226 }
227 case 0: { // Child process
228 // Execute the bcc compiler.
229 execl(BCC_EXE_PATH,
230 BCC_EXE_PATH,
231 "-o", resName,
232 "-output_path", cacheDir,
233 "-bclib", core_lib,
234 bcFilename.string(),
235 (char *) NULL);
236 ALOGE("execl() failed: %s", strerror(errno));
237 abort();
238 return false;
239 }
240 default: { // Parent process (actual driver)
241 // Wait on child process to finish compiling the source.
242 int status = 0;
243 pid_t w = waitpid(pid, &status, 0);
244 if (w == -1) {
245 ALOGE("Could not wait for bcc compiler");
246 return false;
247 }
248
249 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
250 return true;
251 }
252
253 ALOGE("bcc compiler terminated unexpectedly");
254 return false;
255 }
256 }
257}
258#endif // EXTERNAL_BCC_COMPILER
259
Stephen Hinesba17ae42013-06-05 17:18:04 -0700260#endif // !defined(RS_COMPATIBILITY_LIB)
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700261} // namespace
Stephen Hinesba17ae42013-06-05 17:18:04 -0700262
Jason Sams709a0972012-11-15 18:18:04 -0800263namespace android {
264namespace renderscript {
265
266
Jason Sams110f1812013-03-14 16:02:18 -0700267#ifdef RS_COMPATIBILITY_LIB
268#define MAXLINE 500
269#define MAKE_STR_HELPER(S) #S
270#define MAKE_STR(S) MAKE_STR_HELPER(S)
271#define EXPORT_VAR_STR "exportVarCount: "
272#define EXPORT_VAR_STR_LEN strlen(EXPORT_VAR_STR)
273#define EXPORT_FUNC_STR "exportFuncCount: "
274#define EXPORT_FUNC_STR_LEN strlen(EXPORT_FUNC_STR)
275#define EXPORT_FOREACH_STR "exportForEachCount: "
276#define EXPORT_FOREACH_STR_LEN strlen(EXPORT_FOREACH_STR)
277#define OBJECT_SLOT_STR "objectSlotCount: "
278#define OBJECT_SLOT_STR_LEN strlen(OBJECT_SLOT_STR)
279
280// Copy up to a newline or size chars from str -> s, updating str
281// Returns s when successful and NULL when '\0' is finally reached.
282static char* strgets(char *s, int size, const char **ppstr) {
283 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
284 return NULL;
285 }
286
287 int i;
288 for (i = 0; i < (size - 1); i++) {
289 s[i] = **ppstr;
290 (*ppstr)++;
291 if (s[i] == '\0') {
292 return s;
293 } else if (s[i] == '\n') {
294 s[i+1] = '\0';
295 return s;
296 }
297 }
298
299 // size has been exceeded.
300 s[i] = '\0';
301
302 return s;
303}
304#endif
Jason Sams709a0972012-11-15 18:18:04 -0800305
306RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
307 mCtx = ctx;
308 mScript = s;
309
Jason Sams110f1812013-03-14 16:02:18 -0700310#ifdef RS_COMPATIBILITY_LIB
311 mScriptSO = NULL;
312 mInvokeFunctions = NULL;
313 mForEachFunctions = NULL;
314 mFieldAddress = NULL;
315 mFieldIsObject = NULL;
316 mForEachSignatures = NULL;
317#else
318 mCompilerContext = NULL;
319 mCompilerDriver = NULL;
320 mExecutable = NULL;
321#endif
322
Jason Sams709a0972012-11-15 18:18:04 -0800323 mRoot = NULL;
324 mRootExpand = NULL;
325 mInit = NULL;
326 mFreeChildren = NULL;
327
Jason Sams709a0972012-11-15 18:18:04 -0800328
329 mBoundAllocs = NULL;
330 mIntrinsicData = NULL;
331 mIsThreadable = true;
332}
333
334
335bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
336 uint8_t const *bitcode, size_t bitcodeSize,
337 uint32_t flags) {
338 //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
339 //ALOGE("rsdScriptInit %p %p", rsc, script);
340
341 mCtx->lockMutex();
342
Jason Sams110f1812013-03-14 16:02:18 -0700343#ifndef RS_COMPATIBILITY_LIB
Stephen Hinesba17ae42013-06-05 17:18:04 -0700344 bcc::RSExecutable *exec = NULL;
Jason Sams709a0972012-11-15 18:18:04 -0800345
346 mCompilerContext = NULL;
347 mCompilerDriver = NULL;
348 mExecutable = NULL;
349
350 mCompilerContext = new bcc::BCCContext();
351 if (mCompilerContext == NULL) {
352 ALOGE("bcc: FAILS to create compiler context (out of memory)");
353 mCtx->unlockMutex();
354 return false;
355 }
356
357 mCompilerDriver = new bcc::RSCompilerDriver();
358 if (mCompilerDriver == NULL) {
359 ALOGE("bcc: FAILS to create compiler driver (out of memory)");
360 mCtx->unlockMutex();
361 return false;
362 }
363
364 mCompilerDriver->setRSRuntimeLookupFunction(lookupRuntimeStub);
365 mCompilerDriver->setRSRuntimeLookupContext(this);
366
Stephen Hinesb7d9c802013-04-29 19:13:09 -0700367 // Run any compiler setup functions we have been provided with.
368 RSSetupCompilerCallback setupCompilerCallback =
369 mCtx->getSetupCompilerCallback();
370 if (setupCompilerCallback != NULL) {
371 setupCompilerCallback(mCompilerDriver);
372 }
373
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700374 const char *core_lib = bcc::RSInfo::LibCLCorePath;
375
376 bcinfo::MetadataExtractor ME((const char *) bitcode, bitcodeSize);
377 if (!ME.extract()) {
378 ALOGE("Could not extract metadata from bitcode");
379 return false;
380 }
381
382 enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision();
383 switch (prec) {
384 case bcinfo::RS_FP_Imprecise:
385 case bcinfo::RS_FP_Relaxed:
386#if defined(ARCH_ARM_HAVE_NEON)
387 // NEON-capable devices can use an accelerated math library for all
388 // reduced precision scripts.
389 core_lib = bcc::RSInfo::LibCLCoreNEONPath;
390#endif
391 break;
392 case bcinfo::RS_FP_Full:
393 break;
394 default:
395 ALOGE("Unknown precision for bitcode");
396 return false;
397 }
398
399#if defined(ARCH_X86_HAVE_SSE2)
400 // SSE2- or above capable devices will use an optimized library.
401 core_lib = bcc::RSInfo::LibCLCoreX86Path;
402#endif
403
Stephen Hines1d476622013-03-29 22:08:49 -0700404 RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
405 if (selectRTCallback != NULL) {
406 core_lib = selectRTCallback((const char *)bitcode, bitcodeSize);
407 }
Stephen Hinescca3d6c2013-04-15 01:06:39 -0700408
409 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
410 // Use the libclcore_debug.bc instead of the default library.
411 core_lib = bcc::RSInfo::LibCLCoreDebugPath;
Stephen Hinesf47e8b42013-04-18 01:06:29 -0700412 mCompilerDriver->setDebugContext(true);
Stephen Hinesba17ae42013-06-05 17:18:04 -0700413 // Skip the cache lookup
414 } else if (!is_force_recompile()) {
415 // Attempt to just load the script from cache first if we can.
416 exec = mCompilerDriver->loadScript(cacheDir, resName,
417 (const char *)bitcode, bitcodeSize);
Stephen Hinescca3d6c2013-04-15 01:06:39 -0700418 }
Stephen Hinesba17ae42013-06-05 17:18:04 -0700419
Stephen Hinesba17ae42013-06-05 17:18:04 -0700420 if (exec == NULL) {
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700421#ifdef EXTERNAL_BCC_COMPILER
422 bool built = compileBitcode(cacheDir, resName, (const char *)bitcode,
423 bitcodeSize, core_lib);
424#else
Stephen Hinesba17ae42013-06-05 17:18:04 -0700425 bool built = mCompilerDriver->build(*mCompilerContext, cacheDir,
426 resName, (const char *)bitcode,
427 bitcodeSize, core_lib,
428 mCtx->getLinkRuntimeCallback());
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700429#endif // EXTERNAL_BCC_COMPILER
Stephen Hinesba17ae42013-06-05 17:18:04 -0700430 if (built) {
431 exec = mCompilerDriver->loadScript(cacheDir, resName,
432 (const char *)bitcode,
433 bitcodeSize);
434 }
435 }
Jason Sams709a0972012-11-15 18:18:04 -0800436
437 if (exec == NULL) {
438 ALOGE("bcc: FAILS to prepare executable for '%s'", resName);
439 mCtx->unlockMutex();
440 return false;
441 }
442
443 mExecutable = exec;
444
445 exec->setThreadable(mIsThreadable);
446 if (!exec->syncInfo()) {
447 ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
448 }
449
450 mRoot = reinterpret_cast<int (*)()>(exec->getSymbolAddress("root"));
451 mRootExpand =
452 reinterpret_cast<int (*)()>(exec->getSymbolAddress("root.expand"));
453 mInit = reinterpret_cast<void (*)()>(exec->getSymbolAddress("init"));
454 mFreeChildren =
455 reinterpret_cast<void (*)()>(exec->getSymbolAddress(".rs.dtor"));
456
457
Stephen Hines1d476622013-03-29 22:08:49 -0700458 const bcc::RSInfo *info = &mExecutable->getInfo();
Jason Sams709a0972012-11-15 18:18:04 -0800459 if (info->getExportVarNames().size()) {
460 mBoundAllocs = new Allocation *[info->getExportVarNames().size()];
461 memset(mBoundAllocs, 0, sizeof(void *) * info->getExportVarNames().size());
462 }
463
Jason Sams110f1812013-03-14 16:02:18 -0700464#else
465
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700466 mScriptSO = loadSharedLibrary(cacheDir, resName);
Jason Sams110f1812013-03-14 16:02:18 -0700467
468 if (mScriptSO) {
469 char line[MAXLINE];
470 mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
471 if (mRoot) {
472 //ALOGE("Found root(): %p", mRoot);
473 }
474 mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
475 if (mRootExpand) {
476 //ALOGE("Found root.expand(): %p", mRootExpand);
477 }
478 mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
479 if (mInit) {
480 //ALOGE("Found init(): %p", mInit);
481 }
482 mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
483 if (mFreeChildren) {
484 //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
485 }
486
487 const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
488 if (rsInfo) {
489 //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
490 }
491
492 size_t varCount = 0;
493 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
494 goto error;
495 }
496 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
497 ALOGE("Invalid export var count!: %s", line);
498 goto error;
499 }
500
501 mExportedVariableCount = varCount;
502 //ALOGE("varCount: %zu", varCount);
503 if (varCount > 0) {
504 // Start by creating/zeroing this member, since we don't want to
505 // accidentally clean up invalid pointers later (if we error out).
506 mFieldIsObject = new bool[varCount];
507 if (mFieldIsObject == NULL) {
508 goto error;
509 }
510 memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
511 mFieldAddress = new void*[varCount];
512 if (mFieldAddress == NULL) {
513 goto error;
514 }
515 for (size_t i = 0; i < varCount; ++i) {
516 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
517 goto error;
518 }
519 char *c = strrchr(line, '\n');
520 if (c) {
521 *c = '\0';
522 }
523 mFieldAddress[i] = dlsym(mScriptSO, line);
524 if (mFieldAddress[i] == NULL) {
525 ALOGE("Failed to find variable address for %s: %s",
526 line, dlerror());
527 // Not a critical error if we don't find a global variable.
528 }
529 else {
530 //ALOGE("Found variable %s at %p", line,
531 //mFieldAddress[i]);
532 }
533 }
534 }
535
536 size_t funcCount = 0;
537 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
538 goto error;
539 }
540 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
541 ALOGE("Invalid export func count!: %s", line);
542 goto error;
543 }
544
545 mExportedFunctionCount = funcCount;
546 //ALOGE("funcCount: %zu", funcCount);
547
548 if (funcCount > 0) {
549 mInvokeFunctions = new InvokeFunc_t[funcCount];
550 if (mInvokeFunctions == NULL) {
551 goto error;
552 }
553 for (size_t i = 0; i < funcCount; ++i) {
554 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
555 goto error;
556 }
557 char *c = strrchr(line, '\n');
558 if (c) {
559 *c = '\0';
560 }
561
562 mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
563 if (mInvokeFunctions[i] == NULL) {
564 ALOGE("Failed to get function address for %s(): %s",
565 line, dlerror());
566 goto error;
567 }
568 else {
569 //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
570 }
571 }
572 }
573
574 size_t forEachCount = 0;
575 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
576 goto error;
577 }
578 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
579 ALOGE("Invalid export forEach count!: %s", line);
580 goto error;
581 }
582
583 if (forEachCount > 0) {
584
585 mForEachSignatures = new uint32_t[forEachCount];
586 if (mForEachSignatures == NULL) {
587 goto error;
588 }
589 mForEachFunctions = new ForEachFunc_t[forEachCount];
590 if (mForEachFunctions == NULL) {
591 goto error;
592 }
593 for (size_t i = 0; i < forEachCount; ++i) {
594 unsigned int tmpSig = 0;
595 char tmpName[MAXLINE];
596
597 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
598 goto error;
599 }
600 if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
601 &tmpSig, tmpName) != 2) {
602 ALOGE("Invalid export forEach!: %s", line);
603 goto error;
604 }
605
606 // Lookup the expanded ForEach kernel.
607 strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
608 mForEachSignatures[i] = tmpSig;
609 mForEachFunctions[i] =
610 (ForEachFunc_t) dlsym(mScriptSO, tmpName);
Stephen Hinesef7481e2013-04-09 19:05:27 -0700611 if (i != 0 && mForEachFunctions[i] == NULL) {
Jason Sams110f1812013-03-14 16:02:18 -0700612 // Ignore missing root.expand functions.
613 // root() is always specified at location 0.
Stephen Hinesef7481e2013-04-09 19:05:27 -0700614 ALOGE("Failed to find forEach function address for %s: %s",
615 tmpName, dlerror());
616 goto error;
Jason Sams110f1812013-03-14 16:02:18 -0700617 }
618 else {
619 //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
620 }
621 }
622 }
623
624 size_t objectSlotCount = 0;
625 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
626 goto error;
627 }
628 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
629 ALOGE("Invalid object slot count!: %s", line);
630 goto error;
631 }
632
633 if (objectSlotCount > 0) {
634 rsAssert(varCount > 0);
635 for (size_t i = 0; i < objectSlotCount; ++i) {
636 uint32_t varNum = 0;
637 if (strgets(line, MAXLINE, &rsInfo) == NULL) {
638 goto error;
639 }
640 if (sscanf(line, "%u", &varNum) != 1) {
641 ALOGE("Invalid object slot!: %s", line);
642 goto error;
643 }
644
645 if (varNum < varCount) {
646 mFieldIsObject[varNum] = true;
647 }
648 }
649 }
650
651 if (varCount > 0) {
652 mBoundAllocs = new Allocation *[varCount];
653 memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
654 }
655
656 if (mScriptSO == (void*)1) {
657 //rsdLookupRuntimeStub(script, "acos");
658 }
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700659 } else {
660 goto error;
Jason Sams110f1812013-03-14 16:02:18 -0700661 }
662#endif
663
Jason Sams709a0972012-11-15 18:18:04 -0800664 mCtx->unlockMutex();
665 return true;
Jason Sams110f1812013-03-14 16:02:18 -0700666
667#ifdef RS_COMPATIBILITY_LIB
668error:
669
670 mCtx->unlockMutex();
671 delete[] mInvokeFunctions;
672 delete[] mForEachFunctions;
673 delete[] mFieldAddress;
674 delete[] mFieldIsObject;
675 delete[] mForEachSignatures;
676 delete[] mBoundAllocs;
677 if (mScriptSO) {
678 dlclose(mScriptSO);
679 }
680 return false;
681#endif
Jason Sams709a0972012-11-15 18:18:04 -0800682}
683
684void RsdCpuScriptImpl::populateScript(Script *script) {
Jason Sams110f1812013-03-14 16:02:18 -0700685#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -0800686 const bcc::RSInfo *info = &mExecutable->getInfo();
687
688 // Copy info over to runtime
689 script->mHal.info.exportedFunctionCount = info->getExportFuncNames().size();
690 script->mHal.info.exportedVariableCount = info->getExportVarNames().size();
Tobias Grosser47935ac2013-06-17 11:47:26 -0700691 script->mHal.info.exportedForeachFuncList = info->getExportForeachFuncs().array();
Jason Sams709a0972012-11-15 18:18:04 -0800692 script->mHal.info.exportedPragmaCount = info->getPragmas().size();
693 script->mHal.info.exportedPragmaKeyList =
694 const_cast<const char**>(mExecutable->getPragmaKeys().array());
695 script->mHal.info.exportedPragmaValueList =
696 const_cast<const char**>(mExecutable->getPragmaValues().array());
697
698 if (mRootExpand) {
699 script->mHal.info.root = mRootExpand;
700 } else {
701 script->mHal.info.root = mRoot;
702 }
Jason Sams110f1812013-03-14 16:02:18 -0700703#else
704 // Copy info over to runtime
705 script->mHal.info.exportedFunctionCount = mExportedFunctionCount;
706 script->mHal.info.exportedVariableCount = mExportedVariableCount;
707 script->mHal.info.exportedPragmaCount = 0;
708 script->mHal.info.exportedPragmaKeyList = 0;
709 script->mHal.info.exportedPragmaValueList = 0;
710
711 // Bug, need to stash in metadata
712 if (mRootExpand) {
713 script->mHal.info.root = mRootExpand;
714 } else {
715 script->mHal.info.root = mRoot;
716 }
717#endif
Jason Sams709a0972012-11-15 18:18:04 -0800718}
719
Jason Sams709a0972012-11-15 18:18:04 -0800720
721typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
722
723void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation * ain, Allocation * aout,
724 const void * usr, uint32_t usrLen,
725 const RsScriptCall *sc,
726 MTLaunchStruct *mtls) {
727
728 memset(mtls, 0, sizeof(MTLaunchStruct));
729
Tim Murray3a25fdd2013-02-22 17:56:56 -0800730 // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
731 if (ain && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) {
Jason Samsddceab92013-08-07 13:02:32 -0700732 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null in allocations");
Tim Murray3a25fdd2013-02-22 17:56:56 -0800733 return;
734 }
735 if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) {
Jason Samsddceab92013-08-07 13:02:32 -0700736 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null out allocations");
Tim Murray3a25fdd2013-02-22 17:56:56 -0800737 return;
738 }
739
Jason Sams709a0972012-11-15 18:18:04 -0800740 if (ain) {
741 mtls->fep.dimX = ain->getType()->getDimX();
742 mtls->fep.dimY = ain->getType()->getDimY();
743 mtls->fep.dimZ = ain->getType()->getDimZ();
744 //mtls->dimArray = ain->getType()->getDimArray();
745 } else if (aout) {
746 mtls->fep.dimX = aout->getType()->getDimX();
747 mtls->fep.dimY = aout->getType()->getDimY();
748 mtls->fep.dimZ = aout->getType()->getDimZ();
749 //mtls->dimArray = aout->getType()->getDimArray();
750 } else {
751 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
752 return;
753 }
754
755 if (!sc || (sc->xEnd == 0)) {
756 mtls->xEnd = mtls->fep.dimX;
757 } else {
758 rsAssert(sc->xStart < mtls->fep.dimX);
759 rsAssert(sc->xEnd <= mtls->fep.dimX);
760 rsAssert(sc->xStart < sc->xEnd);
761 mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
762 mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
763 if (mtls->xStart >= mtls->xEnd) return;
764 }
765
766 if (!sc || (sc->yEnd == 0)) {
767 mtls->yEnd = mtls->fep.dimY;
768 } else {
769 rsAssert(sc->yStart < mtls->fep.dimY);
770 rsAssert(sc->yEnd <= mtls->fep.dimY);
771 rsAssert(sc->yStart < sc->yEnd);
772 mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
773 mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
774 if (mtls->yStart >= mtls->yEnd) return;
775 }
776
Tim Murrayd4ecb172013-02-07 12:17:03 -0800777 if (!sc || (sc->zEnd == 0)) {
778 mtls->zEnd = mtls->fep.dimZ;
779 } else {
780 rsAssert(sc->zStart < mtls->fep.dimZ);
781 rsAssert(sc->zEnd <= mtls->fep.dimZ);
782 rsAssert(sc->zStart < sc->zEnd);
783 mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
784 mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
785 if (mtls->zStart >= mtls->zEnd) return;
786 }
787
Jason Sams709a0972012-11-15 18:18:04 -0800788 mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
789 mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
790 mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
791 mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
792
793 rsAssert(!ain || (ain->getType()->getDimZ() == 0));
794
795 mtls->rsc = mCtx;
796 mtls->ain = ain;
797 mtls->aout = aout;
798 mtls->fep.usr = usr;
799 mtls->fep.usrLen = usrLen;
800 mtls->mSliceSize = 1;
801 mtls->mSliceNum = 0;
802
803 mtls->fep.ptrIn = NULL;
804 mtls->fep.eStrideIn = 0;
805 mtls->isThreadable = mIsThreadable;
806
807 if (ain) {
808 mtls->fep.ptrIn = (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr;
809 mtls->fep.eStrideIn = ain->getType()->getElementSizeBytes();
810 mtls->fep.yStrideIn = ain->mHal.drvState.lod[0].stride;
811 }
812
813 mtls->fep.ptrOut = NULL;
814 mtls->fep.eStrideOut = 0;
815 if (aout) {
816 mtls->fep.ptrOut = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
817 mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes();
818 mtls->fep.yStrideOut = aout->mHal.drvState.lod[0].stride;
819 }
820}
821
822
823void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
824 const Allocation * ain,
825 Allocation * aout,
826 const void * usr,
827 uint32_t usrLen,
828 const RsScriptCall *sc) {
829
830 MTLaunchStruct mtls;
831 forEachMtlsSetup(ain, aout, usr, usrLen, sc, &mtls);
832 forEachKernelSetup(slot, &mtls);
833
834 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
835 mCtx->launchThreads(ain, aout, sc, &mtls);
836 mCtx->setTLS(oldTLS);
837}
838
839void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
Jason Sams709a0972012-11-15 18:18:04 -0800840 mtls->script = this;
841 mtls->fep.slot = slot;
Jason Sams110f1812013-03-14 16:02:18 -0700842#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -0800843 rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
844 mtls->kernel = reinterpret_cast<ForEachFunc_t>(
845 mExecutable->getExportForeachFuncAddrs()[slot]);
846 rsAssert(mtls->kernel != NULL);
847 mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
Jason Sams110f1812013-03-14 16:02:18 -0700848#else
849 mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
850 rsAssert(mtls->kernel != NULL);
851 mtls->sig = mForEachSignatures[slot];
852#endif
Jason Sams709a0972012-11-15 18:18:04 -0800853}
854
855int RsdCpuScriptImpl::invokeRoot() {
856 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
857 int ret = mRoot();
858 mCtx->setTLS(oldTLS);
859 return ret;
860}
861
862void RsdCpuScriptImpl::invokeInit() {
863 if (mInit) {
864 mInit();
865 }
866}
867
868void RsdCpuScriptImpl::invokeFreeChildren() {
869 if (mFreeChildren) {
870 mFreeChildren();
871 }
872}
873
874void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
875 size_t paramLength) {
876 //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
877
878 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
879 reinterpret_cast<void (*)(const void *, uint32_t)>(
Jason Sams110f1812013-03-14 16:02:18 -0700880#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -0800881 mExecutable->getExportFuncAddrs()[slot])(params, paramLength);
Jason Sams110f1812013-03-14 16:02:18 -0700882#else
883 mInvokeFunctions[slot])(params, paramLength);
884#endif
Jason Sams709a0972012-11-15 18:18:04 -0800885 mCtx->setTLS(oldTLS);
886}
887
888void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
889 //rsAssert(!script->mFieldIsObject[slot]);
890 //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
891
892 //if (mIntrinsicID) {
893 //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
894 //return;
895 //}
896
Jason Sams110f1812013-03-14 16:02:18 -0700897#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -0800898 int32_t *destPtr = reinterpret_cast<int32_t *>(
899 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -0700900#else
901 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
902#endif
Jason Sams709a0972012-11-15 18:18:04 -0800903 if (!destPtr) {
904 //ALOGV("Calling setVar on slot = %i which is null", slot);
905 return;
906 }
907
908 memcpy(destPtr, data, dataLength);
909}
910
Tim Murray9c642392013-04-11 13:29:59 -0700911void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
912 //rsAssert(!script->mFieldIsObject[slot]);
913 //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
914
915#ifndef RS_COMPATIBILITY_LIB
916 int32_t *srcPtr = reinterpret_cast<int32_t *>(
917 mExecutable->getExportVarAddrs()[slot]);
918#else
919 int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
920#endif
921 if (!srcPtr) {
922 //ALOGV("Calling setVar on slot = %i which is null", slot);
923 return;
924 }
925 memcpy(data, srcPtr, dataLength);
926}
927
928
Jason Sams709a0972012-11-15 18:18:04 -0800929void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
930 const Element *elem,
931 const size_t *dims, size_t dimLength) {
932
Jason Sams110f1812013-03-14 16:02:18 -0700933#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -0800934 int32_t *destPtr = reinterpret_cast<int32_t *>(
935 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -0700936#else
937 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
938#endif
Jason Sams709a0972012-11-15 18:18:04 -0800939 if (!destPtr) {
940 //ALOGV("Calling setVar on slot = %i which is null", slot);
941 return;
942 }
943
944 // We want to look at dimension in terms of integer components,
945 // but dimLength is given in terms of bytes.
946 dimLength /= sizeof(int);
947
948 // Only a single dimension is currently supported.
949 rsAssert(dimLength == 1);
950 if (dimLength == 1) {
951 // First do the increment loop.
952 size_t stride = elem->getSizeBytes();
953 const char *cVal = reinterpret_cast<const char *>(data);
954 for (size_t i = 0; i < dims[0]; i++) {
955 elem->incRefs(cVal);
956 cVal += stride;
957 }
958
959 // Decrement loop comes after (to prevent race conditions).
960 char *oldVal = reinterpret_cast<char *>(destPtr);
961 for (size_t i = 0; i < dims[0]; i++) {
962 elem->decRefs(oldVal);
963 oldVal += stride;
964 }
965 }
966
967 memcpy(destPtr, data, dataLength);
968}
969
970void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
971
972 //rsAssert(!script->mFieldIsObject[slot]);
973 //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
974
Jason Sams110f1812013-03-14 16:02:18 -0700975#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -0800976 int32_t *destPtr = reinterpret_cast<int32_t *>(
977 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -0700978#else
979 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
980#endif
Jason Sams709a0972012-11-15 18:18:04 -0800981 if (!destPtr) {
982 //ALOGV("Calling setVar on slot = %i which is null", slot);
983 return;
984 }
985
986 void *ptr = NULL;
987 mBoundAllocs[slot] = data;
988 if(data) {
989 ptr = data->mHal.drvState.lod[0].mallocPtr;
990 }
991 memcpy(destPtr, &ptr, sizeof(void *));
992}
993
994void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
995
996 //rsAssert(script->mFieldIsObject[slot]);
997 //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
998
999 //if (mIntrinsicID) {
1000 //mIntrinsicFuncs.setVarObj(dc, script, drv->mIntrinsicData, slot, alloc);
1001 //return;
1002 //}
1003
Jason Sams110f1812013-03-14 16:02:18 -07001004#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001005 int32_t *destPtr = reinterpret_cast<int32_t *>(
1006 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001007#else
1008 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1009#endif
Jason Sams709a0972012-11-15 18:18:04 -08001010 if (!destPtr) {
1011 //ALOGV("Calling setVar on slot = %i which is null", slot);
1012 return;
1013 }
1014
1015 rsrSetObject(mCtx->getContext(), (ObjectBase **)destPtr, data);
1016}
1017
1018RsdCpuScriptImpl::~RsdCpuScriptImpl() {
Jason Sams110f1812013-03-14 16:02:18 -07001019#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001020 if (mExecutable) {
1021 Vector<void *>::const_iterator var_addr_iter =
1022 mExecutable->getExportVarAddrs().begin();
1023 Vector<void *>::const_iterator var_addr_end =
1024 mExecutable->getExportVarAddrs().end();
1025
1026 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter =
1027 mExecutable->getInfo().getObjectSlots().begin();
1028 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end =
1029 mExecutable->getInfo().getObjectSlots().end();
1030
1031 while ((var_addr_iter != var_addr_end) &&
1032 (is_object_iter != is_object_end)) {
1033 // The field address can be NULL if the script-side has optimized
1034 // the corresponding global variable away.
1035 ObjectBase **obj_addr =
1036 reinterpret_cast<ObjectBase **>(*var_addr_iter);
1037 if (*is_object_iter) {
1038 if (*var_addr_iter != NULL) {
1039 rsrClearObject(mCtx->getContext(), obj_addr);
1040 }
1041 }
1042 var_addr_iter++;
1043 is_object_iter++;
1044 }
1045 }
1046
1047 if (mCompilerContext) {
1048 delete mCompilerContext;
1049 }
1050 if (mCompilerDriver) {
1051 delete mCompilerDriver;
1052 }
1053 if (mExecutable) {
1054 delete mExecutable;
1055 }
1056 if (mBoundAllocs) {
1057 delete[] mBoundAllocs;
1058 }
Jason Sams110f1812013-03-14 16:02:18 -07001059#else
1060 if (mFieldIsObject) {
1061 for (size_t i = 0; i < mExportedVariableCount; ++i) {
1062 if (mFieldIsObject[i]) {
1063 if (mFieldAddress[i] != NULL) {
1064 ObjectBase **obj_addr =
1065 reinterpret_cast<ObjectBase **>(mFieldAddress[i]);
1066 rsrClearObject(mCtx->getContext(), obj_addr);
1067 }
1068 }
1069 }
1070 }
1071
1072 if (mInvokeFunctions) delete[] mInvokeFunctions;
1073 if (mForEachFunctions) delete[] mForEachFunctions;
1074 if (mFieldAddress) delete[] mFieldAddress;
1075 if (mFieldIsObject) delete[] mFieldIsObject;
1076 if (mForEachSignatures) delete[] mForEachSignatures;
1077 if (mBoundAllocs) delete[] mBoundAllocs;
1078 if (mScriptSO) {
1079 dlclose(mScriptSO);
1080 }
1081#endif
Jason Sams709a0972012-11-15 18:18:04 -08001082}
1083
1084Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const {
1085 if (!ptr) {
1086 return NULL;
1087 }
1088
1089 for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) {
1090 Allocation *a = mBoundAllocs[ct];
1091 if (!a) continue;
1092 if (a->mHal.drvState.lod[0].mallocPtr == ptr) {
1093 return a;
1094 }
1095 }
1096 ALOGE("rsGetAllocation, failed to find %p", ptr);
1097 return NULL;
1098}
1099
Jason Sams17e3cdc2013-09-09 17:32:16 -07001100void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation * ain,
1101 Allocation * aout, const void * usr,
1102 uint32_t usrLen, const RsScriptCall *sc)
1103{
1104}
1105
1106void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation * ain,
1107 Allocation * aout, const void * usr,
1108 uint32_t usrLen, const RsScriptCall *sc)
1109{
1110}
1111
Jason Sams709a0972012-11-15 18:18:04 -08001112
1113}
1114}