blob: da879681d0501175217c05bf304fb623007d27b8 [file] [log] [blame]
Zonr Chang0fffa7e2012-04-12 19:43:53 +08001/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Zonr Changc72c4dd2012-04-12 15:38:53 +080017#include "bcc/RenderScript/RSCompilerDriver.h"
Zonr Chang0fffa7e2012-04-12 19:43:53 +080018
Zonr Changc72c4dd2012-04-12 15:38:53 +080019#include "bcc/RenderScript/RSExecutable.h"
20#include "bcc/Support/CompilerConfig.h"
21#include "bcc/Support/TargetCompilerConfigs.h"
Zonr Changc72c4dd2012-04-12 15:38:53 +080022#include "bcc/Support/FileMutex.h"
Zonr Changef73a242012-04-12 16:44:01 +080023#include "bcc/Support/Log.h"
Zonr Changc72c4dd2012-04-12 15:38:53 +080024#include "bcc/Support/InputFile.h"
25#include "bcc/Support/Initialization.h"
26#include "bcc/Support/OutputFile.h"
Zonr Chang0fffa7e2012-04-12 19:43:53 +080027
28#include <cutils/properties.h>
29#include <utils/String8.h>
30
31using namespace bcc;
32
33namespace {
34
35bool is_force_recompile() {
36 char buf[PROPERTY_VALUE_MAX];
37
38 property_get("debug.rs.forcerecompile", buf, "0");
39 if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
40 return true;
41 } else {
42 return false;
43 }
44}
45
46} // end anonymous namespace
47
48RSCompilerDriver::RSCompilerDriver() : mConfig(NULL), mCompiler() {
49 init::Initialize();
50 // Chain the symbol resolvers for BCC runtimes and RS runtimes.
51 mResolver.chainResolver(mBCCRuntime);
52 mResolver.chainResolver(mRSRuntime);
53}
54
55RSCompilerDriver::~RSCompilerDriver() {
56 delete mConfig;
57}
58
59RSExecutable *RSCompilerDriver::loadScriptCache(const RSScript &pScript,
60 const std::string &pOutputPath){
61 RSExecutable *result = NULL;
62
63 if (is_force_recompile())
64 return NULL;
65
66 //===--------------------------------------------------------------------===//
67 // Acquire the read lock for reading output object file.
68 //===--------------------------------------------------------------------===//
69 FileMutex<FileBase::kReadLock> read_output_mutex(pOutputPath);
70
71 if (read_output_mutex.hasError() || !read_output_mutex.lock()) {
72 ALOGE("Unable to acquire the read lock for %s! (%s)", pOutputPath.c_str(),
73 read_output_mutex.getErrorMessage().c_str());
74 return NULL;
75 }
76
77 //===--------------------------------------------------------------------===//
78 // Read the output object file.
79 //===--------------------------------------------------------------------===//
80 InputFile *output_file = new (std::nothrow) InputFile(pOutputPath);
81
82 if ((output_file == NULL) || output_file->hasError()) {
83 ALOGE("Unable to open the %s for read! (%s)", pOutputPath.c_str(),
84 output_file->getErrorMessage().c_str());
85 delete output_file;
86 return NULL;
87 }
88
89 //===--------------------------------------------------------------------===//
90 // Acquire the read lock on output_file for reading its RS info file.
91 //===--------------------------------------------------------------------===//
92 android::String8 info_path = RSInfo::GetPath(*output_file);
93
94 if (!output_file->lock()) {
95 ALOGE("Unable to acquire the read lock on %s for reading %s! (%s)",
96 pOutputPath.c_str(), info_path.string(),
97 output_file->getErrorMessage().c_str());
98 delete output_file;
99 return NULL;
100 }
101
102 //===---------------------------------------------------------------------===//
103 // Open and load the RS info file.
104 //===--------------------------------------------------------------------===//
105 InputFile info_file(info_path.string());
106 RSInfo *info = RSInfo::ReadFromFile(info_file,
107 pScript.getSourceDependencies());
108
109 // Release the lock on output_file.
110 output_file->unlock();
111
112 if (info == NULL) {
113 delete output_file;
114 return NULL;
115 }
116
117 //===--------------------------------------------------------------------===//
118 // Create the RSExecutable.
119 //===--------------------------------------------------------------------===//
120 result = RSExecutable::Create(*info, *output_file, mResolver);
121 if (result == NULL) {
122 delete output_file;
123 delete info;
124 return NULL;
125 }
126
127 // TODO: Dirty hack for libRS. This can be removed once RSExecutable is public
128 // to libRS.
129 if (!result->isThreadable()) {
130 mRSRuntime.getAddress("__clearThreadable");
131 }
132
133 return result;
134}
135
136bool RSCompilerDriver::setupConfig(const RSScript &pScript) {
137 bool changed = false;
138
139 const llvm::CodeGenOpt::Level script_opt_level =
140 static_cast<llvm::CodeGenOpt::Level>(pScript.getOptimizationLevel());
141
142 if (mConfig != NULL) {
143 // Renderscript bitcode may have their optimization flag configuration
144 // different than the previous run of RS compilation.
145 if (mConfig->getOptimizationLevel() != script_opt_level) {
146 mConfig->setOptimizationLevel(script_opt_level);
147 changed = true;
148 }
149 } else {
150 // Haven't run the compiler ever.
151 mConfig = new (std::nothrow) DefaultCompilerConfig();
152 if (mConfig == NULL) {
153 // Return false since mConfig remains NULL and out-of-memory.
154 return false;
155 }
156 mConfig->setOptimizationLevel(script_opt_level);
157 changed = true;
158 }
159
160#if defined(DEFAULT_ARM_CODEGEN)
161 // NEON should be disable when full-precision floating point is required.
162 assert((pScript.getInfo() != NULL) && "NULL RS info!");
163 if (pScript.getInfo()->getFloatPrecisionRequirement() == RSInfo::Full) {
164 // Must be ARMCompilerConfig.
165 ARMCompilerConfig *arm_config = static_cast<ARMCompilerConfig *>(mConfig);
166 changed |= arm_config->enableNEON(/* pEnable */false);
167 }
168#endif
169
170 return changed;
171}
172
173RSExecutable *RSCompilerDriver::compileScript(RSScript &pScript,
174 const std::string &pOutputPath) {
175 RSExecutable *result = NULL;
176 RSInfo *info = NULL;
177
178 //===--------------------------------------------------------------------===//
179 // Extract RS-specific information from source bitcode.
180 //===--------------------------------------------------------------------===//
181 // RS info may contains configuration (such as #optimization_level) to the
182 // compiler therefore it should be extracted before compilation.
183 info = RSInfo::ExtractFromSource(pScript.getSource(),
184 pScript.getSourceDependencies());
185 if (info == NULL) {
186 return NULL;
187 }
188
189 //===--------------------------------------------------------------------===//
190 // Associate script with its info
191 //===--------------------------------------------------------------------===//
192 // This is required since RS compiler may need information in the info file
193 // to do some transformation (e.g., expand foreach-able function.)
194 pScript.setInfo(info);
195
196 //===--------------------------------------------------------------------===//
197 // Acquire the write lock for writing output object file.
198 //===--------------------------------------------------------------------===//
199 FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath);
200
201 if (write_output_mutex.hasError() || !write_output_mutex.lock()) {
202 ALOGE("Unable to acquire the lock for writing %s! (%s)",
203 pOutputPath.c_str(), write_output_mutex.getErrorMessage().c_str());
204 return NULL;
205 }
206
207 //===--------------------------------------------------------------------===//
208 // Open the output file for write.
209 //===--------------------------------------------------------------------===//
210 OutputFile *output_file = new (std::nothrow) OutputFile(pOutputPath);
211
212 if ((output_file == NULL) || output_file->hasError()) {
213 ALOGE("Unable to open the %s for write! (%s)", pOutputPath.c_str(),
214 output_file->getErrorMessage().c_str());
215 delete info;
216 delete output_file;
217 return NULL;
218 }
219
220 //===--------------------------------------------------------------------===//
221 // Setup the config to the compiler.
222 //===--------------------------------------------------------------------===//
223 bool compiler_need_reconfigure = setupConfig(pScript);
224
225 if (mConfig == NULL) {
226 ALOGE("Failed to setup config for RS compiler to compile %s!",
227 pOutputPath.c_str());
228 delete info;
229 delete output_file;
230 return NULL;
231 }
232
233 // Compiler need to re-config if it's haven't run the config() yet or the
234 // configuration it referenced is changed.
235 if (compiler_need_reconfigure) {
236 Compiler::ErrorCode err = mCompiler.config(*mConfig);
237 if (err != Compiler::kSuccess) {
238 ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath.c_str(),
239 Compiler::GetErrorString(err));
240 delete info;
241 delete output_file;
242 return NULL;
243 }
244 }
245
246 //===--------------------------------------------------------------------===//
247 // Run the compiler.
248 //===--------------------------------------------------------------------===//
249 Compiler::ErrorCode compile_result = mCompiler.compile(pScript, *output_file);
250 if (compile_result != Compiler::kSuccess) {
251 ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath.c_str(),
252 Compiler::GetErrorString(compile_result));
253 delete info;
254 delete output_file;
255 return NULL;
256 }
257
258 //===--------------------------------------------------------------------===//
259 // Create the RSExecutable.
260 //===--------------------------------------------------------------------===//
261 result = RSExecutable::Create(*info, *output_file, mResolver);
262 if (result == NULL) {
263 delete info;
264 delete output_file;
265 return NULL;
266 }
267
268 // TODO: Dirty hack for libRS. This can be removed once RSExecutable is public
269 // to libRS.
270 result->setThreadable(mRSRuntime.getAddress("__isThreadable") != NULL);
271
272 //===--------------------------------------------------------------------===//
273 // Write out the RS info file.
274 //===--------------------------------------------------------------------===//
275 // Note that write failure only results in a warning since the source is
276 // successfully compiled and loaded.
277 if (!result->syncInfo(/* pForce */true)) {
278 ALOGW("%s was successfully compiled and loaded but its RS info file failed "
279 "to write out!", pOutputPath.c_str());
280 }
281
282 return result;
283}
284
285RSExecutable *RSCompilerDriver::build(RSScript &pScript,
286 const std::string &pOutputPath) {
287 RSExecutable *result = loadScriptCache(pScript, pOutputPath);
288
289 if (result != NULL) {
290 // Cache hit
291 return result;
292 }
293
294 return compileScript(pScript, pOutputPath);
295}