blob: f38c898373c9c448549055c6f62a01c476aeed8c [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
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 Hinesee48c0b2013-10-30 17:48:30 -070027 #include <sys/stat.h>
Stephen Hinesc2c11cc2013-07-19 01:07:42 -070028 #include <unistd.h>
Stephen Hines7d774852014-10-01 12:57:57 -070029 #include <fstream>
30 #include <iostream>
Jason Sams110f1812013-03-14 16:02:18 -070031#else
32 #include <bcc/BCCContext.h>
Stephen Hines82e0a672014-05-05 15:40:56 -070033 #include <bcc/Config/Config.h>
Jason Sams110f1812013-03-14 16:02:18 -070034 #include <bcc/Renderscript/RSCompilerDriver.h>
35 #include <bcc/Renderscript/RSExecutable.h>
36 #include <bcc/Renderscript/RSInfo.h>
Stephen Hinesb58d9ad2013-06-19 19:26:19 -070037 #include <bcinfo/MetadataExtractor.h>
Stephen Hinesba17ae42013-06-05 17:18:04 -070038 #include <cutils/properties.h>
Stephen Hinesb58d9ad2013-06-19 19:26:19 -070039
40 #include <sys/types.h>
41 #include <sys/wait.h>
42 #include <unistd.h>
Stephen Hines00511322014-01-31 11:20:23 -080043
44 #include <string>
45 #include <vector>
Jason Sams110f1812013-03-14 16:02:18 -070046#endif
Jason Sams709a0972012-11-15 18:18:04 -080047
Stephen Hinesba17ae42013-06-05 17:18:04 -070048namespace {
Stephen Hinesc2c11cc2013-07-19 01:07:42 -070049#ifdef RS_COMPATIBILITY_LIB
50
51// Create a len length string containing random characters from [A-Za-z0-9].
52static std::string getRandomString(size_t len) {
53 char buf[len + 1];
54 for (size_t i = 0; i < len; i++) {
55 uint32_t r = arc4random() & 0xffff;
56 r %= 62;
57 if (r < 26) {
58 // lowercase
59 buf[i] = 'a' + r;
60 } else if (r < 52) {
61 // uppercase
62 buf[i] = 'A' + (r - 26);
63 } else {
64 // Use a number
65 buf[i] = '0' + (r - 52);
66 }
67 }
68 buf[len] = '\0';
69 return std::string(buf);
70}
71
Stephen Hinesee48c0b2013-10-30 17:48:30 -070072// Check if a path exists and attempt to create it if it doesn't.
73static bool ensureCacheDirExists(const char *path) {
74 if (access(path, R_OK | W_OK | X_OK) == 0) {
75 // Done if we can rwx the directory
76 return true;
77 }
78 if (mkdir(path, 0700) == 0) {
79 return true;
80 }
81 return false;
82}
83
Stephen Hines7d774852014-10-01 12:57:57 -070084// Copy the file named \p srcFile to \p dstFile.
85// Return 0 on success and -1 if anything wasn't copied.
86static int copyFile(const char *dstFile, const char *srcFile) {
87 std::ifstream srcStream(srcFile);
88 if (!srcStream) {
89 ALOGE("Could not verify or read source file: %s", srcFile);
90 return -1;
91 }
92 std::ofstream dstStream(dstFile);
93 if (!dstStream) {
94 ALOGE("Could not verify or write destination file: %s", dstFile);
95 return -1;
96 }
97 dstStream << srcStream.rdbuf();
98 if (!dstStream) {
99 ALOGE("Could not write destination file: %s", dstFile);
100 return -1;
101 }
102
103 srcStream.close();
104 dstStream.close();
105
106 return 0;
107}
108
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700109// Attempt to load the shared library from origName, but then fall back to
Stephen Hines7d774852014-10-01 12:57:57 -0700110// creating a copy of the shared library if necessary (to ensure instancing).
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700111// This function returns the dlopen()-ed handle if successful.
112static void *loadSOHelper(const char *origName, const char *cacheDir,
113 const char *resName) {
114 // Keep track of which .so libraries have been loaded. Once a library is
Stephen Hines7d774852014-10-01 12:57:57 -0700115 // in the set (per-process granularity), we must instead make a copy of
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700116 // the original shared object (randomly named .so file) and load that one
117 // instead. If we don't do this, we end up aliasing global data between
118 // the various Script instances (which are supposed to be completely
119 // independent).
120 static std::set<std::string> LoadedLibraries;
121
Chris Wailes44bef6f2014-08-12 13:51:10 -0700122 void *loaded = nullptr;
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700123
124 // Skip everything if we don't even have the original library available.
125 if (access(origName, F_OK) != 0) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700126 return nullptr;
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700127 }
128
129 // Common path is that we have not loaded this Script/library before.
130 if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
131 loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
132 if (loaded) {
133 LoadedLibraries.insert(origName);
134 }
135 return loaded;
136 }
137
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700138 std::string newName(cacheDir);
Stephen Hinesee48c0b2013-10-30 17:48:30 -0700139 newName.append("/com.android.renderscript.cache/");
140
141 if (!ensureCacheDirExists(newName.c_str())) {
142 ALOGE("Could not verify or create cache dir: %s", cacheDir);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700143 return nullptr;
Stephen Hinesee48c0b2013-10-30 17:48:30 -0700144 }
145
Stephen Hines7d774852014-10-01 12:57:57 -0700146 // Construct an appropriately randomized filename for the copy.
Stephen Hinesee48c0b2013-10-30 17:48:30 -0700147 newName.append("librs.");
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700148 newName.append(resName);
149 newName.append("#");
150 newName.append(getRandomString(6)); // 62^6 potential filename variants.
151 newName.append(".so");
152
Stephen Hines7d774852014-10-01 12:57:57 -0700153 int r = copyFile(newName.c_str(), origName);
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700154 if (r != 0) {
Stephen Hines7d774852014-10-01 12:57:57 -0700155 ALOGE("Could not create copy %s -> %s", origName, newName.c_str());
Chris Wailes44bef6f2014-08-12 13:51:10 -0700156 return nullptr;
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700157 }
158 loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
159 r = unlink(newName.c_str());
160 if (r != 0) {
Stephen Hines7d774852014-10-01 12:57:57 -0700161 ALOGE("Could not unlink copy %s", newName.c_str());
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700162 }
163 if (loaded) {
164 LoadedLibraries.insert(newName.c_str());
165 }
166
167 return loaded;
168}
169
170// Load the shared library referred to by cacheDir and resName. If we have
Stephen Hines7d774852014-10-01 12:57:57 -0700171// already loaded this library, we instead create a new copy (in the
172// cache dir) and then load that. We then immediately destroy the copy.
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700173// This is required behavior to implement script instancing for the support
174// library, since shared objects are loaded and de-duped by name only.
175static void *loadSharedLibrary(const char *cacheDir, const char *resName) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700176 void *loaded = nullptr;
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700177#ifndef RS_SERVER
178 std::string scriptSOName(cacheDir);
179 size_t cutPos = scriptSOName.rfind("cache");
180 if (cutPos != std::string::npos) {
181 scriptSOName.erase(cutPos);
182 } else {
183 ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir);
184 }
185 scriptSOName.append("/lib/librs.");
186#else
187 std::string scriptSOName("lib");
188#endif
189 scriptSOName.append(resName);
190 scriptSOName.append(".so");
191
192 // We should check if we can load the library from the standard app
193 // location for shared libraries first.
194 loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName);
195
Chris Wailes44bef6f2014-08-12 13:51:10 -0700196 if (loaded == nullptr) {
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700197 ALOGE("Unable to open shared library (%s): %s",
198 scriptSOName.c_str(), dlerror());
199
200 // One final attempt to find the library in "/system/lib".
201 // We do this to allow bundled applications to use the compatibility
202 // library fallback path. Those applications don't have a private
203 // library path, so they need to install to the system directly.
204 // Note that this is really just a testing path.
Chris Wailes93d6bc82014-07-28 16:54:38 -0700205 std::string scriptSONameSystem("/system/lib/librs.");
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700206 scriptSONameSystem.append(resName);
207 scriptSONameSystem.append(".so");
208 loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir,
209 resName);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700210 if (loaded == nullptr) {
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700211 ALOGE("Unable to open system shared library (%s): %s",
212 scriptSONameSystem.c_str(), dlerror());
213 }
214 }
215
216 return loaded;
217}
218
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700219#else // RS_COMPATIBILITY_LIB is not defined
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700220
Stephen Hinesba17ae42013-06-05 17:18:04 -0700221static bool is_force_recompile() {
222#ifdef RS_SERVER
223 return false;
224#else
225 char buf[PROPERTY_VALUE_MAX];
226
227 // Re-compile if floating point precision has been overridden.
228 property_get("debug.rs.precision", buf, "");
229 if (buf[0] != '\0') {
230 return true;
231 }
232
233 // Re-compile if debug.rs.forcerecompile is set.
234 property_get("debug.rs.forcerecompile", buf, "0");
235 if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
236 return true;
237 } else {
238 return false;
239 }
240#endif // RS_SERVER
241}
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700242
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700243const static char *BCC_EXE_PATH = "/system/bin/bcc";
244
Chris Wailes6847e732014-08-11 17:30:51 -0700245static void setCompileArguments(std::vector<const char*>* args,
246 const std::string& bcFileName,
247 const char* cacheDir, const char* resName,
248 const char* core_lib, bool useRSDebugContext,
249 const char* bccPluginName) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700250 rsAssert(cacheDir && resName && core_lib);
251 args->push_back(BCC_EXE_PATH);
Tim Murray687cfe82015-01-08 14:59:38 -0800252 args->push_back("-unroll-runtime");
253 args->push_back("-scalarize-load-store");
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700254 args->push_back("-o");
255 args->push_back(resName);
256 args->push_back("-output_path");
257 args->push_back(cacheDir);
258 args->push_back("-bclib");
259 args->push_back(core_lib);
260 args->push_back("-mtriple");
261 args->push_back(DEFAULT_TARGET_TRIPLE_STRING);
262
Tim Murray358ffb82014-12-09 11:53:06 -0800263 // Enable workaround for A53 codegen by default.
264#if defined(__aarch64__) && !defined(DISABLE_A53_WORKAROUND)
265 args->push_back("-aarch64-fix-cortex-a53-835769");
266#endif
267
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700268 // Execute the bcc compiler.
269 if (useRSDebugContext) {
270 args->push_back("-rs-debug-ctx");
271 } else {
272 // Only load additional libraries for compiles that don't use
273 // the debug context.
274 if (bccPluginName && strlen(bccPluginName) > 0) {
275 args->push_back("-load");
276 args->push_back(bccPluginName);
277 }
278 }
279
Chris Wailes6847e732014-08-11 17:30:51 -0700280 args->push_back(bcFileName.c_str());
Chris Wailes44bef6f2014-08-12 13:51:10 -0700281 args->push_back(nullptr);
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700282}
283
Chris Wailes6847e732014-08-11 17:30:51 -0700284static bool compileBitcode(const std::string &bcFileName,
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700285 const char *bitcode,
286 size_t bitcodeSize,
Chris Wailes6847e732014-08-11 17:30:51 -0700287 const char **compileArguments,
288 const std::string &compileCommandLine) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700289 rsAssert(bitcode && bitcodeSize);
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700290
Chris Wailes6847e732014-08-11 17:30:51 -0700291 FILE *bcfile = fopen(bcFileName.c_str(), "w");
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700292 if (!bcfile) {
Chris Wailes6847e732014-08-11 17:30:51 -0700293 ALOGE("Could not write to %s", bcFileName.c_str());
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700294 return false;
295 }
296 size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile);
297 fclose(bcfile);
298 if (nwritten != bitcodeSize) {
299 ALOGE("Could not write %zu bytes to %s", bitcodeSize,
Chris Wailes6847e732014-08-11 17:30:51 -0700300 bcFileName.c_str());
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700301 return false;
302 }
303
304 pid_t pid = fork();
Stephen Hines00511322014-01-31 11:20:23 -0800305
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700306 switch (pid) {
307 case -1: { // Error occurred (we attempt no recovery)
308 ALOGE("Couldn't fork for bcc compiler execution");
309 return false;
310 }
311 case 0: { // Child process
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700312 ALOGV("Invoking BCC with: %s", compileCommandLine.c_str());
313 execv(BCC_EXE_PATH, (char* const*)compileArguments);
Stephen Hines00511322014-01-31 11:20:23 -0800314
Stephen Hines00511322014-01-31 11:20:23 -0800315 ALOGE("execv() failed: %s", strerror(errno));
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700316 abort();
317 return false;
318 }
319 default: { // Parent process (actual driver)
320 // Wait on child process to finish compiling the source.
321 int status = 0;
322 pid_t w = waitpid(pid, &status, 0);
323 if (w == -1) {
324 ALOGE("Could not wait for bcc compiler");
325 return false;
326 }
327
328 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
329 return true;
330 }
331
332 ALOGE("bcc compiler terminated unexpectedly");
333 return false;
334 }
335 }
336}
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700337
Stephen Hinesba17ae42013-06-05 17:18:04 -0700338#endif // !defined(RS_COMPATIBILITY_LIB)
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700339} // namespace
Stephen Hinesba17ae42013-06-05 17:18:04 -0700340
Jason Sams709a0972012-11-15 18:18:04 -0800341namespace android {
342namespace renderscript {
343
Jason Sams110f1812013-03-14 16:02:18 -0700344#ifdef RS_COMPATIBILITY_LIB
345#define MAXLINE 500
346#define MAKE_STR_HELPER(S) #S
347#define MAKE_STR(S) MAKE_STR_HELPER(S)
348#define EXPORT_VAR_STR "exportVarCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700349#define EXPORT_FUNC_STR "exportFuncCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700350#define EXPORT_FOREACH_STR "exportForEachCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700351#define OBJECT_SLOT_STR "objectSlotCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700352
353// Copy up to a newline or size chars from str -> s, updating str
Chris Wailes44bef6f2014-08-12 13:51:10 -0700354// Returns s when successful and nullptr when '\0' is finally reached.
Jason Sams110f1812013-03-14 16:02:18 -0700355static char* strgets(char *s, int size, const char **ppstr) {
356 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700357 return nullptr;
Jason Sams110f1812013-03-14 16:02:18 -0700358 }
359
360 int i;
361 for (i = 0; i < (size - 1); i++) {
362 s[i] = **ppstr;
363 (*ppstr)++;
364 if (s[i] == '\0') {
365 return s;
366 } else if (s[i] == '\n') {
367 s[i+1] = '\0';
368 return s;
369 }
370 }
371
372 // size has been exceeded.
373 s[i] = '\0';
374
375 return s;
376}
377#endif
Jason Sams709a0972012-11-15 18:18:04 -0800378
379RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
380 mCtx = ctx;
381 mScript = s;
382
Jason Sams110f1812013-03-14 16:02:18 -0700383#ifdef RS_COMPATIBILITY_LIB
Chris Wailes44bef6f2014-08-12 13:51:10 -0700384 mScriptSO = nullptr;
385 mInvokeFunctions = nullptr;
386 mForEachFunctions = nullptr;
387 mFieldAddress = nullptr;
388 mFieldIsObject = nullptr;
389 mForEachSignatures = nullptr;
Jason Sams110f1812013-03-14 16:02:18 -0700390#else
Chris Wailes44bef6f2014-08-12 13:51:10 -0700391 mCompilerDriver = nullptr;
392 mExecutable = nullptr;
Jason Sams110f1812013-03-14 16:02:18 -0700393#endif
394
Tim Murraye195a3f2014-03-13 15:04:58 -0700395
Chris Wailes44bef6f2014-08-12 13:51:10 -0700396 mRoot = nullptr;
397 mRootExpand = nullptr;
398 mInit = nullptr;
399 mFreeChildren = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800400
Jason Sams709a0972012-11-15 18:18:04 -0800401
Chris Wailes44bef6f2014-08-12 13:51:10 -0700402 mBoundAllocs = nullptr;
403 mIntrinsicData = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800404 mIsThreadable = true;
405}
406
407
408bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
409 uint8_t const *bitcode, size_t bitcodeSize,
Stephen Hines00511322014-01-31 11:20:23 -0800410 uint32_t flags, char const *bccPluginName) {
Jason Sams709a0972012-11-15 18:18:04 -0800411 //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
412 //ALOGE("rsdScriptInit %p %p", rsc, script);
413
414 mCtx->lockMutex();
Jason Sams110f1812013-03-14 16:02:18 -0700415#ifndef RS_COMPATIBILITY_LIB
Stephen Hines00511322014-01-31 11:20:23 -0800416 bool useRSDebugContext = false;
Jason Sams709a0972012-11-15 18:18:04 -0800417
Chris Wailes44bef6f2014-08-12 13:51:10 -0700418 mCompilerDriver = nullptr;
419 mExecutable = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800420
Jason Sams709a0972012-11-15 18:18:04 -0800421 mCompilerDriver = new bcc::RSCompilerDriver();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700422 if (mCompilerDriver == nullptr) {
Jason Sams709a0972012-11-15 18:18:04 -0800423 ALOGE("bcc: FAILS to create compiler driver (out of memory)");
424 mCtx->unlockMutex();
425 return false;
426 }
427
Stephen Hines25e3af52014-05-21 21:23:08 -0700428 // Configure symbol resolvers (via compiler-rt and the RS runtime).
429 mRSRuntime.setLookupFunction(lookupRuntimeStub);
430 mRSRuntime.setContext(this);
431 mResolver.chainResolver(mCompilerRuntime);
432 mResolver.chainResolver(mRSRuntime);
Jason Sams709a0972012-11-15 18:18:04 -0800433
Stephen Hinesb7d9c802013-04-29 19:13:09 -0700434 // Run any compiler setup functions we have been provided with.
435 RSSetupCompilerCallback setupCompilerCallback =
436 mCtx->getSetupCompilerCallback();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700437 if (setupCompilerCallback != nullptr) {
Stephen Hinesb7d9c802013-04-29 19:13:09 -0700438 setupCompilerCallback(mCompilerDriver);
439 }
440
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700441 bcinfo::MetadataExtractor bitcodeMetadata((const char *) bitcode, bitcodeSize);
442 if (!bitcodeMetadata.extract()) {
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700443 ALOGE("Could not extract metadata from bitcode");
Stephen Hinesf94e8db2014-06-26 11:55:29 -0700444 mCtx->unlockMutex();
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700445 return false;
446 }
447
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700448 const char* core_lib = findCoreLib(bitcodeMetadata, (const char*)bitcode, bitcodeSize);
Stephen Hinescca3d6c2013-04-15 01:06:39 -0700449
450 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
Stephen Hinesf47e8b42013-04-18 01:06:29 -0700451 mCompilerDriver->setDebugContext(true);
Stephen Hines00511322014-01-31 11:20:23 -0800452 useRSDebugContext = true;
Stephen Hinescca3d6c2013-04-15 01:06:39 -0700453 }
Stephen Hinesba17ae42013-06-05 17:18:04 -0700454
Chris Wailes6847e732014-08-11 17:30:51 -0700455 std::string bcFileName(cacheDir);
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700456 bcFileName.append("/");
457 bcFileName.append(resName);
458 bcFileName.append(".bc");
459
460 std::vector<const char*> compileArguments;
461 setCompileArguments(&compileArguments, bcFileName, cacheDir, resName, core_lib,
462 useRSDebugContext, bccPluginName);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700463 // The last argument of compileArguments ia a nullptr, so remove 1 from the size.
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700464 std::string compileCommandLine =
465 bcc::getCommandLine(compileArguments.size() - 1, compileArguments.data());
466
467 if (!is_force_recompile()) {
468 // Load the compiled script that's in the cache, if any.
469 mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
470 bitcodeSize, compileCommandLine.c_str(),
471 mResolver);
472 }
473
474 // If we can't, it's either not there or out of date. We compile the bit code and try loading
475 // again.
Chris Wailes44bef6f2014-08-12 13:51:10 -0700476 if (mExecutable == nullptr) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700477 if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize, compileArguments.data(),
478 compileCommandLine)) {
479 ALOGE("bcc: FAILS to compile '%s'", resName);
480 mCtx->unlockMutex();
481 return false;
482 }
483 mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
484 bitcodeSize, compileCommandLine.c_str(),
485 mResolver);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700486 if (mExecutable == nullptr) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700487 ALOGE("bcc: FAILS to load freshly compiled executable for '%s'", resName);
488 mCtx->unlockMutex();
489 return false;
Stephen Hinesba17ae42013-06-05 17:18:04 -0700490 }
491 }
Jason Sams709a0972012-11-15 18:18:04 -0800492
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700493 mExecutable->setThreadable(mIsThreadable);
494 if (!mExecutable->syncInfo()) {
Jason Sams709a0972012-11-15 18:18:04 -0800495 ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
496 }
497
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700498 mRoot = reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root"));
Jason Sams709a0972012-11-15 18:18:04 -0800499 mRootExpand =
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700500 reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root.expand"));
501 mInit = reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress("init"));
Jason Sams709a0972012-11-15 18:18:04 -0800502 mFreeChildren =
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700503 reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress(".rs.dtor"));
Jason Sams709a0972012-11-15 18:18:04 -0800504
505
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700506 if (bitcodeMetadata.getExportVarCount()) {
507 mBoundAllocs = new Allocation *[bitcodeMetadata.getExportVarCount()];
508 memset(mBoundAllocs, 0, sizeof(void *) * bitcodeMetadata.getExportVarCount());
Tim Murray29809d12014-05-28 12:04:19 -0700509 }
510
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700511 for (size_t i = 0; i < bitcodeMetadata.getExportForEachSignatureCount(); i++) {
512 char* name = new char[strlen(bitcodeMetadata.getExportForEachNameList()[i]) + 1];
513 mExportedForEachFuncList.push_back(
514 std::make_pair(name, bitcodeMetadata.getExportForEachSignatureList()[i]));
Jason Sams709a0972012-11-15 18:18:04 -0800515 }
516
Jean-Luc Brouilletf4d216e2014-06-09 18:04:16 -0700517#else // RS_COMPATIBILITY_LIB is defined
Jason Sams110f1812013-03-14 16:02:18 -0700518
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700519 mScriptSO = loadSharedLibrary(cacheDir, resName);
Jason Sams110f1812013-03-14 16:02:18 -0700520
521 if (mScriptSO) {
522 char line[MAXLINE];
523 mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
524 if (mRoot) {
525 //ALOGE("Found root(): %p", mRoot);
526 }
527 mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
528 if (mRootExpand) {
529 //ALOGE("Found root.expand(): %p", mRootExpand);
530 }
531 mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
532 if (mInit) {
533 //ALOGE("Found init(): %p", mInit);
534 }
535 mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
536 if (mFreeChildren) {
537 //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
538 }
539
540 const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
541 if (rsInfo) {
542 //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
543 }
544
545 size_t varCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700546 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700547 goto error;
548 }
549 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
550 ALOGE("Invalid export var count!: %s", line);
551 goto error;
552 }
553
554 mExportedVariableCount = varCount;
555 //ALOGE("varCount: %zu", varCount);
556 if (varCount > 0) {
557 // Start by creating/zeroing this member, since we don't want to
558 // accidentally clean up invalid pointers later (if we error out).
559 mFieldIsObject = new bool[varCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700560 if (mFieldIsObject == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700561 goto error;
562 }
563 memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
564 mFieldAddress = new void*[varCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700565 if (mFieldAddress == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700566 goto error;
567 }
568 for (size_t i = 0; i < varCount; ++i) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700569 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700570 goto error;
571 }
572 char *c = strrchr(line, '\n');
573 if (c) {
574 *c = '\0';
575 }
576 mFieldAddress[i] = dlsym(mScriptSO, line);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700577 if (mFieldAddress[i] == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700578 ALOGE("Failed to find variable address for %s: %s",
579 line, dlerror());
580 // Not a critical error if we don't find a global variable.
581 }
582 else {
583 //ALOGE("Found variable %s at %p", line,
584 //mFieldAddress[i]);
585 }
586 }
587 }
588
589 size_t funcCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700590 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700591 goto error;
592 }
593 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
594 ALOGE("Invalid export func count!: %s", line);
595 goto error;
596 }
597
598 mExportedFunctionCount = funcCount;
599 //ALOGE("funcCount: %zu", funcCount);
600
601 if (funcCount > 0) {
602 mInvokeFunctions = new InvokeFunc_t[funcCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700603 if (mInvokeFunctions == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700604 goto error;
605 }
606 for (size_t i = 0; i < funcCount; ++i) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700607 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700608 goto error;
609 }
610 char *c = strrchr(line, '\n');
611 if (c) {
612 *c = '\0';
613 }
614
615 mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700616 if (mInvokeFunctions[i] == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700617 ALOGE("Failed to get function address for %s(): %s",
618 line, dlerror());
619 goto error;
620 }
621 else {
622 //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
623 }
624 }
625 }
626
627 size_t forEachCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700628 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700629 goto error;
630 }
631 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
632 ALOGE("Invalid export forEach count!: %s", line);
633 goto error;
634 }
635
636 if (forEachCount > 0) {
637
638 mForEachSignatures = new uint32_t[forEachCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700639 if (mForEachSignatures == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700640 goto error;
641 }
642 mForEachFunctions = new ForEachFunc_t[forEachCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700643 if (mForEachFunctions == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700644 goto error;
645 }
646 for (size_t i = 0; i < forEachCount; ++i) {
647 unsigned int tmpSig = 0;
648 char tmpName[MAXLINE];
649
Chris Wailes44bef6f2014-08-12 13:51:10 -0700650 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700651 goto error;
652 }
653 if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
654 &tmpSig, tmpName) != 2) {
655 ALOGE("Invalid export forEach!: %s", line);
656 goto error;
657 }
658
659 // Lookup the expanded ForEach kernel.
660 strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
661 mForEachSignatures[i] = tmpSig;
662 mForEachFunctions[i] =
663 (ForEachFunc_t) dlsym(mScriptSO, tmpName);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700664 if (i != 0 && mForEachFunctions[i] == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700665 // Ignore missing root.expand functions.
666 // root() is always specified at location 0.
Stephen Hinesef7481e2013-04-09 19:05:27 -0700667 ALOGE("Failed to find forEach function address for %s: %s",
668 tmpName, dlerror());
669 goto error;
Jason Sams110f1812013-03-14 16:02:18 -0700670 }
671 else {
672 //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
673 }
674 }
675 }
676
677 size_t objectSlotCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700678 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700679 goto error;
680 }
681 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
682 ALOGE("Invalid object slot count!: %s", line);
683 goto error;
684 }
685
686 if (objectSlotCount > 0) {
687 rsAssert(varCount > 0);
688 for (size_t i = 0; i < objectSlotCount; ++i) {
689 uint32_t varNum = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700690 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700691 goto error;
692 }
693 if (sscanf(line, "%u", &varNum) != 1) {
694 ALOGE("Invalid object slot!: %s", line);
695 goto error;
696 }
697
698 if (varNum < varCount) {
699 mFieldIsObject[varNum] = true;
700 }
701 }
702 }
703
704 if (varCount > 0) {
705 mBoundAllocs = new Allocation *[varCount];
706 memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
707 }
708
709 if (mScriptSO == (void*)1) {
710 //rsdLookupRuntimeStub(script, "acos");
711 }
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700712 } else {
713 goto error;
Jason Sams110f1812013-03-14 16:02:18 -0700714 }
715#endif
Jason Sams709a0972012-11-15 18:18:04 -0800716 mCtx->unlockMutex();
717 return true;
Jason Sams110f1812013-03-14 16:02:18 -0700718
719#ifdef RS_COMPATIBILITY_LIB
720error:
721
722 mCtx->unlockMutex();
723 delete[] mInvokeFunctions;
724 delete[] mForEachFunctions;
725 delete[] mFieldAddress;
726 delete[] mFieldIsObject;
727 delete[] mForEachSignatures;
728 delete[] mBoundAllocs;
729 if (mScriptSO) {
730 dlclose(mScriptSO);
731 }
732 return false;
733#endif
Jason Sams709a0972012-11-15 18:18:04 -0800734}
735
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700736#ifndef RS_COMPATIBILITY_LIB
737
738#ifdef __LP64__
739#define SYSLIBPATH "/system/lib64"
740#else
741#define SYSLIBPATH "/system/lib"
742#endif
743
744const char* RsdCpuScriptImpl::findCoreLib(const bcinfo::MetadataExtractor& ME, const char* bitcode,
745 size_t bitcodeSize) {
746 const char* defaultLib = SYSLIBPATH"/libclcore.bc";
747
748 // If we're debugging, use the debug library.
749 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
750 return SYSLIBPATH"/libclcore_debug.bc";
751 }
752
753 // If a callback has been registered to specify a library, use that.
754 RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700755 if (selectRTCallback != nullptr) {
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700756 return selectRTCallback((const char*)bitcode, bitcodeSize);
757 }
758
759 // Check for a platform specific library
760#if defined(ARCH_ARM_HAVE_NEON) && !defined(DISABLE_CLCORE_NEON)
761 enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision();
Jean-Luc Brouilletf4d38362014-07-09 17:46:03 -0700762 if (prec == bcinfo::RS_FP_Relaxed) {
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700763 // NEON-capable ARMv7a devices can use an accelerated math library
764 // for all reduced precision scripts.
765 // ARMv8 does not use NEON, as ASIMD can be used with all precision
766 // levels.
767 return SYSLIBPATH"/libclcore_neon.bc";
768 } else {
769 return defaultLib;
770 }
771#elif defined(__i386__) || defined(__x86_64__)
772 // x86 devices will use an optimized library.
773 return SYSLIBPATH"/libclcore_x86.bc";
774#else
775 return defaultLib;
776#endif
777}
778
779#endif
780
Jason Sams709a0972012-11-15 18:18:04 -0800781void RsdCpuScriptImpl::populateScript(Script *script) {
Jason Sams110f1812013-03-14 16:02:18 -0700782#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -0800783 // Copy info over to runtime
Tim Murray29809d12014-05-28 12:04:19 -0700784 script->mHal.info.exportedFunctionCount = mExecutable->getExportFuncAddrs().size();
785 script->mHal.info.exportedVariableCount = mExecutable->getExportVarAddrs().size();
786 script->mHal.info.exportedForeachFuncList = &mExportedForEachFuncList[0];
787 script->mHal.info.exportedPragmaCount = mExecutable->getPragmaKeys().size();
Jason Sams709a0972012-11-15 18:18:04 -0800788 script->mHal.info.exportedPragmaKeyList =
Chris Wailes70d49712014-08-08 14:42:33 -0700789 const_cast<const char**>(&mExecutable->getPragmaKeys().front());
Jason Sams709a0972012-11-15 18:18:04 -0800790 script->mHal.info.exportedPragmaValueList =
Chris Wailes70d49712014-08-08 14:42:33 -0700791 const_cast<const char**>(&mExecutable->getPragmaValues().front());
Jason Sams709a0972012-11-15 18:18:04 -0800792
793 if (mRootExpand) {
794 script->mHal.info.root = mRootExpand;
795 } else {
796 script->mHal.info.root = mRoot;
797 }
Jason Sams110f1812013-03-14 16:02:18 -0700798#else
799 // Copy info over to runtime
800 script->mHal.info.exportedFunctionCount = mExportedFunctionCount;
801 script->mHal.info.exportedVariableCount = mExportedVariableCount;
802 script->mHal.info.exportedPragmaCount = 0;
803 script->mHal.info.exportedPragmaKeyList = 0;
804 script->mHal.info.exportedPragmaValueList = 0;
805
806 // Bug, need to stash in metadata
807 if (mRootExpand) {
808 script->mHal.info.root = mRootExpand;
809 } else {
810 script->mHal.info.root = mRoot;
811 }
812#endif
Jason Sams709a0972012-11-15 18:18:04 -0800813}
814
Jason Sams709a0972012-11-15 18:18:04 -0800815
816typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
817
Chris Wailesf3712132014-07-16 15:18:30 -0700818void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation ** ains,
819 uint32_t inLen,
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700820 Allocation * aout,
821 const void * usr, uint32_t usrLen,
822 const RsScriptCall *sc,
823 MTLaunchStruct *mtls) {
824
825 memset(mtls, 0, sizeof(MTLaunchStruct));
826
Chris Wailesf3712132014-07-16 15:18:30 -0700827 for (int index = inLen; --index >= 0;) {
828 const Allocation* ain = ains[index];
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700829
Chris Wailesf3712132014-07-16 15:18:30 -0700830 // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
Chris Wailes44bef6f2014-08-12 13:51:10 -0700831 if (ain != nullptr &&
832 (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == nullptr) {
833
Chris Wailesf3712132014-07-16 15:18:30 -0700834 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
835 "rsForEach called with null in allocations");
836 return;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700837 }
838 }
839
Chris Wailes44bef6f2014-08-12 13:51:10 -0700840 if (aout &&
841 (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == nullptr) {
842
Chris Wailesf3712132014-07-16 15:18:30 -0700843 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
844 "rsForEach called with null out allocations");
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700845 return;
846 }
847
Chris Wailesf3712132014-07-16 15:18:30 -0700848 if (inLen > 0) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700849 const Allocation *ain0 = ains[0];
850 const Type *inType = ain0->getType();
851
852 mtls->fep.dimX = inType->getDimX();
853 mtls->fep.dimY = inType->getDimY();
854 mtls->fep.dimZ = inType->getDimZ();
855
856 for (int Index = inLen; --Index >= 1;) {
857 if (!ain0->hasSameDims(ains[Index])) {
858 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
859 "Failed to launch kernel; dimensions of input and output allocations do not match.");
860
861 return;
862 }
863 }
864
Chris Wailes44bef6f2014-08-12 13:51:10 -0700865 } else if (aout != nullptr) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700866 const Type *outType = aout->getType();
867
868 mtls->fep.dimX = outType->getDimX();
869 mtls->fep.dimY = outType->getDimY();
870 mtls->fep.dimZ = outType->getDimZ();
871
872 } else {
Chris Wailesf3712132014-07-16 15:18:30 -0700873 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
874 "rsForEach called with null allocations");
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700875 return;
876 }
877
Chris Wailes44bef6f2014-08-12 13:51:10 -0700878 if (inLen > 0 && aout != nullptr) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700879 if (!ains[0]->hasSameDims(aout)) {
880 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
881 "Failed to launch kernel; dimensions of input and output allocations do not match.");
882
883 return;
884 }
885 }
886
887 if (!sc || (sc->xEnd == 0)) {
888 mtls->xEnd = mtls->fep.dimX;
889 } else {
890 rsAssert(sc->xStart < mtls->fep.dimX);
891 rsAssert(sc->xEnd <= mtls->fep.dimX);
892 rsAssert(sc->xStart < sc->xEnd);
893 mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
894 mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
895 if (mtls->xStart >= mtls->xEnd) return;
896 }
897
898 if (!sc || (sc->yEnd == 0)) {
899 mtls->yEnd = mtls->fep.dimY;
900 } else {
901 rsAssert(sc->yStart < mtls->fep.dimY);
902 rsAssert(sc->yEnd <= mtls->fep.dimY);
903 rsAssert(sc->yStart < sc->yEnd);
904 mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
905 mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
906 if (mtls->yStart >= mtls->yEnd) return;
907 }
908
909 if (!sc || (sc->zEnd == 0)) {
910 mtls->zEnd = mtls->fep.dimZ;
911 } else {
912 rsAssert(sc->zStart < mtls->fep.dimZ);
913 rsAssert(sc->zEnd <= mtls->fep.dimZ);
914 rsAssert(sc->zStart < sc->zEnd);
915 mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
916 mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
917 if (mtls->zStart >= mtls->zEnd) return;
918 }
919
920 mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
921 mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
922 mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
923 mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
924
Chris Wailesf3712132014-07-16 15:18:30 -0700925 rsAssert(inLen == 0 || (ains[0]->getType()->getDimZ() == 0));
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700926
927 mtls->rsc = mCtx;
928 mtls->ains = ains;
929 mtls->aout = aout;
930 mtls->fep.usr = usr;
931 mtls->fep.usrLen = usrLen;
932 mtls->mSliceSize = 1;
933 mtls->mSliceNum = 0;
934
Chris Wailes44bef6f2014-08-12 13:51:10 -0700935 mtls->fep.inPtrs = nullptr;
936 mtls->fep.inStrides = nullptr;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700937 mtls->isThreadable = mIsThreadable;
938
Chris Wailesf3712132014-07-16 15:18:30 -0700939 if (inLen > 0) {
940
941 if (inLen <= RS_KERNEL_INPUT_THRESHOLD) {
942 mtls->fep.inPtrs = (const uint8_t**)mtls->inPtrsBuff;
943 mtls->fep.inStrides = mtls->inStridesBuff;
944 } else {
945 mtls->fep.heapAllocatedArrays = true;
946
947 mtls->fep.inPtrs = new const uint8_t*[inLen];
948 mtls->fep.inStrides = new StridePair[inLen];
949 }
950
951 mtls->fep.inLen = inLen;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700952
953 for (int index = inLen; --index >= 0;) {
954 const Allocation *ain = ains[index];
955
Chris Wailesf3712132014-07-16 15:18:30 -0700956 mtls->fep.inPtrs[index] =
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700957 (const uint8_t*)ain->mHal.drvState.lod[0].mallocPtr;
958
959 mtls->fep.inStrides[index].eStride =
960 ain->getType()->getElementSizeBytes();
961 mtls->fep.inStrides[index].yStride =
962 ain->mHal.drvState.lod[0].stride;
963 }
964 }
965
Chris Wailes44bef6f2014-08-12 13:51:10 -0700966 mtls->fep.outPtr = nullptr;
Chris Wailesf3712132014-07-16 15:18:30 -0700967 mtls->fep.outStride.eStride = 0;
968 mtls->fep.outStride.yStride = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700969 if (aout != nullptr) {
Chris Wailesf3712132014-07-16 15:18:30 -0700970 mtls->fep.outPtr = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
971
972 mtls->fep.outStride.eStride = aout->getType()->getElementSizeBytes();
973 mtls->fep.outStride.yStride = aout->mHal.drvState.lod[0].stride;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700974 }
975}
976
Jason Sams709a0972012-11-15 18:18:04 -0800977
978void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
Chris Wailesf3712132014-07-16 15:18:30 -0700979 const Allocation ** ains,
980 uint32_t inLen,
Jason Sams709a0972012-11-15 18:18:04 -0800981 Allocation * aout,
982 const void * usr,
983 uint32_t usrLen,
984 const RsScriptCall *sc) {
985
986 MTLaunchStruct mtls;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700987
988 forEachMtlsSetup(ains, inLen, aout, usr, usrLen, sc, &mtls);
989 forEachKernelSetup(slot, &mtls);
990
991 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
992 mCtx->launchThreads(ains, inLen, aout, sc, &mtls);
993 mCtx->setTLS(oldTLS);
994}
995
Jason Sams709a0972012-11-15 18:18:04 -0800996void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
Jason Sams709a0972012-11-15 18:18:04 -0800997 mtls->script = this;
998 mtls->fep.slot = slot;
Jason Sams110f1812013-03-14 16:02:18 -0700999#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001000 rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
1001 mtls->kernel = reinterpret_cast<ForEachFunc_t>(
1002 mExecutable->getExportForeachFuncAddrs()[slot]);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001003 rsAssert(mtls->kernel != nullptr);
Jason Sams709a0972012-11-15 18:18:04 -08001004 mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
Jason Sams110f1812013-03-14 16:02:18 -07001005#else
1006 mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001007 rsAssert(mtls->kernel != nullptr);
Jason Sams110f1812013-03-14 16:02:18 -07001008 mtls->sig = mForEachSignatures[slot];
1009#endif
Jason Sams709a0972012-11-15 18:18:04 -08001010}
1011
1012int RsdCpuScriptImpl::invokeRoot() {
1013 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1014 int ret = mRoot();
1015 mCtx->setTLS(oldTLS);
1016 return ret;
1017}
1018
1019void RsdCpuScriptImpl::invokeInit() {
1020 if (mInit) {
1021 mInit();
1022 }
1023}
1024
1025void RsdCpuScriptImpl::invokeFreeChildren() {
1026 if (mFreeChildren) {
1027 mFreeChildren();
1028 }
1029}
1030
1031void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
1032 size_t paramLength) {
1033 //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
Yong Cheneaba5a32014-12-12 13:25:18 +08001034 void * ap = nullptr;
1035
1036#if defined(__x86_64__)
1037 // The invoked function could have input parameter of vector type for example float4 which
1038 // requires void* params to be 16 bytes aligned when using SSE instructions for x86_64 platform.
1039 // So try to align void* params before passing them into RS exported function.
1040
1041 if ((uint8_t)(uint64_t)params & 0x0F) {
1042 if ((ap = (void*)memalign(16, paramLength)) != nullptr) {
1043 memcpy(ap, params, paramLength);
1044 } else {
1045 ALOGE("x86_64: invokeFunction memalign error, still use params which is not 16 bytes aligned.");
1046 }
1047 }
1048#endif
Jason Sams709a0972012-11-15 18:18:04 -08001049
1050 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1051 reinterpret_cast<void (*)(const void *, uint32_t)>(
Jason Sams110f1812013-03-14 16:02:18 -07001052#ifndef RS_COMPATIBILITY_LIB
Yong Cheneaba5a32014-12-12 13:25:18 +08001053 mExecutable->getExportFuncAddrs()[slot])(ap ? (const void *)ap : params, paramLength);
Jason Sams110f1812013-03-14 16:02:18 -07001054#else
Yong Cheneaba5a32014-12-12 13:25:18 +08001055 mInvokeFunctions[slot])(ap ? (const void *)ap : params, paramLength);
Jason Sams110f1812013-03-14 16:02:18 -07001056#endif
Yong Cheneaba5a32014-12-12 13:25:18 +08001057
1058#if defined(__x86_64__)
1059 if (ap) free(ap);
1060#endif
1061
Jason Sams709a0972012-11-15 18:18:04 -08001062 mCtx->setTLS(oldTLS);
1063}
1064
1065void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
1066 //rsAssert(!script->mFieldIsObject[slot]);
1067 //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
1068
1069 //if (mIntrinsicID) {
1070 //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
1071 //return;
1072 //}
1073
Jason Sams110f1812013-03-14 16:02:18 -07001074#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001075 int32_t *destPtr = reinterpret_cast<int32_t *>(
1076 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001077#else
1078 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1079#endif
Jason Sams709a0972012-11-15 18:18:04 -08001080 if (!destPtr) {
1081 //ALOGV("Calling setVar on slot = %i which is null", slot);
1082 return;
1083 }
1084
1085 memcpy(destPtr, data, dataLength);
1086}
1087
Tim Murray9c642392013-04-11 13:29:59 -07001088void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
1089 //rsAssert(!script->mFieldIsObject[slot]);
1090 //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
1091
1092#ifndef RS_COMPATIBILITY_LIB
1093 int32_t *srcPtr = reinterpret_cast<int32_t *>(
1094 mExecutable->getExportVarAddrs()[slot]);
1095#else
1096 int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1097#endif
1098 if (!srcPtr) {
1099 //ALOGV("Calling setVar on slot = %i which is null", slot);
1100 return;
1101 }
1102 memcpy(data, srcPtr, dataLength);
1103}
1104
1105
Jason Sams709a0972012-11-15 18:18:04 -08001106void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
1107 const Element *elem,
Stephen Hinesac8d1462014-06-25 00:01:23 -07001108 const uint32_t *dims, size_t dimLength) {
Jason Sams709a0972012-11-15 18:18:04 -08001109
Jason Sams110f1812013-03-14 16:02:18 -07001110#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001111 int32_t *destPtr = reinterpret_cast<int32_t *>(
1112 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001113#else
1114 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1115#endif
Jason Sams709a0972012-11-15 18:18:04 -08001116 if (!destPtr) {
1117 //ALOGV("Calling setVar on slot = %i which is null", slot);
1118 return;
1119 }
1120
1121 // We want to look at dimension in terms of integer components,
1122 // but dimLength is given in terms of bytes.
1123 dimLength /= sizeof(int);
1124
1125 // Only a single dimension is currently supported.
1126 rsAssert(dimLength == 1);
1127 if (dimLength == 1) {
1128 // First do the increment loop.
1129 size_t stride = elem->getSizeBytes();
1130 const char *cVal = reinterpret_cast<const char *>(data);
Stephen Hinesac8d1462014-06-25 00:01:23 -07001131 for (uint32_t i = 0; i < dims[0]; i++) {
Jason Sams709a0972012-11-15 18:18:04 -08001132 elem->incRefs(cVal);
1133 cVal += stride;
1134 }
1135
1136 // Decrement loop comes after (to prevent race conditions).
1137 char *oldVal = reinterpret_cast<char *>(destPtr);
Stephen Hinesac8d1462014-06-25 00:01:23 -07001138 for (uint32_t i = 0; i < dims[0]; i++) {
Jason Sams709a0972012-11-15 18:18:04 -08001139 elem->decRefs(oldVal);
1140 oldVal += stride;
1141 }
1142 }
1143
1144 memcpy(destPtr, data, dataLength);
1145}
1146
1147void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
1148
1149 //rsAssert(!script->mFieldIsObject[slot]);
1150 //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
1151
Jason Sams110f1812013-03-14 16:02:18 -07001152#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001153 int32_t *destPtr = reinterpret_cast<int32_t *>(
1154 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001155#else
1156 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1157#endif
Jason Sams709a0972012-11-15 18:18:04 -08001158 if (!destPtr) {
1159 //ALOGV("Calling setVar on slot = %i which is null", slot);
1160 return;
1161 }
1162
Chris Wailes44bef6f2014-08-12 13:51:10 -07001163 void *ptr = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001164 mBoundAllocs[slot] = data;
1165 if(data) {
1166 ptr = data->mHal.drvState.lod[0].mallocPtr;
1167 }
1168 memcpy(destPtr, &ptr, sizeof(void *));
1169}
1170
1171void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
1172
1173 //rsAssert(script->mFieldIsObject[slot]);
1174 //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
1175
Jason Sams110f1812013-03-14 16:02:18 -07001176#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001177 int32_t *destPtr = reinterpret_cast<int32_t *>(
1178 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001179#else
1180 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1181#endif
Tim Murraye195a3f2014-03-13 15:04:58 -07001182
Jason Sams709a0972012-11-15 18:18:04 -08001183 if (!destPtr) {
1184 //ALOGV("Calling setVar on slot = %i which is null", slot);
1185 return;
1186 }
1187
Jason Sams05ef73f2014-08-05 14:59:22 -07001188 rsrSetObject(mCtx->getContext(), (rs_object_base *)destPtr, data);
Jason Sams709a0972012-11-15 18:18:04 -08001189}
1190
1191RsdCpuScriptImpl::~RsdCpuScriptImpl() {
Jason Sams110f1812013-03-14 16:02:18 -07001192#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001193 if (mExecutable) {
Chris Wailes70d49712014-08-08 14:42:33 -07001194 std::vector<void *>::const_iterator var_addr_iter =
Jason Sams709a0972012-11-15 18:18:04 -08001195 mExecutable->getExportVarAddrs().begin();
Chris Wailes70d49712014-08-08 14:42:33 -07001196 std::vector<void *>::const_iterator var_addr_end =
Jason Sams709a0972012-11-15 18:18:04 -08001197 mExecutable->getExportVarAddrs().end();
1198
1199 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter =
1200 mExecutable->getInfo().getObjectSlots().begin();
1201 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end =
1202 mExecutable->getInfo().getObjectSlots().end();
1203
1204 while ((var_addr_iter != var_addr_end) &&
1205 (is_object_iter != is_object_end)) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001206 // The field address can be nullptr if the script-side has optimized
Jason Sams709a0972012-11-15 18:18:04 -08001207 // the corresponding global variable away.
Jason Sams05ef73f2014-08-05 14:59:22 -07001208 rs_object_base *obj_addr =
1209 reinterpret_cast<rs_object_base *>(*var_addr_iter);
Jason Sams709a0972012-11-15 18:18:04 -08001210 if (*is_object_iter) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001211 if (*var_addr_iter != nullptr && mCtx->getContext() != nullptr) {
Jason Sams709a0972012-11-15 18:18:04 -08001212 rsrClearObject(mCtx->getContext(), obj_addr);
1213 }
1214 }
1215 var_addr_iter++;
1216 is_object_iter++;
1217 }
1218 }
1219
Jason Sams709a0972012-11-15 18:18:04 -08001220 if (mCompilerDriver) {
1221 delete mCompilerDriver;
1222 }
1223 if (mExecutable) {
1224 delete mExecutable;
1225 }
1226 if (mBoundAllocs) {
1227 delete[] mBoundAllocs;
1228 }
Tim Murraybee48d72014-06-13 12:44:47 -07001229
Tim Murray29809d12014-05-28 12:04:19 -07001230 for (size_t i = 0; i < mExportedForEachFuncList.size(); i++) {
1231 delete[] mExportedForEachFuncList[i].first;
1232 }
Jason Sams110f1812013-03-14 16:02:18 -07001233#else
1234 if (mFieldIsObject) {
1235 for (size_t i = 0; i < mExportedVariableCount; ++i) {
1236 if (mFieldIsObject[i]) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001237 if (mFieldAddress[i] != nullptr) {
Jason Sams05ef73f2014-08-05 14:59:22 -07001238 rs_object_base *obj_addr =
1239 reinterpret_cast<rs_object_base *>(mFieldAddress[i]);
Jason Sams110f1812013-03-14 16:02:18 -07001240 rsrClearObject(mCtx->getContext(), obj_addr);
1241 }
1242 }
1243 }
1244 }
1245
1246 if (mInvokeFunctions) delete[] mInvokeFunctions;
1247 if (mForEachFunctions) delete[] mForEachFunctions;
1248 if (mFieldAddress) delete[] mFieldAddress;
1249 if (mFieldIsObject) delete[] mFieldIsObject;
1250 if (mForEachSignatures) delete[] mForEachSignatures;
1251 if (mBoundAllocs) delete[] mBoundAllocs;
1252 if (mScriptSO) {
1253 dlclose(mScriptSO);
1254 }
1255#endif
Jason Sams709a0972012-11-15 18:18:04 -08001256}
1257
1258Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const {
1259 if (!ptr) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001260 return nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001261 }
1262
1263 for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) {
1264 Allocation *a = mBoundAllocs[ct];
1265 if (!a) continue;
1266 if (a->mHal.drvState.lod[0].mallocPtr == ptr) {
1267 return a;
1268 }
1269 }
1270 ALOGE("rsGetAllocation, failed to find %p", ptr);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001271 return nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001272}
1273
Chris Wailesf3712132014-07-16 15:18:30 -07001274void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation ** ains,
1275 uint32_t inLen, Allocation * aout,
1276 const void * usr, uint32_t usrLen,
1277 const RsScriptCall *sc) {}
Jason Sams17e3cdc2013-09-09 17:32:16 -07001278
Chris Wailesf3712132014-07-16 15:18:30 -07001279void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation ** ains,
1280 uint32_t inLen, Allocation * aout,
1281 const void * usr, uint32_t usrLen,
1282 const RsScriptCall *sc) {}
Jason Sams17e3cdc2013-09-09 17:32:16 -07001283
Jason Sams709a0972012-11-15 18:18:04 -08001284
1285}
1286}