blob: fe51eecc2dd10b8a1988e65fae12caf42b19a96b [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 mCompilerContext = nullptr;
390 mCompilerDriver = nullptr;
391 mExecutable = nullptr;
Jason Sams110f1812013-03-14 16:02:18 -0700392#endif
393
Tim Murraye195a3f2014-03-13 15:04:58 -0700394
Chris Wailes44bef6f2014-08-12 13:51:10 -0700395 mRoot = nullptr;
396 mRootExpand = nullptr;
397 mInit = nullptr;
398 mFreeChildren = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800399
Jason Sams709a0972012-11-15 18:18:04 -0800400
Chris Wailes44bef6f2014-08-12 13:51:10 -0700401 mBoundAllocs = nullptr;
402 mIntrinsicData = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800403 mIsThreadable = true;
404}
405
406
407bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
408 uint8_t const *bitcode, size_t bitcodeSize,
Stephen Hines00511322014-01-31 11:20:23 -0800409 uint32_t flags, char const *bccPluginName) {
Jason Sams709a0972012-11-15 18:18:04 -0800410 //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
411 //ALOGE("rsdScriptInit %p %p", rsc, script);
412
413 mCtx->lockMutex();
Jason Sams110f1812013-03-14 16:02:18 -0700414#ifndef RS_COMPATIBILITY_LIB
Stephen Hines00511322014-01-31 11:20:23 -0800415 bool useRSDebugContext = false;
Jason Sams709a0972012-11-15 18:18:04 -0800416
Chris Wailes44bef6f2014-08-12 13:51:10 -0700417 mCompilerContext = nullptr;
418 mCompilerDriver = nullptr;
419 mExecutable = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -0800420
421 mCompilerContext = new bcc::BCCContext();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700422 if (mCompilerContext == nullptr) {
Jason Sams709a0972012-11-15 18:18:04 -0800423 ALOGE("bcc: FAILS to create compiler context (out of memory)");
424 mCtx->unlockMutex();
425 return false;
426 }
427
428 mCompilerDriver = new bcc::RSCompilerDriver();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700429 if (mCompilerDriver == nullptr) {
Jason Sams709a0972012-11-15 18:18:04 -0800430 ALOGE("bcc: FAILS to create compiler driver (out of memory)");
431 mCtx->unlockMutex();
432 return false;
433 }
434
Stephen Hines25e3af52014-05-21 21:23:08 -0700435 // Configure symbol resolvers (via compiler-rt and the RS runtime).
436 mRSRuntime.setLookupFunction(lookupRuntimeStub);
437 mRSRuntime.setContext(this);
438 mResolver.chainResolver(mCompilerRuntime);
439 mResolver.chainResolver(mRSRuntime);
Jason Sams709a0972012-11-15 18:18:04 -0800440
Stephen Hinesb7d9c802013-04-29 19:13:09 -0700441 // Run any compiler setup functions we have been provided with.
442 RSSetupCompilerCallback setupCompilerCallback =
443 mCtx->getSetupCompilerCallback();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700444 if (setupCompilerCallback != nullptr) {
Stephen Hinesb7d9c802013-04-29 19:13:09 -0700445 setupCompilerCallback(mCompilerDriver);
446 }
447
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700448 bcinfo::MetadataExtractor bitcodeMetadata((const char *) bitcode, bitcodeSize);
449 if (!bitcodeMetadata.extract()) {
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700450 ALOGE("Could not extract metadata from bitcode");
Stephen Hinesf94e8db2014-06-26 11:55:29 -0700451 mCtx->unlockMutex();
Stephen Hinesb58d9ad2013-06-19 19:26:19 -0700452 return false;
453 }
454
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700455 const char* core_lib = findCoreLib(bitcodeMetadata, (const char*)bitcode, bitcodeSize);
Stephen Hinescca3d6c2013-04-15 01:06:39 -0700456
457 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
Stephen Hinesf47e8b42013-04-18 01:06:29 -0700458 mCompilerDriver->setDebugContext(true);
Stephen Hines00511322014-01-31 11:20:23 -0800459 useRSDebugContext = true;
Stephen Hinescca3d6c2013-04-15 01:06:39 -0700460 }
Stephen Hinesba17ae42013-06-05 17:18:04 -0700461
Chris Wailes6847e732014-08-11 17:30:51 -0700462 std::string bcFileName(cacheDir);
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700463 bcFileName.append("/");
464 bcFileName.append(resName);
465 bcFileName.append(".bc");
466
467 std::vector<const char*> compileArguments;
468 setCompileArguments(&compileArguments, bcFileName, cacheDir, resName, core_lib,
469 useRSDebugContext, bccPluginName);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700470 // The last argument of compileArguments ia a nullptr, so remove 1 from the size.
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700471 std::string compileCommandLine =
472 bcc::getCommandLine(compileArguments.size() - 1, compileArguments.data());
473
474 if (!is_force_recompile()) {
475 // Load the compiled script that's in the cache, if any.
476 mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
477 bitcodeSize, compileCommandLine.c_str(),
478 mResolver);
479 }
480
481 // If we can't, it's either not there or out of date. We compile the bit code and try loading
482 // again.
Chris Wailes44bef6f2014-08-12 13:51:10 -0700483 if (mExecutable == nullptr) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700484 if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize, compileArguments.data(),
485 compileCommandLine)) {
486 ALOGE("bcc: FAILS to compile '%s'", resName);
487 mCtx->unlockMutex();
488 return false;
489 }
490 mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
491 bitcodeSize, compileCommandLine.c_str(),
492 mResolver);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700493 if (mExecutable == nullptr) {
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700494 ALOGE("bcc: FAILS to load freshly compiled executable for '%s'", resName);
495 mCtx->unlockMutex();
496 return false;
Stephen Hinesba17ae42013-06-05 17:18:04 -0700497 }
498 }
Jason Sams709a0972012-11-15 18:18:04 -0800499
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700500 mExecutable->setThreadable(mIsThreadable);
501 if (!mExecutable->syncInfo()) {
Jason Sams709a0972012-11-15 18:18:04 -0800502 ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
503 }
504
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700505 mRoot = reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root"));
Jason Sams709a0972012-11-15 18:18:04 -0800506 mRootExpand =
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700507 reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root.expand"));
508 mInit = reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress("init"));
Jason Sams709a0972012-11-15 18:18:04 -0800509 mFreeChildren =
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700510 reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress(".rs.dtor"));
Jason Sams709a0972012-11-15 18:18:04 -0800511
512
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700513 if (bitcodeMetadata.getExportVarCount()) {
514 mBoundAllocs = new Allocation *[bitcodeMetadata.getExportVarCount()];
515 memset(mBoundAllocs, 0, sizeof(void *) * bitcodeMetadata.getExportVarCount());
Tim Murray29809d12014-05-28 12:04:19 -0700516 }
517
Jean-Luc Brouillet40e35cd2014-06-25 18:21:45 -0700518 for (size_t i = 0; i < bitcodeMetadata.getExportForEachSignatureCount(); i++) {
519 char* name = new char[strlen(bitcodeMetadata.getExportForEachNameList()[i]) + 1];
520 mExportedForEachFuncList.push_back(
521 std::make_pair(name, bitcodeMetadata.getExportForEachSignatureList()[i]));
Jason Sams709a0972012-11-15 18:18:04 -0800522 }
523
Jean-Luc Brouilletf4d216e2014-06-09 18:04:16 -0700524#else // RS_COMPATIBILITY_LIB is defined
Jason Sams110f1812013-03-14 16:02:18 -0700525
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700526 mScriptSO = loadSharedLibrary(cacheDir, resName);
Jason Sams110f1812013-03-14 16:02:18 -0700527
528 if (mScriptSO) {
529 char line[MAXLINE];
530 mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
531 if (mRoot) {
532 //ALOGE("Found root(): %p", mRoot);
533 }
534 mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
535 if (mRootExpand) {
536 //ALOGE("Found root.expand(): %p", mRootExpand);
537 }
538 mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
539 if (mInit) {
540 //ALOGE("Found init(): %p", mInit);
541 }
542 mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
543 if (mFreeChildren) {
544 //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
545 }
546
547 const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
548 if (rsInfo) {
549 //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
550 }
551
552 size_t varCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700553 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700554 goto error;
555 }
556 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
557 ALOGE("Invalid export var count!: %s", line);
558 goto error;
559 }
560
561 mExportedVariableCount = varCount;
562 //ALOGE("varCount: %zu", varCount);
563 if (varCount > 0) {
564 // Start by creating/zeroing this member, since we don't want to
565 // accidentally clean up invalid pointers later (if we error out).
566 mFieldIsObject = new bool[varCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700567 if (mFieldIsObject == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700568 goto error;
569 }
570 memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
571 mFieldAddress = new void*[varCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700572 if (mFieldAddress == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700573 goto error;
574 }
575 for (size_t i = 0; i < varCount; ++i) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700576 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700577 goto error;
578 }
579 char *c = strrchr(line, '\n');
580 if (c) {
581 *c = '\0';
582 }
583 mFieldAddress[i] = dlsym(mScriptSO, line);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700584 if (mFieldAddress[i] == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700585 ALOGE("Failed to find variable address for %s: %s",
586 line, dlerror());
587 // Not a critical error if we don't find a global variable.
588 }
589 else {
590 //ALOGE("Found variable %s at %p", line,
591 //mFieldAddress[i]);
592 }
593 }
594 }
595
596 size_t funcCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700597 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700598 goto error;
599 }
600 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
601 ALOGE("Invalid export func count!: %s", line);
602 goto error;
603 }
604
605 mExportedFunctionCount = funcCount;
606 //ALOGE("funcCount: %zu", funcCount);
607
608 if (funcCount > 0) {
609 mInvokeFunctions = new InvokeFunc_t[funcCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700610 if (mInvokeFunctions == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700611 goto error;
612 }
613 for (size_t i = 0; i < funcCount; ++i) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700614 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700615 goto error;
616 }
617 char *c = strrchr(line, '\n');
618 if (c) {
619 *c = '\0';
620 }
621
622 mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700623 if (mInvokeFunctions[i] == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700624 ALOGE("Failed to get function address for %s(): %s",
625 line, dlerror());
626 goto error;
627 }
628 else {
629 //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
630 }
631 }
632 }
633
634 size_t forEachCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700635 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700636 goto error;
637 }
638 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
639 ALOGE("Invalid export forEach count!: %s", line);
640 goto error;
641 }
642
643 if (forEachCount > 0) {
644
645 mForEachSignatures = new uint32_t[forEachCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700646 if (mForEachSignatures == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700647 goto error;
648 }
649 mForEachFunctions = new ForEachFunc_t[forEachCount];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700650 if (mForEachFunctions == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700651 goto error;
652 }
653 for (size_t i = 0; i < forEachCount; ++i) {
654 unsigned int tmpSig = 0;
655 char tmpName[MAXLINE];
656
Chris Wailes44bef6f2014-08-12 13:51:10 -0700657 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700658 goto error;
659 }
660 if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
661 &tmpSig, tmpName) != 2) {
662 ALOGE("Invalid export forEach!: %s", line);
663 goto error;
664 }
665
666 // Lookup the expanded ForEach kernel.
667 strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
668 mForEachSignatures[i] = tmpSig;
669 mForEachFunctions[i] =
670 (ForEachFunc_t) dlsym(mScriptSO, tmpName);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700671 if (i != 0 && mForEachFunctions[i] == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700672 // Ignore missing root.expand functions.
673 // root() is always specified at location 0.
Stephen Hinesef7481e2013-04-09 19:05:27 -0700674 ALOGE("Failed to find forEach function address for %s: %s",
675 tmpName, dlerror());
676 goto error;
Jason Sams110f1812013-03-14 16:02:18 -0700677 }
678 else {
679 //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
680 }
681 }
682 }
683
684 size_t objectSlotCount = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700685 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700686 goto error;
687 }
688 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
689 ALOGE("Invalid object slot count!: %s", line);
690 goto error;
691 }
692
693 if (objectSlotCount > 0) {
694 rsAssert(varCount > 0);
695 for (size_t i = 0; i < objectSlotCount; ++i) {
696 uint32_t varNum = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700697 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
Jason Sams110f1812013-03-14 16:02:18 -0700698 goto error;
699 }
700 if (sscanf(line, "%u", &varNum) != 1) {
701 ALOGE("Invalid object slot!: %s", line);
702 goto error;
703 }
704
705 if (varNum < varCount) {
706 mFieldIsObject[varNum] = true;
707 }
708 }
709 }
710
711 if (varCount > 0) {
712 mBoundAllocs = new Allocation *[varCount];
713 memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
714 }
715
716 if (mScriptSO == (void*)1) {
717 //rsdLookupRuntimeStub(script, "acos");
718 }
Stephen Hinesc2c11cc2013-07-19 01:07:42 -0700719 } else {
720 goto error;
Jason Sams110f1812013-03-14 16:02:18 -0700721 }
722#endif
Jason Sams709a0972012-11-15 18:18:04 -0800723 mCtx->unlockMutex();
724 return true;
Jason Sams110f1812013-03-14 16:02:18 -0700725
726#ifdef RS_COMPATIBILITY_LIB
727error:
728
729 mCtx->unlockMutex();
730 delete[] mInvokeFunctions;
731 delete[] mForEachFunctions;
732 delete[] mFieldAddress;
733 delete[] mFieldIsObject;
734 delete[] mForEachSignatures;
735 delete[] mBoundAllocs;
736 if (mScriptSO) {
737 dlclose(mScriptSO);
738 }
739 return false;
740#endif
Jason Sams709a0972012-11-15 18:18:04 -0800741}
742
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700743#ifndef RS_COMPATIBILITY_LIB
744
745#ifdef __LP64__
746#define SYSLIBPATH "/system/lib64"
747#else
748#define SYSLIBPATH "/system/lib"
749#endif
750
751const char* RsdCpuScriptImpl::findCoreLib(const bcinfo::MetadataExtractor& ME, const char* bitcode,
752 size_t bitcodeSize) {
753 const char* defaultLib = SYSLIBPATH"/libclcore.bc";
754
755 // If we're debugging, use the debug library.
756 if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
757 return SYSLIBPATH"/libclcore_debug.bc";
758 }
759
760 // If a callback has been registered to specify a library, use that.
761 RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
Chris Wailes44bef6f2014-08-12 13:51:10 -0700762 if (selectRTCallback != nullptr) {
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700763 return selectRTCallback((const char*)bitcode, bitcodeSize);
764 }
765
766 // Check for a platform specific library
767#if defined(ARCH_ARM_HAVE_NEON) && !defined(DISABLE_CLCORE_NEON)
768 enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision();
Jean-Luc Brouilletf4d38362014-07-09 17:46:03 -0700769 if (prec == bcinfo::RS_FP_Relaxed) {
Jean-Luc Brouillet9ab50942014-06-18 18:10:32 -0700770 // NEON-capable ARMv7a devices can use an accelerated math library
771 // for all reduced precision scripts.
772 // ARMv8 does not use NEON, as ASIMD can be used with all precision
773 // levels.
774 return SYSLIBPATH"/libclcore_neon.bc";
775 } else {
776 return defaultLib;
777 }
778#elif defined(__i386__) || defined(__x86_64__)
779 // x86 devices will use an optimized library.
780 return SYSLIBPATH"/libclcore_x86.bc";
781#else
782 return defaultLib;
783#endif
784}
785
786#endif
787
Jason Sams709a0972012-11-15 18:18:04 -0800788void RsdCpuScriptImpl::populateScript(Script *script) {
Jason Sams110f1812013-03-14 16:02:18 -0700789#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -0800790 // Copy info over to runtime
Tim Murray29809d12014-05-28 12:04:19 -0700791 script->mHal.info.exportedFunctionCount = mExecutable->getExportFuncAddrs().size();
792 script->mHal.info.exportedVariableCount = mExecutable->getExportVarAddrs().size();
793 script->mHal.info.exportedForeachFuncList = &mExportedForEachFuncList[0];
794 script->mHal.info.exportedPragmaCount = mExecutable->getPragmaKeys().size();
Jason Sams709a0972012-11-15 18:18:04 -0800795 script->mHal.info.exportedPragmaKeyList =
Chris Wailes70d49712014-08-08 14:42:33 -0700796 const_cast<const char**>(&mExecutable->getPragmaKeys().front());
Jason Sams709a0972012-11-15 18:18:04 -0800797 script->mHal.info.exportedPragmaValueList =
Chris Wailes70d49712014-08-08 14:42:33 -0700798 const_cast<const char**>(&mExecutable->getPragmaValues().front());
Jason Sams709a0972012-11-15 18:18:04 -0800799
800 if (mRootExpand) {
801 script->mHal.info.root = mRootExpand;
802 } else {
803 script->mHal.info.root = mRoot;
804 }
Jason Sams110f1812013-03-14 16:02:18 -0700805#else
806 // Copy info over to runtime
807 script->mHal.info.exportedFunctionCount = mExportedFunctionCount;
808 script->mHal.info.exportedVariableCount = mExportedVariableCount;
809 script->mHal.info.exportedPragmaCount = 0;
810 script->mHal.info.exportedPragmaKeyList = 0;
811 script->mHal.info.exportedPragmaValueList = 0;
812
813 // Bug, need to stash in metadata
814 if (mRootExpand) {
815 script->mHal.info.root = mRootExpand;
816 } else {
817 script->mHal.info.root = mRoot;
818 }
819#endif
Jason Sams709a0972012-11-15 18:18:04 -0800820}
821
Jason Sams709a0972012-11-15 18:18:04 -0800822
823typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
824
Chris Wailesf3712132014-07-16 15:18:30 -0700825void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation ** ains,
826 uint32_t inLen,
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700827 Allocation * aout,
828 const void * usr, uint32_t usrLen,
829 const RsScriptCall *sc,
830 MTLaunchStruct *mtls) {
831
832 memset(mtls, 0, sizeof(MTLaunchStruct));
833
Chris Wailesf3712132014-07-16 15:18:30 -0700834 for (int index = inLen; --index >= 0;) {
835 const Allocation* ain = ains[index];
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700836
Chris Wailesf3712132014-07-16 15:18:30 -0700837 // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
Chris Wailes44bef6f2014-08-12 13:51:10 -0700838 if (ain != nullptr &&
839 (const uint8_t *)ain->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 in allocations");
843 return;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700844 }
845 }
846
Chris Wailes44bef6f2014-08-12 13:51:10 -0700847 if (aout &&
848 (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == nullptr) {
849
Chris Wailesf3712132014-07-16 15:18:30 -0700850 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
851 "rsForEach called with null out allocations");
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700852 return;
853 }
854
Chris Wailesf3712132014-07-16 15:18:30 -0700855 if (inLen > 0) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700856 const Allocation *ain0 = ains[0];
857 const Type *inType = ain0->getType();
858
859 mtls->fep.dimX = inType->getDimX();
860 mtls->fep.dimY = inType->getDimY();
861 mtls->fep.dimZ = inType->getDimZ();
862
863 for (int Index = inLen; --Index >= 1;) {
864 if (!ain0->hasSameDims(ains[Index])) {
865 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
866 "Failed to launch kernel; dimensions of input and output allocations do not match.");
867
868 return;
869 }
870 }
871
Chris Wailes44bef6f2014-08-12 13:51:10 -0700872 } else if (aout != nullptr) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700873 const Type *outType = aout->getType();
874
875 mtls->fep.dimX = outType->getDimX();
876 mtls->fep.dimY = outType->getDimY();
877 mtls->fep.dimZ = outType->getDimZ();
878
879 } else {
Chris Wailesf3712132014-07-16 15:18:30 -0700880 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
881 "rsForEach called with null allocations");
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700882 return;
883 }
884
Chris Wailes44bef6f2014-08-12 13:51:10 -0700885 if (inLen > 0 && aout != nullptr) {
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700886 if (!ains[0]->hasSameDims(aout)) {
887 mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
888 "Failed to launch kernel; dimensions of input and output allocations do not match.");
889
890 return;
891 }
892 }
893
894 if (!sc || (sc->xEnd == 0)) {
895 mtls->xEnd = mtls->fep.dimX;
896 } else {
897 rsAssert(sc->xStart < mtls->fep.dimX);
898 rsAssert(sc->xEnd <= mtls->fep.dimX);
899 rsAssert(sc->xStart < sc->xEnd);
900 mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
901 mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
902 if (mtls->xStart >= mtls->xEnd) return;
903 }
904
905 if (!sc || (sc->yEnd == 0)) {
906 mtls->yEnd = mtls->fep.dimY;
907 } else {
908 rsAssert(sc->yStart < mtls->fep.dimY);
909 rsAssert(sc->yEnd <= mtls->fep.dimY);
910 rsAssert(sc->yStart < sc->yEnd);
911 mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
912 mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
913 if (mtls->yStart >= mtls->yEnd) return;
914 }
915
916 if (!sc || (sc->zEnd == 0)) {
917 mtls->zEnd = mtls->fep.dimZ;
918 } else {
919 rsAssert(sc->zStart < mtls->fep.dimZ);
920 rsAssert(sc->zEnd <= mtls->fep.dimZ);
921 rsAssert(sc->zStart < sc->zEnd);
922 mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
923 mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
924 if (mtls->zStart >= mtls->zEnd) return;
925 }
926
927 mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
928 mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
929 mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
930 mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
931
Chris Wailesf3712132014-07-16 15:18:30 -0700932 rsAssert(inLen == 0 || (ains[0]->getType()->getDimZ() == 0));
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700933
934 mtls->rsc = mCtx;
935 mtls->ains = ains;
936 mtls->aout = aout;
937 mtls->fep.usr = usr;
938 mtls->fep.usrLen = usrLen;
939 mtls->mSliceSize = 1;
940 mtls->mSliceNum = 0;
941
Chris Wailes44bef6f2014-08-12 13:51:10 -0700942 mtls->fep.inPtrs = nullptr;
943 mtls->fep.inStrides = nullptr;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700944 mtls->isThreadable = mIsThreadable;
945
Chris Wailesf3712132014-07-16 15:18:30 -0700946 if (inLen > 0) {
947
948 if (inLen <= RS_KERNEL_INPUT_THRESHOLD) {
949 mtls->fep.inPtrs = (const uint8_t**)mtls->inPtrsBuff;
950 mtls->fep.inStrides = mtls->inStridesBuff;
951 } else {
952 mtls->fep.heapAllocatedArrays = true;
953
954 mtls->fep.inPtrs = new const uint8_t*[inLen];
955 mtls->fep.inStrides = new StridePair[inLen];
956 }
957
958 mtls->fep.inLen = inLen;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700959
960 for (int index = inLen; --index >= 0;) {
961 const Allocation *ain = ains[index];
962
Chris Wailesf3712132014-07-16 15:18:30 -0700963 mtls->fep.inPtrs[index] =
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700964 (const uint8_t*)ain->mHal.drvState.lod[0].mallocPtr;
965
966 mtls->fep.inStrides[index].eStride =
967 ain->getType()->getElementSizeBytes();
968 mtls->fep.inStrides[index].yStride =
969 ain->mHal.drvState.lod[0].stride;
970 }
971 }
972
Chris Wailes44bef6f2014-08-12 13:51:10 -0700973 mtls->fep.outPtr = nullptr;
Chris Wailesf3712132014-07-16 15:18:30 -0700974 mtls->fep.outStride.eStride = 0;
975 mtls->fep.outStride.yStride = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700976 if (aout != nullptr) {
Chris Wailesf3712132014-07-16 15:18:30 -0700977 mtls->fep.outPtr = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
978
979 mtls->fep.outStride.eStride = aout->getType()->getElementSizeBytes();
980 mtls->fep.outStride.yStride = aout->mHal.drvState.lod[0].stride;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700981 }
982}
983
Jason Sams709a0972012-11-15 18:18:04 -0800984
985void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
Chris Wailesf3712132014-07-16 15:18:30 -0700986 const Allocation ** ains,
987 uint32_t inLen,
Jason Sams709a0972012-11-15 18:18:04 -0800988 Allocation * aout,
989 const void * usr,
990 uint32_t usrLen,
991 const RsScriptCall *sc) {
992
993 MTLaunchStruct mtls;
Chris Wailes4b3c34e2014-06-11 12:00:29 -0700994
995 forEachMtlsSetup(ains, inLen, aout, usr, usrLen, sc, &mtls);
996 forEachKernelSetup(slot, &mtls);
997
998 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
999 mCtx->launchThreads(ains, inLen, aout, sc, &mtls);
1000 mCtx->setTLS(oldTLS);
1001}
1002
Jason Sams709a0972012-11-15 18:18:04 -08001003void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
Jason Sams709a0972012-11-15 18:18:04 -08001004 mtls->script = this;
1005 mtls->fep.slot = slot;
Jason Sams110f1812013-03-14 16:02:18 -07001006#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001007 rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
1008 mtls->kernel = reinterpret_cast<ForEachFunc_t>(
1009 mExecutable->getExportForeachFuncAddrs()[slot]);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001010 rsAssert(mtls->kernel != nullptr);
Jason Sams709a0972012-11-15 18:18:04 -08001011 mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
Jason Sams110f1812013-03-14 16:02:18 -07001012#else
1013 mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001014 rsAssert(mtls->kernel != nullptr);
Jason Sams110f1812013-03-14 16:02:18 -07001015 mtls->sig = mForEachSignatures[slot];
1016#endif
Jason Sams709a0972012-11-15 18:18:04 -08001017}
1018
1019int RsdCpuScriptImpl::invokeRoot() {
1020 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1021 int ret = mRoot();
1022 mCtx->setTLS(oldTLS);
1023 return ret;
1024}
1025
1026void RsdCpuScriptImpl::invokeInit() {
1027 if (mInit) {
1028 mInit();
1029 }
1030}
1031
1032void RsdCpuScriptImpl::invokeFreeChildren() {
1033 if (mFreeChildren) {
1034 mFreeChildren();
1035 }
1036}
1037
1038void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
1039 size_t paramLength) {
1040 //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
1041
1042 RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1043 reinterpret_cast<void (*)(const void *, uint32_t)>(
Jason Sams110f1812013-03-14 16:02:18 -07001044#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001045 mExecutable->getExportFuncAddrs()[slot])(params, paramLength);
Jason Sams110f1812013-03-14 16:02:18 -07001046#else
1047 mInvokeFunctions[slot])(params, paramLength);
1048#endif
Jason Sams709a0972012-11-15 18:18:04 -08001049 mCtx->setTLS(oldTLS);
1050}
1051
1052void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
1053 //rsAssert(!script->mFieldIsObject[slot]);
1054 //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
1055
1056 //if (mIntrinsicID) {
1057 //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
1058 //return;
1059 //}
1060
Jason Sams110f1812013-03-14 16:02:18 -07001061#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001062 int32_t *destPtr = reinterpret_cast<int32_t *>(
1063 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001064#else
1065 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1066#endif
Jason Sams709a0972012-11-15 18:18:04 -08001067 if (!destPtr) {
1068 //ALOGV("Calling setVar on slot = %i which is null", slot);
1069 return;
1070 }
1071
1072 memcpy(destPtr, data, dataLength);
1073}
1074
Tim Murray9c642392013-04-11 13:29:59 -07001075void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
1076 //rsAssert(!script->mFieldIsObject[slot]);
1077 //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
1078
1079#ifndef RS_COMPATIBILITY_LIB
1080 int32_t *srcPtr = reinterpret_cast<int32_t *>(
1081 mExecutable->getExportVarAddrs()[slot]);
1082#else
1083 int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1084#endif
1085 if (!srcPtr) {
1086 //ALOGV("Calling setVar on slot = %i which is null", slot);
1087 return;
1088 }
1089 memcpy(data, srcPtr, dataLength);
1090}
1091
1092
Jason Sams709a0972012-11-15 18:18:04 -08001093void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
1094 const Element *elem,
Stephen Hinesac8d1462014-06-25 00:01:23 -07001095 const uint32_t *dims, size_t dimLength) {
Jason Sams709a0972012-11-15 18:18:04 -08001096
Jason Sams110f1812013-03-14 16:02:18 -07001097#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001098 int32_t *destPtr = reinterpret_cast<int32_t *>(
1099 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001100#else
1101 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1102#endif
Jason Sams709a0972012-11-15 18:18:04 -08001103 if (!destPtr) {
1104 //ALOGV("Calling setVar on slot = %i which is null", slot);
1105 return;
1106 }
1107
1108 // We want to look at dimension in terms of integer components,
1109 // but dimLength is given in terms of bytes.
1110 dimLength /= sizeof(int);
1111
1112 // Only a single dimension is currently supported.
1113 rsAssert(dimLength == 1);
1114 if (dimLength == 1) {
1115 // First do the increment loop.
1116 size_t stride = elem->getSizeBytes();
1117 const char *cVal = reinterpret_cast<const char *>(data);
Stephen Hinesac8d1462014-06-25 00:01:23 -07001118 for (uint32_t i = 0; i < dims[0]; i++) {
Jason Sams709a0972012-11-15 18:18:04 -08001119 elem->incRefs(cVal);
1120 cVal += stride;
1121 }
1122
1123 // Decrement loop comes after (to prevent race conditions).
1124 char *oldVal = reinterpret_cast<char *>(destPtr);
Stephen Hinesac8d1462014-06-25 00:01:23 -07001125 for (uint32_t i = 0; i < dims[0]; i++) {
Jason Sams709a0972012-11-15 18:18:04 -08001126 elem->decRefs(oldVal);
1127 oldVal += stride;
1128 }
1129 }
1130
1131 memcpy(destPtr, data, dataLength);
1132}
1133
1134void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
1135
1136 //rsAssert(!script->mFieldIsObject[slot]);
1137 //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
1138
Jason Sams110f1812013-03-14 16:02:18 -07001139#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001140 int32_t *destPtr = reinterpret_cast<int32_t *>(
1141 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001142#else
1143 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1144#endif
Jason Sams709a0972012-11-15 18:18:04 -08001145 if (!destPtr) {
1146 //ALOGV("Calling setVar on slot = %i which is null", slot);
1147 return;
1148 }
1149
Chris Wailes44bef6f2014-08-12 13:51:10 -07001150 void *ptr = nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001151 mBoundAllocs[slot] = data;
1152 if(data) {
1153 ptr = data->mHal.drvState.lod[0].mallocPtr;
1154 }
1155 memcpy(destPtr, &ptr, sizeof(void *));
1156}
1157
1158void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
1159
1160 //rsAssert(script->mFieldIsObject[slot]);
1161 //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
1162
Jason Sams110f1812013-03-14 16:02:18 -07001163#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001164 int32_t *destPtr = reinterpret_cast<int32_t *>(
1165 mExecutable->getExportVarAddrs()[slot]);
Jason Sams110f1812013-03-14 16:02:18 -07001166#else
1167 int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1168#endif
Tim Murraye195a3f2014-03-13 15:04:58 -07001169
Jason Sams709a0972012-11-15 18:18:04 -08001170 if (!destPtr) {
1171 //ALOGV("Calling setVar on slot = %i which is null", slot);
1172 return;
1173 }
1174
Jason Sams05ef73f2014-08-05 14:59:22 -07001175 rsrSetObject(mCtx->getContext(), (rs_object_base *)destPtr, data);
Jason Sams709a0972012-11-15 18:18:04 -08001176}
1177
1178RsdCpuScriptImpl::~RsdCpuScriptImpl() {
Jason Sams110f1812013-03-14 16:02:18 -07001179#ifndef RS_COMPATIBILITY_LIB
Jason Sams709a0972012-11-15 18:18:04 -08001180 if (mExecutable) {
Chris Wailes70d49712014-08-08 14:42:33 -07001181 std::vector<void *>::const_iterator var_addr_iter =
Jason Sams709a0972012-11-15 18:18:04 -08001182 mExecutable->getExportVarAddrs().begin();
Chris Wailes70d49712014-08-08 14:42:33 -07001183 std::vector<void *>::const_iterator var_addr_end =
Jason Sams709a0972012-11-15 18:18:04 -08001184 mExecutable->getExportVarAddrs().end();
1185
1186 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter =
1187 mExecutable->getInfo().getObjectSlots().begin();
1188 bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end =
1189 mExecutable->getInfo().getObjectSlots().end();
1190
1191 while ((var_addr_iter != var_addr_end) &&
1192 (is_object_iter != is_object_end)) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001193 // The field address can be nullptr if the script-side has optimized
Jason Sams709a0972012-11-15 18:18:04 -08001194 // the corresponding global variable away.
Jason Sams05ef73f2014-08-05 14:59:22 -07001195 rs_object_base *obj_addr =
1196 reinterpret_cast<rs_object_base *>(*var_addr_iter);
Jason Sams709a0972012-11-15 18:18:04 -08001197 if (*is_object_iter) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001198 if (*var_addr_iter != nullptr && mCtx->getContext() != nullptr) {
Jason Sams709a0972012-11-15 18:18:04 -08001199 rsrClearObject(mCtx->getContext(), obj_addr);
1200 }
1201 }
1202 var_addr_iter++;
1203 is_object_iter++;
1204 }
1205 }
1206
1207 if (mCompilerContext) {
1208 delete mCompilerContext;
1209 }
1210 if (mCompilerDriver) {
1211 delete mCompilerDriver;
1212 }
1213 if (mExecutable) {
1214 delete mExecutable;
1215 }
1216 if (mBoundAllocs) {
1217 delete[] mBoundAllocs;
1218 }
Tim Murraybee48d72014-06-13 12:44:47 -07001219
Tim Murray29809d12014-05-28 12:04:19 -07001220 for (size_t i = 0; i < mExportedForEachFuncList.size(); i++) {
1221 delete[] mExportedForEachFuncList[i].first;
1222 }
Jason Sams110f1812013-03-14 16:02:18 -07001223#else
1224 if (mFieldIsObject) {
1225 for (size_t i = 0; i < mExportedVariableCount; ++i) {
1226 if (mFieldIsObject[i]) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001227 if (mFieldAddress[i] != nullptr) {
Jason Sams05ef73f2014-08-05 14:59:22 -07001228 rs_object_base *obj_addr =
1229 reinterpret_cast<rs_object_base *>(mFieldAddress[i]);
Jason Sams110f1812013-03-14 16:02:18 -07001230 rsrClearObject(mCtx->getContext(), obj_addr);
1231 }
1232 }
1233 }
1234 }
1235
1236 if (mInvokeFunctions) delete[] mInvokeFunctions;
1237 if (mForEachFunctions) delete[] mForEachFunctions;
1238 if (mFieldAddress) delete[] mFieldAddress;
1239 if (mFieldIsObject) delete[] mFieldIsObject;
1240 if (mForEachSignatures) delete[] mForEachSignatures;
1241 if (mBoundAllocs) delete[] mBoundAllocs;
1242 if (mScriptSO) {
1243 dlclose(mScriptSO);
1244 }
1245#endif
Jason Sams709a0972012-11-15 18:18:04 -08001246}
1247
1248Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const {
1249 if (!ptr) {
Chris Wailes44bef6f2014-08-12 13:51:10 -07001250 return nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001251 }
1252
1253 for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) {
1254 Allocation *a = mBoundAllocs[ct];
1255 if (!a) continue;
1256 if (a->mHal.drvState.lod[0].mallocPtr == ptr) {
1257 return a;
1258 }
1259 }
1260 ALOGE("rsGetAllocation, failed to find %p", ptr);
Chris Wailes44bef6f2014-08-12 13:51:10 -07001261 return nullptr;
Jason Sams709a0972012-11-15 18:18:04 -08001262}
1263
Chris Wailesf3712132014-07-16 15:18:30 -07001264void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation ** ains,
1265 uint32_t inLen, Allocation * aout,
1266 const void * usr, uint32_t usrLen,
1267 const RsScriptCall *sc) {}
Jason Sams17e3cdc2013-09-09 17:32:16 -07001268
Chris Wailesf3712132014-07-16 15:18:30 -07001269void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation ** ains,
1270 uint32_t inLen, Allocation * aout,
1271 const void * usr, uint32_t usrLen,
1272 const RsScriptCall *sc) {}
Jason Sams17e3cdc2013-09-09 17:32:16 -07001273
Jason Sams709a0972012-11-15 18:18:04 -08001274
1275}
1276}