blob: 6c534cf90e02e9924ab409ae3301ff8e238575f9 [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);
252 args->push_back("-o");
253 args->push_back(resName);
254 args->push_back("-output_path");
255 args->push_back(cacheDir);
256 args->push_back("-bclib");
257 args->push_back(core_lib);
258 args->push_back("-mtriple");
259 args->push_back(DEFAULT_TARGET_TRIPLE_STRING);
260
Tim Murray358ffb82014-12-09 11:53:06 -0800261 // Enable workaround for A53 codegen by default.
262#if defined(__aarch64__) && !defined(DISABLE_A53_WORKAROUND)
263 args->push_back("-aarch64-fix-cortex-a53-835769");
264#endif
265
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700266 // Execute the bcc compiler.
267 if (useRSDebugContext) {
268 args->push_back("-rs-debug-ctx");
269 } else {
270 // Only load additional libraries for compiles that don't use
271 // the debug context.
272 if (bccPluginName && strlen(bccPluginName) > 0) {
273 args->push_back("-load");
274 args->push_back(bccPluginName);
275 }
276 }
277
Chris Wailes6847e732014-08-11 17:30:51 -0700278 args->push_back(bcFileName.c_str());
Chris Wailes44bef6f2014-08-12 13:51:10 -0700279 args->push_back(nullptr);
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700280}
281
Chris Wailes6847e732014-08-11 17:30:51 -0700282static bool compileBitcode(const std::string &bcFileName,
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700283 const char *bitcode,
284 size_t bitcodeSize,
Chris Wailes6847e732014-08-11 17:30:51 -0700285 const char **compileArguments,
286 const std::string &compileCommandLine) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700287 rsAssert(bitcode && bitcodeSize);
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700288
Chris Wailes6847e732014-08-11 17:30:51 -0700289 FILE *bcfile = fopen(bcFileName.c_str(), "w");
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700290 if (!bcfile) {
Chris Wailes6847e732014-08-11 17:30:51 -0700291 ALOGE("Could not write to %s", bcFileName.c_str());
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700292 return false;
293 }
294 size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile);
295 fclose(bcfile);
296 if (nwritten != bitcodeSize) {
297 ALOGE("Could not write %zu bytes to %s", bitcodeSize,
Chris Wailes6847e732014-08-11 17:30:51 -0700298 bcFileName.c_str());
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700299 return false;
300 }
301
302 pid_t pid = fork();
Stephen Hines00511322014-01-31 11:20:23 -0800303
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700304 switch (pid) {
305 case -1: { // Error occurred (we attempt no recovery)
306 ALOGE("Couldn't fork for bcc compiler execution");
307 return false;
308 }
309 case 0: { // Child process
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700310 ALOGV("Invoking BCC with: %s", compileCommandLine.c_str());
311 execv(BCC_EXE_PATH, (char* const*)compileArguments);
Stephen Hines00511322014-01-31 11:20:23 -0800312
Stephen Hines00511322014-01-31 11:20:23 -0800313 ALOGE("execv() failed: %s", strerror(errno));
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700314 abort();
315 return false;
316 }
317 default: { // Parent process (actual driver)
318 // Wait on child process to finish compiling the source.
319 int status = 0;
320 pid_t w = waitpid(pid, &status, 0);
321 if (w == -1) {
322 ALOGE("Could not wait for bcc compiler");
323 return false;
324 }
325
326 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
327 return true;
328 }
329
330 ALOGE("bcc compiler terminated unexpectedly");
331 return false;
332 }
333 }
334}
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700335
Stephen Hinesba17ae42013-06-05 17:18:04 -0700336#endif // !defined(RS_COMPATIBILITY_LIB)
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700337} // namespace
Stephen Hinesba17ae42013-06-05 17:18:04 -0700338
Jason Sams709a0972012-11-15 18:18:04 -0800339namespace android {
340namespace renderscript {
341
Jason Sams110f1812013-03-14 16:02:18 -0700342#ifdef RS_COMPATIBILITY_LIB
343#define MAXLINE 500
344#define MAKE_STR_HELPER(S) #S
345#define MAKE_STR(S) MAKE_STR_HELPER(S)
346#define EXPORT_VAR_STR "exportVarCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700347#define EXPORT_FUNC_STR "exportFuncCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700348#define EXPORT_FOREACH_STR "exportForEachCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700349#define OBJECT_SLOT_STR "objectSlotCount: "
Jason Sams110f1812013-03-14 16:02:18 -0700350
351// Copy up to a newline or size chars from str -> s, updating str
Chris Wailes44bef6f2014-08-12 13:51:10 -0700352// Returns s when successful and nullptr when '\0' is finally reached.
Jason Sams110f1812013-03-14 16:02:18 -0700353static char* strgets(char *s, int size, const char **ppstr) {
354 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700355 return nullptr;
Jason Sams110f1812013-03-14 16:02:18 -0700356 }
357
358 int i;
359 for (i = 0; i < (size - 1); i++) {
360 s[i] = **ppstr;
361 (*ppstr)++;
362 if (s[i] == '\0') {
363 return s;
364 } else if (s[i] == '\n') {
365 s[i+1] = '\0';
366 return s;
367 }
368 }
369
370 // size has been exceeded.
371 s[i] = '\0';
372
373 return s;
374}
375#endif
Jason Sams709a0972012-11-15 18:18:04 -0800376
377RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
378 mCtx = ctx;
379 mScript = s;
380
Jason Sams110f1812013-03-14 16:02:18 -0700381#ifdef RS_COMPATIBILITY_LIB
Chris Wailes44bef6f2014-08-12 13:51:10 -0700382 mScriptSO = nullptr;
383 mInvokeFunctions = nullptr;
384 mForEachFunctions = nullptr;
385 mFieldAddress = nullptr;
386 mFieldIsObject = nullptr;
387 mForEachSignatures = nullptr;
Jason Sams110f1812013-03-14 16:02:18 -0700388#else
Chris Wailes44bef6f2014-08-12 13:51:10 -0700389 mCompilerDriver = nullptr;
390 mExecutable = nullptr;
Jason Sams110f1812013-03-14 16:02:18 -0700391#endif
392
Tim Murraye195a3f2014-03-13 15:04:58 -0700393
Chris Wailes44bef6f2014-08-12 13:51:10 -0700394 mRoot = nullptr;
395 mRootExpand = nullptr;
396 mInit = nullptr;
397 mFreeChildren = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800398
Jason Sams709a0972012-11-15 18:18:04 -0800399
Chris Wailes44bef6f2014-08-12 13:51:10 -0700400 mBoundAllocs = nullptr;
401 mIntrinsicData = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800402 mIsThreadable = true;
403}
404
405
406bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
407 uint8_t const *bitcode, size_t bitcodeSize,
Stephen Hines00511322014-01-31 11:20:23 -0800408 uint32_t flags, char const *bccPluginName) {
Jason Sams709a0972012-11-15 18:18:04 -0800409 //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
410 //ALOGE("rsdScriptInit %p %p", rsc, script);
411
412 mCtx->lockMutex();
Jason Sams110f1812013-03-14 16:02:18 -0700413#ifndef RS_COMPATIBILITY_LIB
Stephen Hines00511322014-01-31 11:20:23 -0800414 bool useRSDebugContext = false;
Jason Sams709a0972012-11-15 18:18:04 -0800415
Chris Wailes44bef6f2014-08-12 13:51:10 -0700416 mCompilerDriver = nullptr;
417 mExecutable = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800418
Jason Sams709a0972012-11-15 18:18:04 -0800419 mCompilerDriver = new bcc::RSCompilerDriver();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700420 if (mCompilerDriver == nullptr) {
Jason Sams709a0972012-11-15 18:18:04 -0800421 ALOGE("bcc: FAILS to create compiler driver (out of memory)");
422 mCtx->unlockMutex();
423 return false;
424 }
425
Stephen Hines25e3af52014-05-21 21:23:08 -0700426 // Configure symbol resolvers (via compiler-rt and the RS runtime).
427 mRSRuntime.setLookupFunction(lookupRuntimeStub);
428 mRSRuntime.setContext(this);
429 mResolver.chainResolver(mCompilerRuntime);
430 mResolver.chainResolver(mRSRuntime);
Jason Sams709a0972012-11-15 18:18:04 -0800431
Stephen Hinesb7d9c802013-04-29 19:13:09 -0700432 // Run any compiler setup functions we have been provided with.
433 RSSetupCompilerCallback setupCompilerCallback =
434 mCtx->getSetupCompilerCallback();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700435 if (setupCompilerCallback != nullptr) {
Stephen Hinesb7d9c802013-04-29 19:13:09 -0700436 setupCompilerCallback(mCompilerDriver);
437 }
438
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700439 bcinfo::MetadataExtractor bitcodeMetadata((const char *) bitcode, bitcodeSize);
440 if (!bitcodeMetadata.extract()) {
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700441 ALOGE("Could not extract metadata from bitcode");
Stephen Hinesf94e8db2014-06-26 11:55:29 -0700442 mCtx->unlockMutex();
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700443 return false;
444 }
445
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700446 const char* core_lib = findCoreLib(bitcodeMetadata, (const char*)bitcode, bitcodeSize);
Stephen Hinescca3d6c2013-04-15 01:06:39 -0700447
448 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
Stephen Hinesf47e8b42013-04-18 01:06:29 -0700449 mCompilerDriver->setDebugContext(true);
Stephen Hines00511322014-01-31 11:20:23 -0800450 useRSDebugContext = true;
Stephen Hinescca3d6c2013-04-15 01:06:39 -0700451 }
Stephen Hinesba17ae42013-06-05 17:18:04 -0700452
Chris Wailes6847e732014-08-11 17:30:51 -0700453 std::string bcFileName(cacheDir);
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700454 bcFileName.append("/");
455 bcFileName.append(resName);
456 bcFileName.append(".bc");
457
458 std::vector<const char*> compileArguments;
459 setCompileArguments(&compileArguments, bcFileName, cacheDir, resName, core_lib,
460 useRSDebugContext, bccPluginName);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700461 // The last argument of compileArguments ia a nullptr, so remove 1 from the size.
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700462 std::string compileCommandLine =
463 bcc::getCommandLine(compileArguments.size() - 1, compileArguments.data());
464
465 if (!is_force_recompile()) {
466 // Load the compiled script that's in the cache, if any.
467 mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
468 bitcodeSize, compileCommandLine.c_str(),
469 mResolver);
470 }
471
472 // If we can't, it's either not there or out of date. We compile the bit code and try loading
473 // again.
Chris Wailes44bef6f2014-08-12 13:51:10 -0700474 if (mExecutable == nullptr) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700475 if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize, compileArguments.data(),
476 compileCommandLine)) {
477 ALOGE("bcc: FAILS to compile '%s'", resName);
478 mCtx->unlockMutex();
479 return false;
480 }
481 mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
482 bitcodeSize, compileCommandLine.c_str(),
483 mResolver);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700484 if (mExecutable == nullptr) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700485 ALOGE("bcc: FAILS to load freshly compiled executable for '%s'", resName);
486 mCtx->unlockMutex();
487 return false;
Stephen Hinesba17ae42013-06-05 17:18:04 -0700488 }
489 }
Jason Sams709a0972012-11-15 18:18:04 -0800490
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700491 mExecutable->setThreadable(mIsThreadable);
492 if (!mExecutable->syncInfo()) {
Jason Sams709a0972012-11-15 18:18:04 -0800493 ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
494 }
495
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700496 mRoot = reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root"));
Jason Sams709a0972012-11-15 18:18:04 -0800497 mRootExpand =
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700498 reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root.expand"));
499 mInit = reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress("init"));
Jason Sams709a0972012-11-15 18:18:04 -0800500 mFreeChildren =
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700501 reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress(".rs.dtor"));
Jason Sams709a0972012-11-15 18:18:04 -0800502
503
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700504 if (bitcodeMetadata.getExportVarCount()) {
505 mBoundAllocs = new Allocation *[bitcodeMetadata.getExportVarCount()];
506 memset(mBoundAllocs, 0, sizeof(void *) * bitcodeMetadata.getExportVarCount());
Tim Murray29809d12014-05-28 12:04:19 -0700507 }
508
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700509 for (size_t i = 0; i < bitcodeMetadata.getExportForEachSignatureCount(); i++) {
510 char* name = new char[strlen(bitcodeMetadata.getExportForEachNameList()[i]) + 1];
511 mExportedForEachFuncList.push_back(
512 std::make_pair(name, bitcodeMetadata.getExportForEachSignatureList()[i]));
Jason Sams709a0972012-11-15 18:18:04 -0800513 }
514
Jean-Luc Brouilletf4d216e2014-06-09 18:04:16 -0700515#else // RS_COMPATIBILITY_LIB is defined
Jason Sams110f1812013-03-14 16:02:18 -0700516
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700517 mScriptSO = loadSharedLibrary(cacheDir, resName);
Jason Sams110f1812013-03-14 16:02:18 -0700518
519 if (mScriptSO) {
520 char line[MAXLINE];
521 mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
522 if (mRoot) {
523 //ALOGE("Found root(): %p", mRoot);
524 }
525 mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
526 if (mRootExpand) {
527 //ALOGE("Found root.expand(): %p", mRootExpand);
528 }
529 mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
530 if (mInit) {
531 //ALOGE("Found init(): %p", mInit);
532 }
533 mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
534 if (mFreeChildren) {
535 //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
536 }
537
538 const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
539 if (rsInfo) {
540 //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
541 }
542
543 size_t varCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700544 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700545 goto error;
546 }
547 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
548 ALOGE("Invalid export var count!: %s", line);
549 goto error;
550 }
551
552 mExportedVariableCount = varCount;
553 //ALOGE("varCount: %zu", varCount);
554 if (varCount > 0) {
555 // Start by creating/zeroing this member, since we don't want to
556 // accidentally clean up invalid pointers later (if we error out).
557 mFieldIsObject = new bool[varCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700558 if (mFieldIsObject == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700559 goto error;
560 }
561 memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
562 mFieldAddress = new void*[varCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700563 if (mFieldAddress == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700564 goto error;
565 }
566 for (size_t i = 0; i < varCount; ++i) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700567 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700568 goto error;
569 }
570 char *c = strrchr(line, '\n');
571 if (c) {
572 *c = '\0';
573 }
574 mFieldAddress[i] = dlsym(mScriptSO, line);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700575 if (mFieldAddress[i] == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700576 ALOGE("Failed to find variable address for %s: %s",
577 line, dlerror());
578 // Not a critical error if we don't find a global variable.
579 }
580 else {
581 //ALOGE("Found variable %s at %p", line,
582 //mFieldAddress[i]);
583 }
584 }
585 }
586
587 size_t funcCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700588 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700589 goto error;
590 }
591 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
592 ALOGE("Invalid export func count!: %s", line);
593 goto error;
594 }
595
596 mExportedFunctionCount = funcCount;
597 //ALOGE("funcCount: %zu", funcCount);
598
599 if (funcCount > 0) {
600 mInvokeFunctions = new InvokeFunc_t[funcCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700601 if (mInvokeFunctions == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700602 goto error;
603 }
604 for (size_t i = 0; i < funcCount; ++i) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700605 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700606 goto error;
607 }
608 char *c = strrchr(line, '\n');
609 if (c) {
610 *c = '\0';
611 }
612
613 mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700614 if (mInvokeFunctions[i] == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700615 ALOGE("Failed to get function address for %s(): %s",
616 line, dlerror());
617 goto error;
618 }
619 else {
620 //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
621 }
622 }
623 }
624
625 size_t forEachCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700626 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700627 goto error;
628 }
629 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
630 ALOGE("Invalid export forEach count!: %s", line);
631 goto error;
632 }
633
634 if (forEachCount > 0) {
635
636 mForEachSignatures = new uint32_t[forEachCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700637 if (mForEachSignatures == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700638 goto error;
639 }
640 mForEachFunctions = new ForEachFunc_t[forEachCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700641 if (mForEachFunctions == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700642 goto error;
643 }
644 for (size_t i = 0; i < forEachCount; ++i) {
645 unsigned int tmpSig = 0;
646 char tmpName[MAXLINE];
647
Chris Wailes44bef6f2014-08-12 13:51:10 -0700648 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700649 goto error;
650 }
651 if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
652 &tmpSig, tmpName) != 2) {
653 ALOGE("Invalid export forEach!: %s", line);
654 goto error;
655 }
656
657 // Lookup the expanded ForEach kernel.
658 strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
659 mForEachSignatures[i] = tmpSig;
660 mForEachFunctions[i] =
661 (ForEachFunc_t) dlsym(mScriptSO, tmpName);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700662 if (i != 0 && mForEachFunctions[i] == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700663 // Ignore missing root.expand functions.
664 // root() is always specified at location 0.
Stephen Hinesef7481e2013-04-09 19:05:27 -0700665 ALOGE("Failed to find forEach function address for %s: %s",
666 tmpName, dlerror());
667 goto error;
Jason Sams110f1812013-03-14 16:02:18 -0700668 }
669 else {
670 //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
671 }
672 }
673 }
674
675 size_t objectSlotCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700676 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700677 goto error;
678 }
679 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
680 ALOGE("Invalid object slot count!: %s", line);
681 goto error;
682 }
683
684 if (objectSlotCount > 0) {
685 rsAssert(varCount > 0);
686 for (size_t i = 0; i < objectSlotCount; ++i) {
687 uint32_t varNum = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700688 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700689 goto error;
690 }
691 if (sscanf(line, "%u", &varNum) != 1) {
692 ALOGE("Invalid object slot!: %s", line);
693 goto error;
694 }
695
696 if (varNum < varCount) {
697 mFieldIsObject[varNum] = true;
698 }
699 }
700 }
701
702 if (varCount > 0) {
703 mBoundAllocs = new Allocation *[varCount];
704 memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
705 }
706
707 if (mScriptSO == (void*)1) {
708 //rsdLookupRuntimeStub(script, "acos");
709 }
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700710 } else {
711 goto error;
Jason Sams110f1812013-03-14 16:02:18 -0700712 }
713#endif
Jason Sams709a0972012-11-15 18:18:04 -0800714 mCtx->unlockMutex();
715 return true;
Jason Sams110f1812013-03-14 16:02:18 -0700716
717#ifdef RS_COMPATIBILITY_LIB
718error:
719
720 mCtx->unlockMutex();
721 delete[] mInvokeFunctions;
722 delete[] mForEachFunctions;
723 delete[] mFieldAddress;
724 delete[] mFieldIsObject;
725 delete[] mForEachSignatures;
726 delete[] mBoundAllocs;
727 if (mScriptSO) {
728 dlclose(mScriptSO);
729 }
730 return false;
731#endif
Jason Sams709a0972012-11-15 18:18:04 -0800732}
733
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700734#ifndef RS_COMPATIBILITY_LIB
735
736#ifdef __LP64__
737#define SYSLIBPATH "/system/lib64"
738#else
739#define SYSLIBPATH "/system/lib"
740#endif
741
742const char* RsdCpuScriptImpl::findCoreLib(const bcinfo::MetadataExtractor& ME, const char* bitcode,
743 size_t bitcodeSize) {
744 const char* defaultLib = SYSLIBPATH"/libclcore.bc";
745
746 // If we're debugging, use the debug library.
747 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
748 return SYSLIBPATH"/libclcore_debug.bc";
749 }
750
751 // If a callback has been registered to specify a library, use that.
752 RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700753 if (selectRTCallback != nullptr) {
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700754 return selectRTCallback((const char*)bitcode, bitcodeSize);
755 }
756
757 // Check for a platform specific library
758#if defined(ARCH_ARM_HAVE_NEON) && !defined(DISABLE_CLCORE_NEON)
759 enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision();
Jean-Luc Brouilletf4d38362014-07-09 17:46:03 -0700760 if (prec == bcinfo::RS_FP_Relaxed) {
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700761 // NEON-capable ARMv7a devices can use an accelerated math library
762 // for all reduced precision scripts.
763 // ARMv8 does not use NEON, as ASIMD can be used with all precision
764 // levels.
765 return SYSLIBPATH"/libclcore_neon.bc";
766 } else {
767 return defaultLib;
768 }
769#elif defined(__i386__) || defined(__x86_64__)
770 // x86 devices will use an optimized library.
771 return SYSLIBPATH"/libclcore_x86.bc";
772#else
773 return defaultLib;
774#endif
775}
776
777#endif
778
Jason Sams709a0972012-11-15 18:18:04 -0800779void RsdCpuScriptImpl::populateScript(Script *script) {
Jason Sams110f1812013-03-14 16:02:18 -0700780#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -0800781 // Copy info over to runtime
Tim Murray29809d12014-05-28 12:04:19 -0700782 script->mHal.info.exportedFunctionCount = mExecutable->getExportFuncAddrs().size();
783 script->mHal.info.exportedVariableCount = mExecutable->getExportVarAddrs().size();
784 script->mHal.info.exportedForeachFuncList = &mExportedForEachFuncList[0];
785 script->mHal.info.exportedPragmaCount = mExecutable->getPragmaKeys().size();
Jason Sams709a0972012-11-15 18:18:04 -0800786 script->mHal.info.exportedPragmaKeyList =
Chris Wailes70d49712014-08-08 14:42:33 -0700787 const_cast<const char**>(&mExecutable->getPragmaKeys().front());
Jason Sams709a0972012-11-15 18:18:04 -0800788 script->mHal.info.exportedPragmaValueList =
Chris Wailes70d49712014-08-08 14:42:33 -0700789 const_cast<const char**>(&mExecutable->getPragmaValues().front());
Jason Sams709a0972012-11-15 18:18:04 -0800790
791 if (mRootExpand) {
792 script->mHal.info.root = mRootExpand;
793 } else {
794 script->mHal.info.root = mRoot;
795 }
Jason Sams110f1812013-03-14 16:02:18 -0700796#else
797 // Copy info over to runtime
798 script->mHal.info.exportedFunctionCount = mExportedFunctionCount;
799 script->mHal.info.exportedVariableCount = mExportedVariableCount;
800 script->mHal.info.exportedPragmaCount = 0;
801 script->mHal.info.exportedPragmaKeyList = 0;
802 script->mHal.info.exportedPragmaValueList = 0;
803
804 // Bug, need to stash in metadata
805 if (mRootExpand) {
806 script->mHal.info.root = mRootExpand;
807 } else {
808 script->mHal.info.root = mRoot;
809 }
810#endif
Jason Sams709a0972012-11-15 18:18:04 -0800811}
812
Jason Sams709a0972012-11-15 18:18:04 -0800813
814typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
815
Chris Wailesf3712132014-07-16 15:18:30 -0700816void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation ** ains,
817 uint32_t inLen,
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700818 Allocation * aout,
819 const void * usr, uint32_t usrLen,
820 const RsScriptCall *sc,
821 MTLaunchStruct *mtls) {
822
823 memset(mtls, 0, sizeof(MTLaunchStruct));
824
Chris Wailesf3712132014-07-16 15:18:30 -0700825 for (int index = inLen; --index >= 0;) {
826 const Allocation* ain = ains[index];
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700827
Chris Wailesf3712132014-07-16 15:18:30 -0700828 // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
Chris Wailes44bef6f2014-08-12 13:51:10 -0700829 if (ain != nullptr &&
830 (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == nullptr) {
831
Chris Wailesf3712132014-07-16 15:18:30 -0700832 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
833 "rsForEach called with null in allocations");
834 return;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700835 }
836 }
837
Chris Wailes44bef6f2014-08-12 13:51:10 -0700838 if (aout &&
839 (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == nullptr) {
840
Chris Wailesf3712132014-07-16 15:18:30 -0700841 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
842 "rsForEach called with null out allocations");
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700843 return;
844 }
845
Chris Wailesf3712132014-07-16 15:18:30 -0700846 if (inLen > 0) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700847 const Allocation *ain0 = ains[0];
848 const Type *inType = ain0->getType();
849
850 mtls->fep.dimX = inType->getDimX();
851 mtls->fep.dimY = inType->getDimY();
852 mtls->fep.dimZ = inType->getDimZ();
853
854 for (int Index = inLen; --Index >= 1;) {
855 if (!ain0->hasSameDims(ains[Index])) {
856 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
857 "Failed to launch kernel; dimensions of input and output allocations do not match.");
858
859 return;
860 }
861 }
862
Chris Wailes44bef6f2014-08-12 13:51:10 -0700863 } else if (aout != nullptr) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700864 const Type *outType = aout->getType();
865
866 mtls->fep.dimX = outType->getDimX();
867 mtls->fep.dimY = outType->getDimY();
868 mtls->fep.dimZ = outType->getDimZ();
869
870 } else {
Chris Wailesf3712132014-07-16 15:18:30 -0700871 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
872 "rsForEach called with null allocations");
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700873 return;
874 }
875
Chris Wailes44bef6f2014-08-12 13:51:10 -0700876 if (inLen > 0 && aout != nullptr) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700877 if (!ains[0]->hasSameDims(aout)) {
878 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
879 "Failed to launch kernel; dimensions of input and output allocations do not match.");
880
881 return;
882 }
883 }
884
885 if (!sc || (sc->xEnd == 0)) {
886 mtls->xEnd = mtls->fep.dimX;
887 } else {
888 rsAssert(sc->xStart < mtls->fep.dimX);
889 rsAssert(sc->xEnd <= mtls->fep.dimX);
890 rsAssert(sc->xStart < sc->xEnd);
891 mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
892 mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
893 if (mtls->xStart >= mtls->xEnd) return;
894 }
895
896 if (!sc || (sc->yEnd == 0)) {
897 mtls->yEnd = mtls->fep.dimY;
898 } else {
899 rsAssert(sc->yStart < mtls->fep.dimY);
900 rsAssert(sc->yEnd <= mtls->fep.dimY);
901 rsAssert(sc->yStart < sc->yEnd);
902 mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
903 mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
904 if (mtls->yStart >= mtls->yEnd) return;
905 }
906
907 if (!sc || (sc->zEnd == 0)) {
908 mtls->zEnd = mtls->fep.dimZ;
909 } else {
910 rsAssert(sc->zStart < mtls->fep.dimZ);
911 rsAssert(sc->zEnd <= mtls->fep.dimZ);
912 rsAssert(sc->zStart < sc->zEnd);
913 mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
914 mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
915 if (mtls->zStart >= mtls->zEnd) return;
916 }
917
918 mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
919 mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
920 mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
921 mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
922
Chris Wailesf3712132014-07-16 15:18:30 -0700923 rsAssert(inLen == 0 || (ains[0]->getType()->getDimZ() == 0));
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700924
925 mtls->rsc = mCtx;
926 mtls->ains = ains;
927 mtls->aout = aout;
928 mtls->fep.usr = usr;
929 mtls->fep.usrLen = usrLen;
930 mtls->mSliceSize = 1;
931 mtls->mSliceNum = 0;
932
Chris Wailes44bef6f2014-08-12 13:51:10 -0700933 mtls->fep.inPtrs = nullptr;
934 mtls->fep.inStrides = nullptr;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700935 mtls->isThreadable = mIsThreadable;
936
Chris Wailesf3712132014-07-16 15:18:30 -0700937 if (inLen > 0) {
938
939 if (inLen <= RS_KERNEL_INPUT_THRESHOLD) {
940 mtls->fep.inPtrs = (const uint8_t**)mtls->inPtrsBuff;
941 mtls->fep.inStrides = mtls->inStridesBuff;
942 } else {
943 mtls->fep.heapAllocatedArrays = true;
944
945 mtls->fep.inPtrs = new const uint8_t*[inLen];
946 mtls->fep.inStrides = new StridePair[inLen];
947 }
948
949 mtls->fep.inLen = inLen;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700950
951 for (int index = inLen; --index >= 0;) {
952 const Allocation *ain = ains[index];
953
Chris Wailesf3712132014-07-16 15:18:30 -0700954 mtls->fep.inPtrs[index] =
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700955 (const uint8_t*)ain->mHal.drvState.lod[0].mallocPtr;
956
957 mtls->fep.inStrides[index].eStride =
958 ain->getType()->getElementSizeBytes();
959 mtls->fep.inStrides[index].yStride =
960 ain->mHal.drvState.lod[0].stride;
961 }
962 }
963
Chris Wailes44bef6f2014-08-12 13:51:10 -0700964 mtls->fep.outPtr = nullptr;
Chris Wailesf3712132014-07-16 15:18:30 -0700965 mtls->fep.outStride.eStride = 0;
966 mtls->fep.outStride.yStride = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700967 if (aout != nullptr) {
Chris Wailesf3712132014-07-16 15:18:30 -0700968 mtls->fep.outPtr = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
969
970 mtls->fep.outStride.eStride = aout->getType()->getElementSizeBytes();
971 mtls->fep.outStride.yStride = aout->mHal.drvState.lod[0].stride;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700972 }
973}
974
Jason Sams709a0972012-11-15 18:18:04 -0800975
976void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
Chris Wailesf3712132014-07-16 15:18:30 -0700977 const Allocation ** ains,
978 uint32_t inLen,
Jason Sams709a0972012-11-15 18:18:04 -0800979 Allocation * aout,
980 const void * usr,
981 uint32_t usrLen,
982 const RsScriptCall *sc) {
983
984 MTLaunchStruct mtls;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700985
986 forEachMtlsSetup(ains, inLen, aout, usr, usrLen, sc, &mtls);
987 forEachKernelSetup(slot, &mtls);
988
989 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
990 mCtx->launchThreads(ains, inLen, aout, sc, &mtls);
991 mCtx->setTLS(oldTLS);
992}
993
Jason Sams709a0972012-11-15 18:18:04 -0800994void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
Jason Sams709a0972012-11-15 18:18:04 -0800995 mtls->script = this;
996 mtls->fep.slot = slot;
Jason Sams110f1812013-03-14 16:02:18 -0700997#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -0800998 rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
999 mtls->kernel = reinterpret_cast<ForEachFunc_t>(
1000 mExecutable->getExportForeachFuncAddrs()[slot]);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001001 rsAssert(mtls->kernel != nullptr);
Jason Sams709a0972012-11-15 18:18:04 -08001002 mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
Jason Sams110f1812013-03-14 16:02:18 -07001003#else
1004 mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001005 rsAssert(mtls->kernel != nullptr);
Jason Sams110f1812013-03-14 16:02:18 -07001006 mtls->sig = mForEachSignatures[slot];
1007#endif
Jason Sams709a0972012-11-15 18:18:04 -08001008}
1009
1010int RsdCpuScriptImpl::invokeRoot() {
1011 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1012 int ret = mRoot();
1013 mCtx->setTLS(oldTLS);
1014 return ret;
1015}
1016
1017void RsdCpuScriptImpl::invokeInit() {
1018 if (mInit) {
1019 mInit();
1020 }
1021}
1022
1023void RsdCpuScriptImpl::invokeFreeChildren() {
1024 if (mFreeChildren) {
1025 mFreeChildren();
1026 }
1027}
1028
1029void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
1030 size_t paramLength) {
1031 //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
Yong Cheneaba5a32014-12-12 13:25:18 +08001032 void * ap = nullptr;
1033
1034#if defined(__x86_64__)
1035 // The invoked function could have input parameter of vector type for example float4 which
1036 // requires void* params to be 16 bytes aligned when using SSE instructions for x86_64 platform.
1037 // So try to align void* params before passing them into RS exported function.
1038
1039 if ((uint8_t)(uint64_t)params & 0x0F) {
1040 if ((ap = (void*)memalign(16, paramLength)) != nullptr) {
1041 memcpy(ap, params, paramLength);
1042 } else {
1043 ALOGE("x86_64: invokeFunction memalign error, still use params which is not 16 bytes aligned.");
1044 }
1045 }
1046#endif
Jason Sams709a0972012-11-15 18:18:04 -08001047
1048 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1049 reinterpret_cast<void (*)(const void *, uint32_t)>(
Jason Sams110f1812013-03-14 16:02:18 -07001050#ifndef RS_COMPATIBILITY_LIB
Yong Cheneaba5a32014-12-12 13:25:18 +08001051 mExecutable->getExportFuncAddrs()[slot])(ap ? (const void *)ap : params, paramLength);
Jason Sams110f1812013-03-14 16:02:18 -07001052#else
Yong Cheneaba5a32014-12-12 13:25:18 +08001053 mInvokeFunctions[slot])(ap ? (const void *)ap : params, paramLength);
Jason Sams110f1812013-03-14 16:02:18 -07001054#endif
Yong Cheneaba5a32014-12-12 13:25:18 +08001055
1056#if defined(__x86_64__)
1057 if (ap) free(ap);
1058#endif
1059
Jason Sams709a0972012-11-15 18:18:04 -08001060 mCtx->setTLS(oldTLS);
1061}
1062
1063void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
1064 //rsAssert(!script->mFieldIsObject[slot]);
1065 //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
1066
1067 //if (mIntrinsicID) {
1068 //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
1069 //return;
1070 //}
1071
Jason Sams110f1812013-03-14 16:02:18 -07001072#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001073 int32_t *destPtr = reinterpret_cast<int32_t *>(
1074 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001075#else
1076 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1077#endif
Jason Sams709a0972012-11-15 18:18:04 -08001078 if (!destPtr) {
1079 //ALOGV("Calling setVar on slot = %i which is null", slot);
1080 return;
1081 }
1082
1083 memcpy(destPtr, data, dataLength);
1084}
1085
Tim Murray9c642392013-04-11 13:29:59 -07001086void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
1087 //rsAssert(!script->mFieldIsObject[slot]);
1088 //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
1089
1090#ifndef RS_COMPATIBILITY_LIB
1091 int32_t *srcPtr = reinterpret_cast<int32_t *>(
1092 mExecutable->getExportVarAddrs()[slot]);
1093#else
1094 int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1095#endif
1096 if (!srcPtr) {
1097 //ALOGV("Calling setVar on slot = %i which is null", slot);
1098 return;
1099 }
1100 memcpy(data, srcPtr, dataLength);
1101}
1102
1103
Jason Sams709a0972012-11-15 18:18:04 -08001104void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
1105 const Element *elem,
Stephen Hinesac8d1462014-06-25 00:01:23 -07001106 const uint32_t *dims, size_t dimLength) {
Jason Sams709a0972012-11-15 18:18:04 -08001107
Jason Sams110f1812013-03-14 16:02:18 -07001108#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001109 int32_t *destPtr = reinterpret_cast<int32_t *>(
1110 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001111#else
1112 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1113#endif
Jason Sams709a0972012-11-15 18:18:04 -08001114 if (!destPtr) {
1115 //ALOGV("Calling setVar on slot = %i which is null", slot);
1116 return;
1117 }
1118
1119 // We want to look at dimension in terms of integer components,
1120 // but dimLength is given in terms of bytes.
1121 dimLength /= sizeof(int);
1122
1123 // Only a single dimension is currently supported.
1124 rsAssert(dimLength == 1);
1125 if (dimLength == 1) {
1126 // First do the increment loop.
1127 size_t stride = elem->getSizeBytes();
1128 const char *cVal = reinterpret_cast<const char *>(data);
Stephen Hinesac8d1462014-06-25 00:01:23 -07001129 for (uint32_t i = 0; i < dims[0]; i++) {
Jason Sams709a0972012-11-15 18:18:04 -08001130 elem->incRefs(cVal);
1131 cVal += stride;
1132 }
1133
1134 // Decrement loop comes after (to prevent race conditions).
1135 char *oldVal = reinterpret_cast<char *>(destPtr);
Stephen Hinesac8d1462014-06-25 00:01:23 -07001136 for (uint32_t i = 0; i < dims[0]; i++) {
Jason Sams709a0972012-11-15 18:18:04 -08001137 elem->decRefs(oldVal);
1138 oldVal += stride;
1139 }
1140 }
1141
1142 memcpy(destPtr, data, dataLength);
1143}
1144
1145void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
1146
1147 //rsAssert(!script->mFieldIsObject[slot]);
1148 //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
1149
Jason Sams110f1812013-03-14 16:02:18 -07001150#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001151 int32_t *destPtr = reinterpret_cast<int32_t *>(
1152 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001153#else
1154 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1155#endif
Jason Sams709a0972012-11-15 18:18:04 -08001156 if (!destPtr) {
1157 //ALOGV("Calling setVar on slot = %i which is null", slot);
1158 return;
1159 }
1160
Chris Wailes44bef6f2014-08-12 13:51:10 -07001161 void *ptr = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001162 mBoundAllocs[slot] = data;
1163 if(data) {
1164 ptr = data->mHal.drvState.lod[0].mallocPtr;
1165 }
1166 memcpy(destPtr, &ptr, sizeof(void *));
1167}
1168
1169void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
1170
1171 //rsAssert(script->mFieldIsObject[slot]);
1172 //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
1173
Jason Sams110f1812013-03-14 16:02:18 -07001174#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001175 int32_t *destPtr = reinterpret_cast<int32_t *>(
1176 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001177#else
1178 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1179#endif
Tim Murraye195a3f2014-03-13 15:04:58 -07001180
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 (mExecutable) {
Chris Wailes70d49712014-08-08 14:42:33 -07001192 std::vector<void *>::const_iterator var_addr_iter =
Jason Sams709a0972012-11-15 18:18:04 -08001193 mExecutable->getExportVarAddrs().begin();
Chris Wailes70d49712014-08-08 14:42:33 -07001194 std::vector<void *>::const_iterator var_addr_end =
Jason Sams709a0972012-11-15 18:18:04 -08001195 mExecutable->getExportVarAddrs().end();
1196
1197 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter =
1198 mExecutable->getInfo().getObjectSlots().begin();
1199 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end =
1200 mExecutable->getInfo().getObjectSlots().end();
1201
1202 while ((var_addr_iter != var_addr_end) &&
1203 (is_object_iter != is_object_end)) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001204 // The field address can be nullptr if the script-side has optimized
Jason Sams709a0972012-11-15 18:18:04 -08001205 // the corresponding global variable away.
Jason Sams05ef73f2014-08-05 14:59:22 -07001206 rs_object_base *obj_addr =
1207 reinterpret_cast<rs_object_base *>(*var_addr_iter);
Jason Sams709a0972012-11-15 18:18:04 -08001208 if (*is_object_iter) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001209 if (*var_addr_iter != nullptr && mCtx->getContext() != nullptr) {
Jason Sams709a0972012-11-15 18:18:04 -08001210 rsrClearObject(mCtx->getContext(), obj_addr);
1211 }
1212 }
1213 var_addr_iter++;
1214 is_object_iter++;
1215 }
1216 }
1217
Jason Sams709a0972012-11-15 18:18:04 -08001218 if (mCompilerDriver) {
1219 delete mCompilerDriver;
1220 }
1221 if (mExecutable) {
1222 delete mExecutable;
1223 }
1224 if (mBoundAllocs) {
1225 delete[] mBoundAllocs;
1226 }
Tim Murraybee48d72014-06-13 12:44:47 -07001227
Tim Murray29809d12014-05-28 12:04:19 -07001228 for (size_t i = 0; i < mExportedForEachFuncList.size(); i++) {
1229 delete[] mExportedForEachFuncList[i].first;
1230 }
Jason Sams110f1812013-03-14 16:02:18 -07001231#else
1232 if (mFieldIsObject) {
1233 for (size_t i = 0; i < mExportedVariableCount; ++i) {
1234 if (mFieldIsObject[i]) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001235 if (mFieldAddress[i] != nullptr) {
Jason Sams05ef73f2014-08-05 14:59:22 -07001236 rs_object_base *obj_addr =
1237 reinterpret_cast<rs_object_base *>(mFieldAddress[i]);
Jason Sams110f1812013-03-14 16:02:18 -07001238 rsrClearObject(mCtx->getContext(), obj_addr);
1239 }
1240 }
1241 }
1242 }
1243
1244 if (mInvokeFunctions) delete[] mInvokeFunctions;
1245 if (mForEachFunctions) delete[] mForEachFunctions;
1246 if (mFieldAddress) delete[] mFieldAddress;
1247 if (mFieldIsObject) delete[] mFieldIsObject;
1248 if (mForEachSignatures) delete[] mForEachSignatures;
1249 if (mBoundAllocs) delete[] mBoundAllocs;
1250 if (mScriptSO) {
1251 dlclose(mScriptSO);
1252 }
1253#endif
Jason Sams709a0972012-11-15 18:18:04 -08001254}
1255
1256Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const {
1257 if (!ptr) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001258 return nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001259 }
1260
1261 for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) {
1262 Allocation *a = mBoundAllocs[ct];
1263 if (!a) continue;
1264 if (a->mHal.drvState.lod[0].mallocPtr == ptr) {
1265 return a;
1266 }
1267 }
1268 ALOGE("rsGetAllocation, failed to find %p", ptr);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001269 return nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001270}
1271
Chris Wailesf3712132014-07-16 15:18:30 -07001272void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation ** ains,
1273 uint32_t inLen, Allocation * aout,
1274 const void * usr, uint32_t usrLen,
1275 const RsScriptCall *sc) {}
Jason Sams17e3cdc2013-09-09 17:32:16 -07001276
Chris Wailesf3712132014-07-16 15:18:30 -07001277void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation ** ains,
1278 uint32_t inLen, Allocation * aout,
1279 const void * usr, uint32_t usrLen,
1280 const RsScriptCall *sc) {}
Jason Sams17e3cdc2013-09-09 17:32:16 -07001281
Jason Sams709a0972012-11-15 18:18:04 -08001282
1283}
1284}