blob: 17f54052a0d9253a261182b38dc19b90a7de9586 [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
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -07007 *
Jason Sams709a0972012-11-15 18:18:04 -08008 * 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
Jason Sams110f1812013-03-14 16:02:18 -070021 #include <stdio.h>
Stephen Hinesee48c0b2013-10-30 17:48:30 -070022 #include <sys/stat.h>
Stephen Hinesc2c11cc2013-07-19 01:07:42 -070023 #include <unistd.h>
Jason Sams110f1812013-03-14 16:02:18 -070024#else
25 #include <bcc/BCCContext.h>
Stephen Hines82e0a672014-05-05 15:40:56 -070026 #include <bcc/Config/Config.h>
Jason Sams110f1812013-03-14 16:02:18 -070027 #include <bcc/Renderscript/RSCompilerDriver.h>
Jason Sams110f1812013-03-14 16:02:18 -070028 #include <bcc/Renderscript/RSInfo.h>
Stephen Hinesb58d9ad2013-06-19 19:26:19 -070029 #include <bcinfo/MetadataExtractor.h>
Stephen Hinesba17ae42013-06-05 17:18:04 -070030 #include <cutils/properties.h>
Stephen Hinesb58d9ad2013-06-19 19:26:19 -070031
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
Stephen Hines00511322014-01-31 11:20:23 -080035
36 #include <string>
37 #include <vector>
Jason Sams110f1812013-03-14 16:02:18 -070038#endif
Jason Sams709a0972012-11-15 18:18:04 -080039
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -080040#include <set>
41#include <string>
42#include <dlfcn.h>
43#include <stdlib.h>
44#include <string.h>
45#include <fstream>
46#include <iostream>
47
48#ifdef __LP64__
49#define SYSLIBPATH "/system/lib64"
50#else
51#define SYSLIBPATH "/system/lib"
52#endif
53
Stephen Hinesba17ae42013-06-05 17:18:04 -070054namespace {
Stephen Hinesc2c11cc2013-07-19 01:07:42 -070055
56// Create a len length string containing random characters from [A-Za-z0-9].
57static std::string getRandomString(size_t len) {
58 char buf[len + 1];
59 for (size_t i = 0; i < len; i++) {
60 uint32_t r = arc4random() & 0xffff;
61 r %= 62;
62 if (r < 26) {
63 // lowercase
64 buf[i] = 'a' + r;
65 } else if (r < 52) {
66 // uppercase
67 buf[i] = 'A' + (r - 26);
68 } else {
69 // Use a number
70 buf[i] = '0' + (r - 52);
71 }
72 }
73 buf[len] = '\0';
74 return std::string(buf);
75}
76
Stephen Hinesee48c0b2013-10-30 17:48:30 -070077// Check if a path exists and attempt to create it if it doesn't.
78static bool ensureCacheDirExists(const char *path) {
79 if (access(path, R_OK | W_OK | X_OK) == 0) {
80 // Done if we can rwx the directory
81 return true;
82 }
83 if (mkdir(path, 0700) == 0) {
84 return true;
85 }
86 return false;
87}
88
Stephen Hines7d774852014-10-01 12:57:57 -070089// Copy the file named \p srcFile to \p dstFile.
90// Return 0 on success and -1 if anything wasn't copied.
91static int copyFile(const char *dstFile, const char *srcFile) {
92 std::ifstream srcStream(srcFile);
93 if (!srcStream) {
94 ALOGE("Could not verify or read source file: %s", srcFile);
95 return -1;
96 }
97 std::ofstream dstStream(dstFile);
98 if (!dstStream) {
99 ALOGE("Could not verify or write destination file: %s", dstFile);
100 return -1;
101 }
102 dstStream << srcStream.rdbuf();
103 if (!dstStream) {
104 ALOGE("Could not write destination file: %s", dstFile);
105 return -1;
106 }
107
108 srcStream.close();
109 dstStream.close();
110
111 return 0;
112}
113
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800114static std::string findSharedObjectName(const char *cacheDir,
115 const char *resName) {
116
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700117#ifndef RS_SERVER
118 std::string scriptSOName(cacheDir);
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800119#ifdef RS_COMPATIBILITY_LIB
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700120 size_t cutPos = scriptSOName.rfind("cache");
121 if (cutPos != std::string::npos) {
122 scriptSOName.erase(cutPos);
123 } else {
124 ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir);
125 }
126 scriptSOName.append("/lib/librs.");
127#else
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800128 scriptSOName.append("/librs.");
129#endif
130
131#else
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700132 std::string scriptSOName("lib");
133#endif
134 scriptSOName.append(resName);
135 scriptSOName.append(".so");
136
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800137 return scriptSOName;
138}
139
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800140#ifndef RS_COMPATIBILITY_LIB
141
Stephen Hinesba17ae42013-06-05 17:18:04 -0700142static bool is_force_recompile() {
143#ifdef RS_SERVER
144 return false;
145#else
146 char buf[PROPERTY_VALUE_MAX];
147
148 // Re-compile if floating point precision has been overridden.
149 property_get("debug.rs.precision", buf, "");
150 if (buf[0] != '\0') {
151 return true;
152 }
153
154 // Re-compile if debug.rs.forcerecompile is set.
155 property_get("debug.rs.forcerecompile", buf, "0");
156 if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
157 return true;
158 } else {
159 return false;
160 }
161#endif // RS_SERVER
162}
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700163
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700164const static char *BCC_EXE_PATH = "/system/bin/bcc";
165
Chris Wailes6847e732014-08-11 17:30:51 -0700166static void setCompileArguments(std::vector<const char*>* args,
167 const std::string& bcFileName,
168 const char* cacheDir, const char* resName,
169 const char* core_lib, bool useRSDebugContext,
170 const char* bccPluginName) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700171 rsAssert(cacheDir && resName && core_lib);
172 args->push_back(BCC_EXE_PATH);
Tim Murray687cfe82015-01-08 14:59:38 -0800173 args->push_back("-unroll-runtime");
174 args->push_back("-scalarize-load-store");
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700175 args->push_back("-o");
176 args->push_back(resName);
177 args->push_back("-output_path");
178 args->push_back(cacheDir);
179 args->push_back("-bclib");
180 args->push_back(core_lib);
181 args->push_back("-mtriple");
182 args->push_back(DEFAULT_TARGET_TRIPLE_STRING);
183
Tim Murray358ffb82014-12-09 11:53:06 -0800184 // Enable workaround for A53 codegen by default.
185#if defined(__aarch64__) && !defined(DISABLE_A53_WORKAROUND)
186 args->push_back("-aarch64-fix-cortex-a53-835769");
187#endif
188
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700189 // Execute the bcc compiler.
190 if (useRSDebugContext) {
191 args->push_back("-rs-debug-ctx");
192 } else {
193 // Only load additional libraries for compiles that don't use
194 // the debug context.
195 if (bccPluginName && strlen(bccPluginName) > 0) {
196 args->push_back("-load");
197 args->push_back(bccPluginName);
198 }
199 }
200
Stephen Hines45e753a2015-01-19 20:58:44 -0800201 args->push_back("-fPIC");
202 args->push_back("-embedRSInfo");
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800203
Chris Wailes6847e732014-08-11 17:30:51 -0700204 args->push_back(bcFileName.c_str());
Chris Wailes44bef6f2014-08-12 13:51:10 -0700205 args->push_back(nullptr);
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700206}
207
Chris Wailes6847e732014-08-11 17:30:51 -0700208static bool compileBitcode(const std::string &bcFileName,
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700209 const char *bitcode,
210 size_t bitcodeSize,
Chris Wailes6847e732014-08-11 17:30:51 -0700211 const char **compileArguments,
212 const std::string &compileCommandLine) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700213 rsAssert(bitcode && bitcodeSize);
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700214
Chris Wailes6847e732014-08-11 17:30:51 -0700215 FILE *bcfile = fopen(bcFileName.c_str(), "w");
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700216 if (!bcfile) {
Chris Wailes6847e732014-08-11 17:30:51 -0700217 ALOGE("Could not write to %s", bcFileName.c_str());
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700218 return false;
219 }
220 size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile);
221 fclose(bcfile);
222 if (nwritten != bitcodeSize) {
223 ALOGE("Could not write %zu bytes to %s", bitcodeSize,
Chris Wailes6847e732014-08-11 17:30:51 -0700224 bcFileName.c_str());
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700225 return false;
226 }
227
228 pid_t pid = fork();
Stephen Hines00511322014-01-31 11:20:23 -0800229
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700230 switch (pid) {
231 case -1: { // Error occurred (we attempt no recovery)
232 ALOGE("Couldn't fork for bcc compiler execution");
233 return false;
234 }
235 case 0: { // Child process
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700236 ALOGV("Invoking BCC with: %s", compileCommandLine.c_str());
237 execv(BCC_EXE_PATH, (char* const*)compileArguments);
Stephen Hines00511322014-01-31 11:20:23 -0800238
Stephen Hines00511322014-01-31 11:20:23 -0800239 ALOGE("execv() failed: %s", strerror(errno));
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700240 abort();
241 return false;
242 }
243 default: { // Parent process (actual driver)
244 // Wait on child process to finish compiling the source.
245 int status = 0;
246 pid_t w = waitpid(pid, &status, 0);
247 if (w == -1) {
248 ALOGE("Could not wait for bcc compiler");
249 return false;
250 }
251
252 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
253 return true;
254 }
255
256 ALOGE("bcc compiler terminated unexpectedly");
257 return false;
258 }
259 }
260}
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700261
Yang Ni1c44cb62015-01-22 12:02:27 -0800262#endif // !defined(RS_COMPATIBILITY_LIB)
263} // namespace
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800264
Yang Ni1c44cb62015-01-22 12:02:27 -0800265namespace android {
266namespace renderscript {
267
268const char* SharedLibraryUtils::LD_EXE_PATH = "/system/bin/ld.mc";
269const char* SharedLibraryUtils::RS_CACHE_DIR = "com.android.renderscript.cache";
270
271#ifndef RS_COMPATIBILITY_LIB
272
273bool SharedLibraryUtils::createSharedLibrary(const char *cacheDir, const char *resName) {
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800274 std::string sharedLibName = findSharedObjectName(cacheDir, resName);
275 std::string objFileName = cacheDir;
276 objFileName.append("/");
277 objFileName.append(resName);
278 objFileName.append(".o");
279
280 const char *compiler_rt = SYSLIBPATH"/libcompiler_rt.so";
281 std::vector<const char *> args = {
282 LD_EXE_PATH,
283 "-shared",
284 "-nostdlib",
285 compiler_rt,
286 "-mtriple", DEFAULT_TARGET_TRIPLE_STRING,
287 "-L", SYSLIBPATH,
288 "-lRSDriver", "-lm", "-lc",
289 objFileName.c_str(),
290 "-o", sharedLibName.c_str(),
291 nullptr
292 };
293
294 std::string cmdLineStr = bcc::getCommandLine(args.size()-1, args.data());
295
296 pid_t pid = fork();
297
298 switch (pid) {
299 case -1: { // Error occurred (we attempt no recovery)
300 ALOGE("Couldn't fork for linker (%s) execution", LD_EXE_PATH);
301 return false;
302 }
303 case 0: { // Child process
304 ALOGV("Invoking ld.mc with args '%s'", cmdLineStr.c_str());
305 execv(LD_EXE_PATH, (char* const*) args.data());
306
307 ALOGE("execv() failed: %s", strerror(errno));
308 abort();
309 return false;
310 }
311 default: { // Parent process (actual driver)
312 // Wait on child process to finish compiling the source.
313 int status = 0;
314 pid_t w = waitpid(pid, &status, 0);
315 if (w == -1) {
316 ALOGE("Could not wait for linker (%s)", LD_EXE_PATH);
317 return false;
318 }
319
320 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
321 return true;
322 }
323
324 ALOGE("Linker (%s) terminated unexpectedly", LD_EXE_PATH);
325 return false;
326 }
327 }
328}
Stephen Hinesba17ae42013-06-05 17:18:04 -0700329
Yang Ni1c44cb62015-01-22 12:02:27 -0800330#endif // RS_COMPATIBILITY_LIB
331
332void* SharedLibraryUtils::loadSharedLibrary(const char *cacheDir, const char *resName) {
333 void *loaded = nullptr;
334
335 std::string scriptSOName = findSharedObjectName(cacheDir, resName);
336
337 // We should check if we can load the library from the standard app
338 // location for shared libraries first.
339 loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName);
340
341 if (loaded == nullptr) {
342 ALOGE("Unable to open shared library (%s): %s",
343 scriptSOName.c_str(), dlerror());
344
345#ifdef RS_COMPATIBILITY_LIB
346 // One final attempt to find the library in "/system/lib".
347 // We do this to allow bundled applications to use the compatibility
348 // library fallback path. Those applications don't have a private
349 // library path, so they need to install to the system directly.
350 // Note that this is really just a testing path.
351 std::string scriptSONameSystem("/system/lib/librs.");
352 scriptSONameSystem.append(resName);
353 scriptSONameSystem.append(".so");
354 loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir,
355 resName);
356 if (loaded == nullptr) {
357 ALOGE("Unable to open system shared library (%s): %s",
358 scriptSONameSystem.c_str(), dlerror());
359 }
360#endif
361 }
362
363 return loaded;
364}
365
366void* SharedLibraryUtils::loadSOHelper(const char *origName, const char *cacheDir,
367 const char *resName) {
368 // Keep track of which .so libraries have been loaded. Once a library is
369 // in the set (per-process granularity), we must instead make a copy of
370 // the original shared object (randomly named .so file) and load that one
371 // instead. If we don't do this, we end up aliasing global data between
372 // the various Script instances (which are supposed to be completely
373 // independent).
374 static std::set<std::string> LoadedLibraries;
375
376 void *loaded = nullptr;
377
378 // Skip everything if we don't even have the original library available.
379 if (access(origName, F_OK) != 0) {
380 return nullptr;
381 }
382
383 // Common path is that we have not loaded this Script/library before.
384 if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
385 loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
386 if (loaded) {
387 LoadedLibraries.insert(origName);
388 }
389 return loaded;
390 }
391
392 std::string newName(cacheDir);
393
394 // Append RS_CACHE_DIR only if it is not found in cacheDir
395 // In driver mode, RS_CACHE_DIR is already appended to cacheDir.
396 if (newName.find(RS_CACHE_DIR) == std::string::npos) {
397 newName.append("/");
398 newName.append(RS_CACHE_DIR);
399 newName.append("/");
400 }
401
402 if (!ensureCacheDirExists(newName.c_str())) {
403 ALOGE("Could not verify or create cache dir: %s", cacheDir);
404 return nullptr;
405 }
406
407 // Construct an appropriately randomized filename for the copy.
408 newName.append("librs.");
409 newName.append(resName);
410 newName.append("#");
411 newName.append(getRandomString(6)); // 62^6 potential filename variants.
412 newName.append(".so");
413
414 int r = copyFile(newName.c_str(), origName);
415 if (r != 0) {
416 ALOGE("Could not create copy %s -> %s", origName, newName.c_str());
417 return nullptr;
418 }
419 loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
420 r = unlink(newName.c_str());
421 if (r != 0) {
422 ALOGE("Could not unlink copy %s", newName.c_str());
423 }
424 if (loaded) {
425 LoadedLibraries.insert(newName.c_str());
426 }
427
428 return loaded;
429}
Jason Sams709a0972012-11-15 18:18:04 -0800430
Jason Sams110f1812013-03-14 16:02:18 -0700431#define MAXLINE 500
432#define MAKE_STR_HELPER(S) #S
433#define MAKE_STR(S) MAKE_STR_HELPER(S)
434#define EXPORT_VAR_STR "exportVarCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700435#define EXPORT_FUNC_STR "exportFuncCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700436#define EXPORT_FOREACH_STR "exportForEachCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700437#define OBJECT_SLOT_STR "objectSlotCount: "
Pirama Arumuga Nainar577194a2015-01-23 14:27:33 -0800438#define PRAGMA_STR "pragmaCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700439
440// Copy up to a newline or size chars from str -> s, updating str
Chris Wailes44bef6f2014-08-12 13:51:10 -0700441// Returns s when successful and nullptr when '\0' is finally reached.
Jason Sams110f1812013-03-14 16:02:18 -0700442static char* strgets(char *s, int size, const char **ppstr) {
443 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700444 return nullptr;
Jason Sams110f1812013-03-14 16:02:18 -0700445 }
446
447 int i;
448 for (i = 0; i < (size - 1); i++) {
449 s[i] = **ppstr;
450 (*ppstr)++;
451 if (s[i] == '\0') {
452 return s;
453 } else if (s[i] == '\n') {
454 s[i+1] = '\0';
455 return s;
456 }
457 }
458
459 // size has been exceeded.
460 s[i] = '\0';
461
462 return s;
463}
Jason Sams709a0972012-11-15 18:18:04 -0800464
465RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
466 mCtx = ctx;
467 mScript = s;
468
Chris Wailes44bef6f2014-08-12 13:51:10 -0700469 mScriptSO = nullptr;
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800470
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800471#ifndef RS_COMPATIBILITY_LIB
Chris Wailes44bef6f2014-08-12 13:51:10 -0700472 mCompilerDriver = nullptr;
Jason Sams110f1812013-03-14 16:02:18 -0700473#endif
474
Tim Murraye195a3f2014-03-13 15:04:58 -0700475
Chris Wailes44bef6f2014-08-12 13:51:10 -0700476 mRoot = nullptr;
477 mRootExpand = nullptr;
478 mInit = nullptr;
479 mFreeChildren = nullptr;
Yang Nid9bae682015-01-20 15:31:15 -0800480 mScriptExec = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800481
Chris Wailes44bef6f2014-08-12 13:51:10 -0700482 mBoundAllocs = nullptr;
483 mIntrinsicData = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800484 mIsThreadable = true;
485}
486
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800487bool RsdCpuScriptImpl::storeRSInfoFromSO() {
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800488 mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
489 if (mRoot) {
490 //ALOGE("Found root(): %p", mRoot);
491 }
492 mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
493 if (mRootExpand) {
494 //ALOGE("Found root.expand(): %p", mRootExpand);
495 }
496 mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
497 if (mInit) {
498 //ALOGE("Found init(): %p", mInit);
499 }
500 mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
501 if (mFreeChildren) {
502 //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
503 }
504
Yang Nid9bae682015-01-20 15:31:15 -0800505 mScriptExec = ScriptExecutable::createFromSharedObject(
506 mCtx->getContext(), mScriptSO);
507
508 if (mScriptExec == nullptr) {
509 return false;
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800510 }
511
Yang Nid9bae682015-01-20 15:31:15 -0800512 size_t varCount = mScriptExec->getExportedVariableCount();
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800513 if (varCount > 0) {
514 mBoundAllocs = new Allocation *[varCount];
515 memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
516 }
517
Yang Nid9bae682015-01-20 15:31:15 -0800518 return true;
519}
520
521ScriptExecutable* ScriptExecutable::createFromSharedObject(
522 Context* RSContext, void* sharedObj) {
523 char line[MAXLINE];
524
525 size_t varCount = 0;
526 size_t funcCount = 0;
527 size_t forEachCount = 0;
528 size_t objectSlotCount = 0;
Pirama Arumuga Nainar577194a2015-01-23 14:27:33 -0800529 size_t pragmaCount = 0;
Yang Nid9bae682015-01-20 15:31:15 -0800530
531 const char *rsInfo = (const char *) dlsym(sharedObj, ".rs.info");
532
533 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
534 return nullptr;
535 }
536 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
537 ALOGE("Invalid export var count!: %s", line);
538 return nullptr;
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800539 }
540
Yang Nid9bae682015-01-20 15:31:15 -0800541 std::vector<void*> fieldAddress;
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800542
Yang Nid9bae682015-01-20 15:31:15 -0800543 for (size_t i = 0; i < varCount; ++i) {
544 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
545 return nullptr;
546 }
547 char *c = strrchr(line, '\n');
548 if (c) {
549 *c = '\0';
550 }
551 void* addr = dlsym(sharedObj, line);
552 if (addr == nullptr) {
553 ALOGE("Failed to find variable address for %s: %s",
554 line, dlerror());
555 // Not a critical error if we don't find a global variable.
556 }
557 fieldAddress.push_back(addr);
558 }
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800559
Yang Nid9bae682015-01-20 15:31:15 -0800560 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
561 return nullptr;
562 }
563 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
564 ALOGE("Invalid export func count!: %s", line);
565 return nullptr;
566 }
567
568 std::vector<InvokeFunc_t> invokeFunctions(funcCount);
569
570 for (size_t i = 0; i < funcCount; ++i) {
571 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
572 return nullptr ;
573 }
574 char *c = strrchr(line, '\n');
575 if (c) {
576 *c = '\0';
577 }
578
579 invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line);
580 if (invokeFunctions[i] == nullptr) {
581 ALOGE("Failed to get function address for %s(): %s",
582 line, dlerror());
583 return nullptr;
584 }
585 }
586
587 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
588 return nullptr;
589 }
590 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
591 ALOGE("Invalid export forEach count!: %s", line);
592 return nullptr;
593 }
594
595 std::vector<ForEachFunc_t> forEachFunctions(forEachCount);
596 std::vector<uint32_t> forEachSignatures(forEachCount);
597
598 for (size_t i = 0; i < forEachCount; ++i) {
599 unsigned int tmpSig = 0;
600 char tmpName[MAXLINE];
601
602 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
603 return nullptr;
604 }
605 if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
606 &tmpSig, tmpName) != 2) {
607 ALOGE("Invalid export forEach!: %s", line);
608 return nullptr;
609 }
610
611 // Lookup the expanded ForEach kernel.
612 strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
613 forEachSignatures[i] = tmpSig;
614 forEachFunctions[i] =
615 (ForEachFunc_t) dlsym(sharedObj, tmpName);
616 if (i != 0 && forEachFunctions[i] == nullptr) {
617 // Ignore missing root.expand functions.
618 // root() is always specified at location 0.
619 ALOGE("Failed to find forEach function address for %s: %s",
620 tmpName, dlerror());
621 return nullptr;
622 }
623 }
624
625 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
626 return nullptr;
627 }
628 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
629 ALOGE("Invalid object slot count!: %s", line);
630 return nullptr;
631 }
632
633 std::vector<bool> fieldIsObject(varCount, false);
634
635 rsAssert(varCount > 0);
636 for (size_t i = 0; i < objectSlotCount; ++i) {
637 uint32_t varNum = 0;
638 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
639 return nullptr;
640 }
641 if (sscanf(line, "%u", &varNum) != 1) {
642 ALOGE("Invalid object slot!: %s", line);
643 return nullptr;
644 }
645
646 if (varNum < varCount) {
647 fieldIsObject[varNum] = true;
648 }
649 }
650
Pirama Arumuga Nainar577194a2015-01-23 14:27:33 -0800651#ifdef RS_COMPATIBILITY_LIB
652 // Do not attempt to read pragmas in compat lib path
653 std::vector<const char *> pragmaKeys(pragmaCount);
654 std::vector<const char *> pragmaValues(pragmaCount);
655
656#else
657 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
658 return nullptr;
659 }
660
661 if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) {
662 ALOGE("Invalid pragma count!: %s", line);
663 return nullptr;
664 }
665
666 std::vector<const char *> pragmaKeys(pragmaCount);
667 std::vector<const char *> pragmaValues(pragmaCount);
668
669 for (size_t i = 0; i < pragmaCount; ++i) {
670 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
671 ALOGE("Unable to read pragma at index %zu!", i);
672 return nullptr;
673 }
674
675 char key[MAXLINE];
676 char value[MAXLINE] = ""; // initialize in case value is empty
677
678 // pragmas can just have a key and no value. Only check to make sure
679 // that the key is not empty
680 if (sscanf(line, "%" MAKE_STR(MAXLINE) "s - %" MAKE_STR(MAXLINE) "s",
681 key, value) == 0 ||
682 strlen(key) == 0)
683 {
684 ALOGE("Invalid pragma value!: %s", line);
685
686 // free previously allocated keys and values
687 for (size_t idx = 0; idx < i; ++idx) {
688 delete [] pragmaKeys[idx];
689 delete [] pragmaValues[idx];
690 }
691 return nullptr;
692 }
693
694 char *pKey = new char[strlen(key)+1];
695 strcpy(pKey, key);
696 pragmaKeys[i] = pKey;
697
698 char *pValue = new char[strlen(value)+1];
699 strcpy(pValue, value);
700 pragmaValues[i] = pValue;
701 //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue);
702 }
703#endif
704
Yang Nid9bae682015-01-20 15:31:15 -0800705 return new ScriptExecutable(
706 RSContext, fieldAddress, fieldIsObject, invokeFunctions,
Pirama Arumuga Nainar577194a2015-01-23 14:27:33 -0800707 forEachFunctions, forEachSignatures, pragmaKeys, pragmaValues);
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800708}
709
Jason Sams709a0972012-11-15 18:18:04 -0800710bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
711 uint8_t const *bitcode, size_t bitcodeSize,
Stephen Hines00511322014-01-31 11:20:23 -0800712 uint32_t flags, char const *bccPluginName) {
Jason Sams709a0972012-11-15 18:18:04 -0800713 //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
714 //ALOGE("rsdScriptInit %p %p", rsc, script);
715
716 mCtx->lockMutex();
Jason Sams110f1812013-03-14 16:02:18 -0700717#ifndef RS_COMPATIBILITY_LIB
Stephen Hines00511322014-01-31 11:20:23 -0800718 bool useRSDebugContext = false;
Jason Sams709a0972012-11-15 18:18:04 -0800719
Chris Wailes44bef6f2014-08-12 13:51:10 -0700720 mCompilerDriver = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800721
Jason Sams709a0972012-11-15 18:18:04 -0800722 mCompilerDriver = new bcc::RSCompilerDriver();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700723 if (mCompilerDriver == nullptr) {
Jason Sams709a0972012-11-15 18:18:04 -0800724 ALOGE("bcc: FAILS to create compiler driver (out of memory)");
725 mCtx->unlockMutex();
726 return false;
727 }
728
Stephen Hinesb7d9c802013-04-29 19:13:09 -0700729 // Run any compiler setup functions we have been provided with.
730 RSSetupCompilerCallback setupCompilerCallback =
731 mCtx->getSetupCompilerCallback();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700732 if (setupCompilerCallback != nullptr) {
Stephen Hinesb7d9c802013-04-29 19:13:09 -0700733 setupCompilerCallback(mCompilerDriver);
734 }
735
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700736 bcinfo::MetadataExtractor bitcodeMetadata((const char *) bitcode, bitcodeSize);
737 if (!bitcodeMetadata.extract()) {
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700738 ALOGE("Could not extract metadata from bitcode");
Stephen Hinesf94e8db2014-06-26 11:55:29 -0700739 mCtx->unlockMutex();
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700740 return false;
741 }
742
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700743 const char* core_lib = findCoreLib(bitcodeMetadata, (const char*)bitcode, bitcodeSize);
Stephen Hinescca3d6c2013-04-15 01:06:39 -0700744
745 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
Stephen Hinesf47e8b42013-04-18 01:06:29 -0700746 mCompilerDriver->setDebugContext(true);
Stephen Hines00511322014-01-31 11:20:23 -0800747 useRSDebugContext = true;
Stephen Hinescca3d6c2013-04-15 01:06:39 -0700748 }
Stephen Hinesba17ae42013-06-05 17:18:04 -0700749
Chris Wailes6847e732014-08-11 17:30:51 -0700750 std::string bcFileName(cacheDir);
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700751 bcFileName.append("/");
752 bcFileName.append(resName);
753 bcFileName.append(".bc");
754
755 std::vector<const char*> compileArguments;
756 setCompileArguments(&compileArguments, bcFileName, cacheDir, resName, core_lib,
757 useRSDebugContext, bccPluginName);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700758 // The last argument of compileArguments ia a nullptr, so remove 1 from the size.
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700759 std::string compileCommandLine =
760 bcc::getCommandLine(compileArguments.size() - 1, compileArguments.data());
761
Stephen Hines45e753a2015-01-19 20:58:44 -0800762 if (!is_force_recompile()) {
Yang Ni1c44cb62015-01-22 12:02:27 -0800763 mScriptSO = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700764 }
765
766 // If we can't, it's either not there or out of date. We compile the bit code and try loading
767 // again.
Stephen Hines45e753a2015-01-19 20:58:44 -0800768 if (mScriptSO == nullptr) {
769 if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize,
770 compileArguments.data(), compileCommandLine))
771 {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700772 ALOGE("bcc: FAILS to compile '%s'", resName);
773 mCtx->unlockMutex();
774 return false;
775 }
Stephen Hines45e753a2015-01-19 20:58:44 -0800776
Yang Ni1c44cb62015-01-22 12:02:27 -0800777 if (!SharedLibraryUtils::createSharedLibrary(cacheDir, resName)) {
Stephen Hines45e753a2015-01-19 20:58:44 -0800778 ALOGE("Linker: Failed to link object file '%s'", resName);
779 mCtx->unlockMutex();
780 return false;
781 }
782
Yang Ni1c44cb62015-01-22 12:02:27 -0800783 mScriptSO = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);
Stephen Hines45e753a2015-01-19 20:58:44 -0800784 if (mScriptSO == nullptr) {
785 ALOGE("Unable to load '%s'", resName);
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700786 mCtx->unlockMutex();
787 return false;
Stephen Hinesba17ae42013-06-05 17:18:04 -0700788 }
789 }
Jason Sams709a0972012-11-15 18:18:04 -0800790
Stephen Hines45e753a2015-01-19 20:58:44 -0800791 // Read RS symbol information from the .so.
792 if ( !mScriptSO) {
793 goto error;
Jason Sams709a0972012-11-15 18:18:04 -0800794 }
795
Stephen Hines45e753a2015-01-19 20:58:44 -0800796 if ( !storeRSInfoFromSO()) {
797 goto error;
Tim Murray29809d12014-05-28 12:04:19 -0700798 }
Jean-Luc Brouilletf4d216e2014-06-09 18:04:16 -0700799#else // RS_COMPATIBILITY_LIB is defined
Jason Sams110f1812013-03-14 16:02:18 -0700800
Yang Ni1c44cb62015-01-22 12:02:27 -0800801 mScriptSO = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);
Jason Sams110f1812013-03-14 16:02:18 -0700802
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800803 if (!mScriptSO) {
804 goto error;
805 }
Jason Sams110f1812013-03-14 16:02:18 -0700806
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -0800807 if (!storeRSInfoFromSO()) {
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700808 goto error;
Jason Sams110f1812013-03-14 16:02:18 -0700809 }
810#endif
Jason Sams709a0972012-11-15 18:18:04 -0800811 mCtx->unlockMutex();
812 return true;
Jason Sams110f1812013-03-14 16:02:18 -0700813
Jason Sams110f1812013-03-14 16:02:18 -0700814error:
815
816 mCtx->unlockMutex();
Jason Sams110f1812013-03-14 16:02:18 -0700817 if (mScriptSO) {
818 dlclose(mScriptSO);
819 }
820 return false;
Jason Sams709a0972012-11-15 18:18:04 -0800821}
822
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700823#ifndef RS_COMPATIBILITY_LIB
824
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700825const char* RsdCpuScriptImpl::findCoreLib(const bcinfo::MetadataExtractor& ME, const char* bitcode,
826 size_t bitcodeSize) {
827 const char* defaultLib = SYSLIBPATH"/libclcore.bc";
828
829 // If we're debugging, use the debug library.
830 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
831 return SYSLIBPATH"/libclcore_debug.bc";
832 }
833
834 // If a callback has been registered to specify a library, use that.
835 RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700836 if (selectRTCallback != nullptr) {
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700837 return selectRTCallback((const char*)bitcode, bitcodeSize);
838 }
839
840 // Check for a platform specific library
841#if defined(ARCH_ARM_HAVE_NEON) && !defined(DISABLE_CLCORE_NEON)
842 enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision();
Jean-Luc Brouilletf4d38362014-07-09 17:46:03 -0700843 if (prec == bcinfo::RS_FP_Relaxed) {
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700844 // NEON-capable ARMv7a devices can use an accelerated math library
845 // for all reduced precision scripts.
846 // ARMv8 does not use NEON, as ASIMD can be used with all precision
847 // levels.
848 return SYSLIBPATH"/libclcore_neon.bc";
849 } else {
850 return defaultLib;
851 }
852#elif defined(__i386__) || defined(__x86_64__)
853 // x86 devices will use an optimized library.
854 return SYSLIBPATH"/libclcore_x86.bc";
855#else
856 return defaultLib;
857#endif
858}
859
860#endif
861
Jason Sams709a0972012-11-15 18:18:04 -0800862void RsdCpuScriptImpl::populateScript(Script *script) {
Jason Sams110f1812013-03-14 16:02:18 -0700863 // Copy info over to runtime
Yang Nid9bae682015-01-20 15:31:15 -0800864 script->mHal.info.exportedFunctionCount = mScriptExec->getExportedFunctionCount();
865 script->mHal.info.exportedVariableCount = mScriptExec->getExportedVariableCount();
Pirama Arumuga Nainar577194a2015-01-23 14:27:33 -0800866 script->mHal.info.exportedPragmaCount = mScriptExec->getPragmaCount();;
867 script->mHal.info.exportedPragmaKeyList =
868 const_cast<const char**>(&mScriptExec->getPragmaKeys().front());
869 script->mHal.info.exportedPragmaValueList =
870 const_cast<const char**>(&mScriptExec->getPragmaValues().front());
Jason Sams110f1812013-03-14 16:02:18 -0700871
872 // Bug, need to stash in metadata
873 if (mRootExpand) {
874 script->mHal.info.root = mRootExpand;
875 } else {
876 script->mHal.info.root = mRoot;
877 }
Jason Sams709a0972012-11-15 18:18:04 -0800878}
879
Jason Sams709a0972012-11-15 18:18:04 -0800880
881typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
882
Chris Wailesf3712132014-07-16 15:18:30 -0700883void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation ** ains,
884 uint32_t inLen,
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700885 Allocation * aout,
886 const void * usr, uint32_t usrLen,
887 const RsScriptCall *sc,
888 MTLaunchStruct *mtls) {
889
890 memset(mtls, 0, sizeof(MTLaunchStruct));
891
Chris Wailesf3712132014-07-16 15:18:30 -0700892 for (int index = inLen; --index >= 0;) {
893 const Allocation* ain = ains[index];
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700894
Chris Wailesf3712132014-07-16 15:18:30 -0700895 // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
Chris Wailes44bef6f2014-08-12 13:51:10 -0700896 if (ain != nullptr &&
897 (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == nullptr) {
898
Chris Wailesf3712132014-07-16 15:18:30 -0700899 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
900 "rsForEach called with null in allocations");
901 return;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700902 }
903 }
904
Chris Wailes44bef6f2014-08-12 13:51:10 -0700905 if (aout &&
906 (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == nullptr) {
907
Chris Wailesf3712132014-07-16 15:18:30 -0700908 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
909 "rsForEach called with null out allocations");
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700910 return;
911 }
912
Chris Wailesf3712132014-07-16 15:18:30 -0700913 if (inLen > 0) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700914 const Allocation *ain0 = ains[0];
915 const Type *inType = ain0->getType();
916
Jason Samsc0d68472015-01-20 14:29:52 -0800917 mtls->fep.dim.x = inType->getDimX();
918 mtls->fep.dim.y = inType->getDimY();
919 mtls->fep.dim.z = inType->getDimZ();
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700920
921 for (int Index = inLen; --Index >= 1;) {
922 if (!ain0->hasSameDims(ains[Index])) {
923 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
924 "Failed to launch kernel; dimensions of input and output allocations do not match.");
925
926 return;
927 }
928 }
929
Chris Wailes44bef6f2014-08-12 13:51:10 -0700930 } else if (aout != nullptr) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700931 const Type *outType = aout->getType();
932
Jason Samsc0d68472015-01-20 14:29:52 -0800933 mtls->fep.dim.x = outType->getDimX();
934 mtls->fep.dim.y = outType->getDimY();
935 mtls->fep.dim.z = outType->getDimZ();
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700936
937 } else {
Chris Wailesf3712132014-07-16 15:18:30 -0700938 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
939 "rsForEach called with null allocations");
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700940 return;
941 }
942
Chris Wailes44bef6f2014-08-12 13:51:10 -0700943 if (inLen > 0 && aout != nullptr) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700944 if (!ains[0]->hasSameDims(aout)) {
945 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
946 "Failed to launch kernel; dimensions of input and output allocations do not match.");
947
948 return;
949 }
950 }
951
952 if (!sc || (sc->xEnd == 0)) {
Jason Samsc0d68472015-01-20 14:29:52 -0800953 mtls->xEnd = mtls->fep.dim.x;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700954 } else {
Jason Samsc0d68472015-01-20 14:29:52 -0800955 rsAssert(sc->xStart < mtls->fep.dim.x);
956 rsAssert(sc->xEnd <= mtls->fep.dim.x);
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700957 rsAssert(sc->xStart < sc->xEnd);
Jason Samsc0d68472015-01-20 14:29:52 -0800958 mtls->xStart = rsMin(mtls->fep.dim.x, sc->xStart);
959 mtls->xEnd = rsMin(mtls->fep.dim.x, sc->xEnd);
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700960 if (mtls->xStart >= mtls->xEnd) return;
961 }
962
963 if (!sc || (sc->yEnd == 0)) {
Jason Samsc0d68472015-01-20 14:29:52 -0800964 mtls->yEnd = mtls->fep.dim.y;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700965 } else {
Jason Samsc0d68472015-01-20 14:29:52 -0800966 rsAssert(sc->yStart < mtls->fep.dim.y);
967 rsAssert(sc->yEnd <= mtls->fep.dim.y);
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700968 rsAssert(sc->yStart < sc->yEnd);
Jason Samsc0d68472015-01-20 14:29:52 -0800969 mtls->yStart = rsMin(mtls->fep.dim.y, sc->yStart);
970 mtls->yEnd = rsMin(mtls->fep.dim.y, sc->yEnd);
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700971 if (mtls->yStart >= mtls->yEnd) return;
972 }
973
974 if (!sc || (sc->zEnd == 0)) {
Jason Samsc0d68472015-01-20 14:29:52 -0800975 mtls->zEnd = mtls->fep.dim.z;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700976 } else {
Jason Samsc0d68472015-01-20 14:29:52 -0800977 rsAssert(sc->zStart < mtls->fep.dim.z);
978 rsAssert(sc->zEnd <= mtls->fep.dim.z);
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700979 rsAssert(sc->zStart < sc->zEnd);
Jason Samsc0d68472015-01-20 14:29:52 -0800980 mtls->zStart = rsMin(mtls->fep.dim.z, sc->zStart);
981 mtls->zEnd = rsMin(mtls->fep.dim.z, sc->zEnd);
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700982 if (mtls->zStart >= mtls->zEnd) return;
983 }
984
985 mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
986 mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
987 mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
988 mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
989
Chris Wailesf3712132014-07-16 15:18:30 -0700990 rsAssert(inLen == 0 || (ains[0]->getType()->getDimZ() == 0));
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700991
992 mtls->rsc = mCtx;
Jason Samsc0d68472015-01-20 14:29:52 -0800993 if (ains) {
994 memcpy(mtls->ains, ains, inLen * sizeof(ains[0]));
995 }
996 mtls->aout[0] = aout;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700997 mtls->fep.usr = usr;
998 mtls->fep.usrLen = usrLen;
999 mtls->mSliceSize = 1;
1000 mtls->mSliceNum = 0;
1001
Chris Wailes4b3c34e2014-06-11 12:00:29 -07001002 mtls->isThreadable = mIsThreadable;
1003
Chris Wailesf3712132014-07-16 15:18:30 -07001004 if (inLen > 0) {
Chris Wailesf3712132014-07-16 15:18:30 -07001005 mtls->fep.inLen = inLen;
Chris Wailes4b3c34e2014-06-11 12:00:29 -07001006 for (int index = inLen; --index >= 0;) {
Jason Samsc0d68472015-01-20 14:29:52 -08001007 mtls->fep.inPtr[index] = (const uint8_t*)ains[index]->mHal.drvState.lod[0].mallocPtr;
1008 mtls->fep.inStride[index] = ains[index]->getType()->getElementSizeBytes();
Chris Wailes4b3c34e2014-06-11 12:00:29 -07001009 }
1010 }
1011
Chris Wailes44bef6f2014-08-12 13:51:10 -07001012 if (aout != nullptr) {
Jason Samsc0d68472015-01-20 14:29:52 -08001013 mtls->fep.outPtr[0] = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
1014 mtls->fep.outStride[0] = aout->getType()->getElementSizeBytes();
Chris Wailes4b3c34e2014-06-11 12:00:29 -07001015 }
1016}
1017
Jason Sams709a0972012-11-15 18:18:04 -08001018
1019void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
Chris Wailesf3712132014-07-16 15:18:30 -07001020 const Allocation ** ains,
1021 uint32_t inLen,
Jason Sams709a0972012-11-15 18:18:04 -08001022 Allocation * aout,
1023 const void * usr,
1024 uint32_t usrLen,
1025 const RsScriptCall *sc) {
1026
1027 MTLaunchStruct mtls;
Chris Wailes4b3c34e2014-06-11 12:00:29 -07001028
1029 forEachMtlsSetup(ains, inLen, aout, usr, usrLen, sc, &mtls);
1030 forEachKernelSetup(slot, &mtls);
1031
1032 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1033 mCtx->launchThreads(ains, inLen, aout, sc, &mtls);
1034 mCtx->setTLS(oldTLS);
1035}
1036
Jason Sams709a0972012-11-15 18:18:04 -08001037void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
Jason Sams709a0972012-11-15 18:18:04 -08001038 mtls->script = this;
1039 mtls->fep.slot = slot;
Yang Nid9bae682015-01-20 15:31:15 -08001040 mtls->kernel = mScriptExec->getForEachFunction(slot);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001041 rsAssert(mtls->kernel != nullptr);
Yang Nid9bae682015-01-20 15:31:15 -08001042 mtls->sig = mScriptExec->getForEachSignature(slot);
Jason Sams709a0972012-11-15 18:18:04 -08001043}
1044
1045int RsdCpuScriptImpl::invokeRoot() {
1046 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1047 int ret = mRoot();
1048 mCtx->setTLS(oldTLS);
1049 return ret;
1050}
1051
1052void RsdCpuScriptImpl::invokeInit() {
1053 if (mInit) {
1054 mInit();
1055 }
1056}
1057
1058void RsdCpuScriptImpl::invokeFreeChildren() {
1059 if (mFreeChildren) {
1060 mFreeChildren();
1061 }
1062}
1063
1064void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
1065 size_t paramLength) {
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -08001066 //ALOGE("invoke %i %p %zu", slot, params, paramLength);
Yong Cheneaba5a32014-12-12 13:25:18 +08001067 void * ap = nullptr;
1068
1069#if defined(__x86_64__)
1070 // The invoked function could have input parameter of vector type for example float4 which
1071 // requires void* params to be 16 bytes aligned when using SSE instructions for x86_64 platform.
1072 // So try to align void* params before passing them into RS exported function.
1073
1074 if ((uint8_t)(uint64_t)params & 0x0F) {
1075 if ((ap = (void*)memalign(16, paramLength)) != nullptr) {
1076 memcpy(ap, params, paramLength);
1077 } else {
1078 ALOGE("x86_64: invokeFunction memalign error, still use params which is not 16 bytes aligned.");
1079 }
1080 }
1081#endif
Jason Sams709a0972012-11-15 18:18:04 -08001082
1083 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -08001084 reinterpret_cast<void (*)(const void *, uint32_t)>(
Yang Nid9bae682015-01-20 15:31:15 -08001085 mScriptExec->getInvokeFunction(slot))(ap? (const void *) ap: params, paramLength);
Yong Cheneaba5a32014-12-12 13:25:18 +08001086
Jason Sams709a0972012-11-15 18:18:04 -08001087 mCtx->setTLS(oldTLS);
1088}
1089
1090void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
1091 //rsAssert(!script->mFieldIsObject[slot]);
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -08001092 //ALOGE("setGlobalVar %i %p %zu", slot, data, dataLength);
Jason Sams709a0972012-11-15 18:18:04 -08001093
1094 //if (mIntrinsicID) {
1095 //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
1096 //return;
1097 //}
1098
Yang Nid9bae682015-01-20 15:31:15 -08001099 int32_t *destPtr = reinterpret_cast<int32_t *>(mScriptExec->getFieldAddress(slot));
Jason Sams709a0972012-11-15 18:18:04 -08001100 if (!destPtr) {
1101 //ALOGV("Calling setVar on slot = %i which is null", slot);
1102 return;
1103 }
1104
1105 memcpy(destPtr, data, dataLength);
1106}
1107
Tim Murray9c642392013-04-11 13:29:59 -07001108void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
1109 //rsAssert(!script->mFieldIsObject[slot]);
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -08001110 //ALOGE("getGlobalVar %i %p %zu", slot, data, dataLength);
Tim Murray9c642392013-04-11 13:29:59 -07001111
Yang Nid9bae682015-01-20 15:31:15 -08001112 int32_t *srcPtr = reinterpret_cast<int32_t *>(mScriptExec->getFieldAddress(slot));
Tim Murray9c642392013-04-11 13:29:59 -07001113 if (!srcPtr) {
1114 //ALOGV("Calling setVar on slot = %i which is null", slot);
1115 return;
1116 }
1117 memcpy(data, srcPtr, dataLength);
1118}
1119
1120
Jason Sams709a0972012-11-15 18:18:04 -08001121void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
1122 const Element *elem,
Stephen Hinesac8d1462014-06-25 00:01:23 -07001123 const uint32_t *dims, size_t dimLength) {
Yang Nid9bae682015-01-20 15:31:15 -08001124 int32_t *destPtr = reinterpret_cast<int32_t *>(mScriptExec->getFieldAddress(slot));
Jason Sams709a0972012-11-15 18:18:04 -08001125 if (!destPtr) {
1126 //ALOGV("Calling setVar on slot = %i which is null", slot);
1127 return;
1128 }
1129
1130 // We want to look at dimension in terms of integer components,
1131 // but dimLength is given in terms of bytes.
1132 dimLength /= sizeof(int);
1133
1134 // Only a single dimension is currently supported.
1135 rsAssert(dimLength == 1);
1136 if (dimLength == 1) {
1137 // First do the increment loop.
1138 size_t stride = elem->getSizeBytes();
1139 const char *cVal = reinterpret_cast<const char *>(data);
Stephen Hinesac8d1462014-06-25 00:01:23 -07001140 for (uint32_t i = 0; i < dims[0]; i++) {
Jason Sams709a0972012-11-15 18:18:04 -08001141 elem->incRefs(cVal);
1142 cVal += stride;
1143 }
1144
1145 // Decrement loop comes after (to prevent race conditions).
1146 char *oldVal = reinterpret_cast<char *>(destPtr);
Stephen Hinesac8d1462014-06-25 00:01:23 -07001147 for (uint32_t i = 0; i < dims[0]; i++) {
Jason Sams709a0972012-11-15 18:18:04 -08001148 elem->decRefs(oldVal);
1149 oldVal += stride;
1150 }
1151 }
1152
1153 memcpy(destPtr, data, dataLength);
1154}
1155
1156void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
1157
1158 //rsAssert(!script->mFieldIsObject[slot]);
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -08001159 //ALOGE("setGlobalBind %i %p", slot, data);
Jason Sams709a0972012-11-15 18:18:04 -08001160
Yang Nid9bae682015-01-20 15:31:15 -08001161 int32_t *destPtr = reinterpret_cast<int32_t *>(mScriptExec->getFieldAddress(slot));
Jason Sams709a0972012-11-15 18:18:04 -08001162 if (!destPtr) {
1163 //ALOGV("Calling setVar on slot = %i which is null", slot);
1164 return;
1165 }
1166
Chris Wailes44bef6f2014-08-12 13:51:10 -07001167 void *ptr = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001168 mBoundAllocs[slot] = data;
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -08001169 if (data) {
Jason Sams709a0972012-11-15 18:18:04 -08001170 ptr = data->mHal.drvState.lod[0].mallocPtr;
1171 }
1172 memcpy(destPtr, &ptr, sizeof(void *));
1173}
1174
1175void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
1176
1177 //rsAssert(script->mFieldIsObject[slot]);
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -08001178 //ALOGE("setGlobalObj %i %p", slot, data);
Jason Sams709a0972012-11-15 18:18:04 -08001179
Yang Nid9bae682015-01-20 15:31:15 -08001180 int32_t *destPtr = reinterpret_cast<int32_t *>(mScriptExec->getFieldAddress(slot));
Jason Sams709a0972012-11-15 18:18:04 -08001181 if (!destPtr) {
1182 //ALOGV("Calling setVar on slot = %i which is null", slot);
1183 return;
1184 }
1185
Jason Sams05ef73f2014-08-05 14:59:22 -07001186 rsrSetObject(mCtx->getContext(), (rs_object_base *)destPtr, data);
Jason Sams709a0972012-11-15 18:18:04 -08001187}
1188
1189RsdCpuScriptImpl::~RsdCpuScriptImpl() {
Jason Sams110f1812013-03-14 16:02:18 -07001190#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001191 if (mCompilerDriver) {
1192 delete mCompilerDriver;
1193 }
Stephen Hines45e753a2015-01-19 20:58:44 -08001194#endif
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -08001195
Yang Nid9bae682015-01-20 15:31:15 -08001196 if (mScriptExec != nullptr) {
1197 delete mScriptExec;
Pirama Arumuga Nainardc0d8f72014-12-02 15:23:38 -08001198 }
Jason Sams110f1812013-03-14 16:02:18 -07001199 if (mBoundAllocs) delete[] mBoundAllocs;
1200 if (mScriptSO) {
1201 dlclose(mScriptSO);
1202 }
Jason Sams709a0972012-11-15 18:18:04 -08001203}
1204
1205Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const {
1206 if (!ptr) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001207 return nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001208 }
1209
1210 for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) {
1211 Allocation *a = mBoundAllocs[ct];
1212 if (!a) continue;
1213 if (a->mHal.drvState.lod[0].mallocPtr == ptr) {
1214 return a;
1215 }
1216 }
1217 ALOGE("rsGetAllocation, failed to find %p", ptr);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001218 return nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001219}
1220
Chris Wailesf3712132014-07-16 15:18:30 -07001221void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation ** ains,
1222 uint32_t inLen, Allocation * aout,
1223 const void * usr, uint32_t usrLen,
1224 const RsScriptCall *sc) {}
Jason Sams17e3cdc2013-09-09 17:32:16 -07001225
Chris Wailesf3712132014-07-16 15:18:30 -07001226void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation ** ains,
1227 uint32_t inLen, Allocation * aout,
1228 const void * usr, uint32_t usrLen,
1229 const RsScriptCall *sc) {}
Jason Sams17e3cdc2013-09-09 17:32:16 -07001230
Jason Sams709a0972012-11-15 18:18:04 -08001231
1232}
1233}