Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
impellerc_main.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <filesystem>
6#include <system_error>
7
10#include "flutter/fml/file.h"
11#include "flutter/fml/mapping.h"
19
20namespace impeller {
21namespace compiler {
22
23namespace {
24
25Reflector::Options CreateReflectorOptions(const SourceOptions& options,
26 const Switches& switches) {
27 Reflector::Options reflector_options;
28 reflector_options.target_platform = options.target_platform;
29 reflector_options.entry_point_name = options.entry_point_name;
30 reflector_options.shader_name =
31 InferShaderNameFromPath(switches.source_file_name);
32 reflector_options.header_file_name =
33 Utf8FromPath(switches.reflection_header_name.filename());
34 return reflector_options;
35}
36
37std::shared_ptr<Compiler> CreateCompiler(
38 TargetPlatform platform,
39 const std::shared_ptr<const fml::Mapping>& source_file_mapping,
40 const Switches& switches) {
41 SourceOptions options = switches.CreateSourceOptions();
42 options.target_platform = platform;
43 Reflector::Options reflector_options =
44 CreateReflectorOptions(options, switches);
45 return std::make_shared<Compiler>(source_file_mapping, options,
46 reflector_options);
47}
48
49void OutputVerboseErrorFile(const std::string& verbose_error_messages,
50 const Switches& switches) {
51 auto error_mapping = std::make_shared<fml::NonOwnedMapping>(
52 reinterpret_cast<const uint8_t*>(verbose_error_messages.data()),
53 verbose_error_messages.size(), [](auto, auto) {});
54 std::filesystem::path output_path =
55 std::filesystem::path(fml::CreateTemporaryDirectory()) /
56 "impellerc_verbose_error.txt";
57
58 if (fml::WriteAtomically(*switches.working_directory,
59 Utf8FromPath(output_path).c_str(), *error_mapping)) {
60 std::cerr << "Full \"" << InferShaderNameFromPath(switches.source_file_name)
61 << "\" error output written to " << output_path << std::endl;
62 } else {
63 std::cerr << "Failed to write full \""
64 << InferShaderNameFromPath(switches.source_file_name)
65 << "\" error output to " << output_path << std::endl;
66 }
67}
68
69bool OutputIPLR(const std::vector<std::shared_ptr<Compiler>>& compilers,
70 const Switches& switches) {
71 FML_DCHECK(switches.iplr);
72
73 RuntimeStageData stages;
74 for (const auto& compiler : compilers) {
75 std::shared_ptr<RuntimeStageData::Shader> stage_data =
76 compiler->GetReflector()->GetRuntimeStageShaderData();
77 if (!stage_data) {
78 std::cerr << "Runtime stage information was nil." << std::endl;
79 return false;
80 }
81 stages.AddShader(stage_data);
82 }
83
84 auto stage_data_mapping = switches.json_format ? stages.CreateJsonMapping()
85 : stages.CreateMapping();
86 if (!stage_data_mapping) {
87 std::cerr << "Runtime stage data could not be created." << std::endl;
88 return false;
89 }
90 if (!fml::WriteAtomically(*switches.working_directory, //
91 Utf8FromPath(switches.sl_file_name).c_str(), //
92 *stage_data_mapping //
93 )) {
94 std::cerr << "Could not write file to " << switches.sl_file_name
95 << std::endl;
96 return false;
97 }
98 // Tools that consume the runtime stage data expect the access mode to
99 // be 0644.
100 if (!SetPermissiveAccess(switches.sl_file_name)) {
101 return false;
102 }
103 return true;
104}
105
106bool OutputSLFile(const Compiler& compiler, const Switches& switches) {
107 auto sl_file_name = std::filesystem::absolute(
108 std::filesystem::current_path() / switches.sl_file_name);
109 if (!fml::WriteAtomically(*switches.working_directory,
110 Utf8FromPath(sl_file_name).c_str(),
111 *compiler.GetSLShaderSource())) {
112 std::cerr << "Could not write file to " << switches.sl_file_name
113 << std::endl;
114 return false;
115 }
116 return true;
117}
118
119bool OutputSPIRV(const Compiler& compiler, const Switches& switches) {
120 auto spriv_file_name = std::filesystem::absolute(
121 std::filesystem::current_path() / switches.spirv_file_name);
122 if (!fml::WriteAtomically(*switches.working_directory,
123 Utf8FromPath(spriv_file_name).c_str(),
124 *compiler.GetSPIRVAssembly())) {
125 std::cerr << "Could not write file to " << switches.spirv_file_name
126 << std::endl;
127 return false;
128 }
129 return true;
130}
131
132bool ShouldOutputReflectionData(const Switches& switches) {
133 return !switches.reflection_json_name.empty() ||
134 !switches.reflection_header_name.empty() ||
135 !switches.reflection_cc_name.empty();
136}
137
138bool OutputReflectionData(const Compiler& compiler, const Switches& switches) {
139 if (!switches.reflection_json_name.empty()) {
140 auto reflection_json_name = std::filesystem::absolute(
141 std::filesystem::current_path() / switches.reflection_json_name);
142 if (!fml::WriteAtomically(*switches.working_directory,
143 Utf8FromPath(reflection_json_name).c_str(),
144 *compiler.GetReflector()->GetReflectionJSON())) {
145 std::cerr << "Could not write reflection json to "
146 << switches.reflection_json_name << std::endl;
147 return false;
148 }
149 }
150
151 if (!switches.reflection_header_name.empty()) {
152 auto reflection_header_name = std::filesystem::absolute(
153 std::filesystem::current_path() / switches.reflection_header_name);
155 *switches.working_directory,
156 Utf8FromPath(reflection_header_name).c_str(),
157 *compiler.GetReflector()->GetReflectionHeader())) {
158 std::cerr << "Could not write reflection header to "
159 << switches.reflection_header_name << std::endl;
160 return false;
161 }
162 }
163
164 if (!switches.reflection_cc_name.empty()) {
165 auto reflection_cc_name = std::filesystem::absolute(
166 std::filesystem::current_path() / switches.reflection_cc_name);
167 if (!fml::WriteAtomically(*switches.working_directory,
168 Utf8FromPath(reflection_cc_name).c_str(),
169 *compiler.GetReflector()->GetReflectionCC())) {
170 std::cerr << "Could not write reflection CC to "
171 << switches.reflection_cc_name << std::endl;
172 return false;
173 }
174 }
175 return true;
176}
177
178bool OutputDepfile(const Compiler& compiler, const Switches& switches) {
179 if (!switches.depfile_path.empty()) {
180 std::string result_file = Utf8FromPath(switches.sl_file_name);
181 auto depfile_path = std::filesystem::absolute(
182 std::filesystem::current_path() / switches.depfile_path);
183 if (!fml::WriteAtomically(*switches.working_directory,
184 Utf8FromPath(depfile_path).c_str(),
185 *compiler.CreateDepfileContents({result_file}))) {
186 std::cerr << "Could not write depfile to " << switches.depfile_path
187 << std::endl;
188 return false;
189 }
190 }
191
192 return true;
193}
194
195} // namespace
196
197bool Main(const fml::CommandLine& command_line) {
199 if (command_line.HasOption("help")) {
200 Switches::PrintHelp(std::cout);
201 return true;
202 }
203
204 Switches switches(command_line);
205 if (!switches.AreValid(std::cerr)) {
206 std::cerr << "Invalid flags specified." << std::endl;
207 Switches::PrintHelp(std::cerr);
208 return false;
209 }
210
211 if (!switches.shader_bundle.empty()) {
212 // Invoke the compiler multiple times to build a shader bundle with the
213 // given shader_bundle spec.
214 return GenerateShaderBundle(switches);
215 }
216
217 std::shared_ptr<fml::FileMapping> source_file_mapping =
219 if (!source_file_mapping) {
220 std::cerr << "Could not open input file." << std::endl;
221 return false;
222 }
223
224 std::vector<std::shared_ptr<Compiler>> compilers;
225 compilers.reserve(switches.PlatformsToCompile().size());
226 for (const auto& platform : switches.PlatformsToCompile()) {
227 std::shared_ptr<Compiler> compiler =
228 CreateCompiler(platform, source_file_mapping, switches);
229 if (compiler->IsValid()) {
230 compilers.push_back(compiler);
231 } else {
232 std::cerr << "Compilation failed for target: "
233 << TargetPlatformToString(platform) << std::endl;
234
235 std::string verbose_error_messages = compiler->GetVerboseErrorMessages();
236 if (verbose_error_messages.empty()) {
237 // No verbose error messages. Output the regular error messages.
238 std::cerr << compiler->GetErrorMessages();
239 } else {
240 if (switches.verbose) {
241 // Verbose messages are available and the --verbose flag was set.
242 // Directly output the verbose error messages.
243 std::cerr << verbose_error_messages;
244 } else {
245 // Verbose messages are available and the --verbose flag was not set.
246 // Output the regular error messages and write the verbose error
247 // messages to a file.
248 std::cerr << compiler->GetErrorMessages();
249 OutputVerboseErrorFile(verbose_error_messages, switches);
250 }
251 }
252
253 return false;
254 }
255 }
256
257 // --------------------------------------------------------------------------
258 /// 1. Output the source file. When in IPLR/RuntimeStage mode, output the
259 /// serialized IPLR flatbuffer. Otherwise output the shader source in the
260 /// target shading language.
261 ///
262
263 if (switches.iplr) {
264 if (!OutputIPLR(compilers, switches)) {
265 return false;
266 }
267 } else {
268 // Non-IPLR mode is supported only for single platform targets. There is
269 // exactly 1 created compiler for this case.
270 FML_DCHECK(compilers.size() == 1);
271 if (!OutputSLFile(*compilers.front(), switches)) {
272 return false;
273 }
274 }
275
276 // Use the first compiler for outputting the SPIRV file, reflection data, and
277 // the depfile. The SPIRV and depfile outputs do not depend on the target
278 // platform, so any valid compiler can be used. Reflection data output is only
279 // supported for single platform targets, so it uses the first (only) valid
280 // compiler as well.
281 auto first_valid_compiler = compilers.front();
282
283 // --------------------------------------------------------------------------
284 /// 2. Output SPIRV file.
285 ///
286
287 if (!OutputSPIRV(*first_valid_compiler, switches)) {
288 return false;
289 }
290
291 // --------------------------------------------------------------------------
292 /// 3. Output shader reflection data.
293 /// May include a JSON file, a C++ header, and/or a C++ TU.
294 ///
295
296 if (ShouldOutputReflectionData(switches)) {
297 // Outputting reflection data is supported only for single platform targets.
298 FML_DCHECK(compilers.size() == 1);
299 if (!OutputReflectionData(*first_valid_compiler, switches)) {
300 return false;
301 }
302 }
303
304 // --------------------------------------------------------------------------
305 /// 4. Output a depfile.
306 ///
307
308 // Dep file output does not depend on the target platform. Any valid compiler
309 // can be used to output it. Arbitrarily pick the first valid compiler.
310 if (!OutputDepfile(*first_valid_compiler, switches)) {
311 return false;
312 }
313
314 return true;
315}
316
317} // namespace compiler
318} // namespace impeller
319
320int main(int argc, char const* argv[]) {
323 ? EXIT_SUCCESS
324 : EXIT_FAILURE;
325}
bool HasOption(std::string_view name, size_t *index=nullptr) const
static std::unique_ptr< FileMapping > CreateReadOnly(const std::string &path)
Definition mapping.cc:20
std::vector< TargetPlatform > PlatformsToCompile() const
A vector containing at least one valid platform.
Definition switches.cc:312
bool AreValid(std::ostream &explain) const
Definition switches.cc:259
static void PrintHelp(std::ostream &stream)
Definition switches.cc:43
std::filesystem::path source_file_name
Definition switches.h:26
#define FML_DCHECK(condition)
Definition logging.h:122
int main(int argc, char const *argv[])
char ** argv
Definition library.h:9
bool WriteAtomically(const fml::UniqueFD &base_directory, const char *file_name, const Mapping &mapping)
std::string CreateTemporaryDirectory()
Definition file_posix.cc:25
void InstallCrashHandler()
Definition backtrace.cc:126
CommandLine CommandLineFromPlatformOrArgcArgv(int argc, const char *const *argv)
bool Main(const fml::CommandLine &command_line)
std::string TargetPlatformToString(TargetPlatform platform)
Definition types.cc:62
bool SetPermissiveAccess(const std::filesystem::path &p)
Sets the file access mode of the file at path 'p' to 0644.
Definition utilities.cc:16
std::string InferShaderNameFromPath(const std::filesystem::path &path)
Definition utilities.cc:34
bool GenerateShaderBundle(Switches &switches)
Parses the JSON shader bundle configuration and invokes the compiler multiple times to produce a shad...
static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options)
Definition compiler.cc:234
std::string Utf8FromPath(const std::filesystem::path &path)
Converts a native format path to a utf8 string.
Definition utilities.cc:30