| Flutter Impeller |

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
8 #include "flutter/fml/backtrace.h"
9 #include "flutter/fml/command_line.h"
10 #include "flutter/fml/file.h"
11 #include "flutter/fml/mapping.h"
12 #include "impeller/compiler/compiler.h"
13 #include "impeller/compiler/runtime_stage_data.h"
14 #include "impeller/compiler/shader_bundle.h"
15 #include "impeller/compiler/source_options.h"
16 #include "impeller/compiler/switches.h"
17 #include "impeller/compiler/types.h"
18 #include "impeller/compiler/utilities.h"
19
20 namespace impeller {
21 namespace compiler {
22
23 static Reflector::Options CreateReflectorOptions(const SourceOptions& options,
24 const Switches& switches) {
25 Reflector::Options reflector_options;
26 reflector_options.target_platform = options.target_platform;
27 reflector_options.entry_point_name = options.entry_point_name;
28 reflector_options.shader_name =
29 InferShaderNameFromPath(switches.source_file_name);
30 reflector_options.header_file_name =
31 Utf8FromPath(switches.reflection_header_name.filename());
32 return reflector_options;
33 }
34
35 /// Run the shader compiler to geneate SkSL reflection data.
36 /// If there is an error, prints error text and returns `nullptr`.
37 static std::shared_ptr<RuntimeStageData::Shader> CompileSkSL(
38 std::shared_ptr<fml::Mapping> source_file_mapping,
39 const Switches& switches) {
40 auto options = switches.CreateSourceOptions(TargetPlatform::kSkSL);
41
42 Reflector::Options sksl_reflector_options =
43 CreateReflectorOptions(options, switches);
44 sksl_reflector_options.target_platform = TargetPlatform::kSkSL;
45
46 Compiler sksl_compiler =
47 Compiler(std::move(source_file_mapping), options, sksl_reflector_options);
48 if (!sksl_compiler.IsValid()) {
49 std::cerr << "Compilation to SkSL failed." << std::endl;
50 std::cerr << sksl_compiler.GetErrorMessages() << std::endl;
51 return nullptr;
52 }
53 return sksl_compiler.GetReflector()->GetRuntimeStageShaderData();
54 }
55
56 static bool OutputIPLR(
57 const Switches& switches,
58 const std::shared_ptr<fml::Mapping>& source_file_mapping) {
59 FML_DCHECK(switches.iplr);
60
61 RuntimeStageData stages;
62 std::shared_ptr<RuntimeStageData::Shader> sksl_shader;
63 if (TargetPlatformBundlesSkSL(switches.SelectDefaultTargetPlatform())) {
64 sksl_shader = CompileSkSL(source_file_mapping, switches);
65 if (!sksl_shader) {
66 return false;
67 }
68 stages.AddShader(sksl_shader);
69 }
70
71 for (const auto& platform : switches.PlatformsToCompile()) {
72 if (platform == TargetPlatform::kSkSL) {
73 // Already handled above.
74 continue;
75 }
76 SourceOptions options = switches.CreateSourceOptions(platform);
77
78 // Invoke the compiler and generate reflection data for a single shader.
79
80 Reflector::Options reflector_options =
81 CreateReflectorOptions(options, switches);
82 Compiler compiler(source_file_mapping, options, reflector_options);
83 if (!compiler.IsValid()) {
84 std::cerr << "Compilation failed." << std::endl;
85 std::cerr << compiler.GetErrorMessages() << std::endl;
86 return false;
87 }
88
89 auto reflector = compiler.GetReflector();
90 if (reflector == nullptr) {
91 std::cerr << "Could not create reflector." << std::endl;
92 return false;
93 }
94
95 auto stage_data = reflector->GetRuntimeStageShaderData();
96 if (!stage_data) {
97 std::cerr << "Runtime stage information was nil." << std::endl;
98 return false;
99 }
100
101 stages.AddShader(stage_data);
102 }
103
104 auto stage_data_mapping = switches.json_format ? stages.CreateJsonMapping()
105 : stages.CreateMapping();
106 if (!stage_data_mapping) {
107 std::cerr << "Runtime stage data could not be created." << std::endl;
108 return false;
109 }
110 if (!fml::WriteAtomically(*switches.working_directory, //
111 Utf8FromPath(switches.sl_file_name).c_str(), //
112 *stage_data_mapping //
113 )) {
114 std::cerr << "Could not write file to " << switches.sl_file_name
115 << std::endl;
116 return false;
117 }
118 // Tools that consume the runtime stage data expect the access mode to
119 // be 0644.
120 if (!SetPermissiveAccess(switches.sl_file_name)) {
121 return false;
122 }
123 return true;
124 }
125
126 static bool OutputSLFile(const Compiler& compiler, const Switches& switches) {
127 // --------------------------------------------------------------------------
128 /// 2. Output the source file. When in IPLR/RuntimeStage mode, output the
129 /// serialized IPLR flatbuffer.
130 ///
131
132 auto sl_file_name = std::filesystem::absolute(
133 std::filesystem::current_path() / switches.sl_file_name);
134 if (!fml::WriteAtomically(*switches.working_directory,
135 Utf8FromPath(sl_file_name).c_str(),
136 *compiler.GetSLShaderSource())) {
137 std::cerr << "Could not write file to " << switches.sl_file_name
138 << std::endl;
139 return false;
140 }
141 return true;
142 }
143
144 static bool OutputReflectionData(const Compiler& compiler,
145 const Switches& switches,
146 const SourceOptions& options) {
147 // --------------------------------------------------------------------------
148 /// 3. Output shader reflection data.
149 /// May include a JSON file, a C++ header, and/or a C++ TU.
150 ///
151
152 if (TargetPlatformNeedsReflection(options.target_platform)) {
153 if (!switches.reflection_json_name.empty()) {
154 auto reflection_json_name = std::filesystem::absolute(
155 std::filesystem::current_path() / switches.reflection_json_name);
156 if (!fml::WriteAtomically(
157 *switches.working_directory,
158 Utf8FromPath(reflection_json_name).c_str(),
159 *compiler.GetReflector()->GetReflectionJSON())) {
160 std::cerr << "Could not write reflection json to "
161 << switches.reflection_json_name << std::endl;
162 return false;
163 }
164 }
165
166 if (!switches.reflection_header_name.empty()) {
167 auto reflection_header_name = std::filesystem::absolute(
168 std::filesystem::current_path() / switches.reflection_header_name);
169 if (!fml::WriteAtomically(
170 *switches.working_directory,
171 Utf8FromPath(reflection_header_name).c_str(),
172 *compiler.GetReflector()->GetReflectionHeader())) {
173 std::cerr << "Could not write reflection header to "
174 << switches.reflection_header_name << std::endl;
175 return false;
176 }
177 }
178
179 if (!switches.reflection_cc_name.empty()) {
180 auto reflection_cc_name = std::filesystem::absolute(
181 std::filesystem::current_path() / switches.reflection_cc_name);
182 if (!fml::WriteAtomically(*switches.working_directory,
183 Utf8FromPath(reflection_cc_name).c_str(),
184 *compiler.GetReflector()->GetReflectionCC())) {
185 std::cerr << "Could not write reflection CC to "
186 << switches.reflection_cc_name << std::endl;
187 return false;
188 }
189 }
190 }
191 return true;
192 }
193
194 static bool OutputDepfile(const Compiler& compiler, const Switches& switches) {
195 // --------------------------------------------------------------------------
196 /// 4. Output a depfile.
197 ///
198
199 if (!switches.depfile_path.empty()) {
200 std::string result_file;
201 switch (switches.SelectDefaultTargetPlatform()) {
202 case TargetPlatform::kMetalDesktop:
203 case TargetPlatform::kMetalIOS:
204 case TargetPlatform::kOpenGLES:
205 case TargetPlatform::kOpenGLDesktop:
206 case TargetPlatform::kRuntimeStageMetal:
207 case TargetPlatform::kRuntimeStageGLES:
208 case TargetPlatform::kRuntimeStageGLES3:
209 case TargetPlatform::kRuntimeStageVulkan:
210 case TargetPlatform::kSkSL:
211 case TargetPlatform::kVulkan:
212 result_file = Utf8FromPath(switches.sl_file_name);
213 break;
214 case TargetPlatform::kUnknown:
215 result_file = Utf8FromPath(switches.spirv_file_name);
216 break;
217 }
218 auto depfile_path = std::filesystem::absolute(
219 std::filesystem::current_path() / switches.depfile_path);
220 if (!fml::WriteAtomically(*switches.working_directory,
221 Utf8FromPath(depfile_path).c_str(),
222 *compiler.CreateDepfileContents({result_file}))) {
223 std::cerr << "Could not write depfile to " << switches.depfile_path
224 << std::endl;
225 return false;
226 }
227 }
228
229 return true;
230 }
231
232 bool Main(const fml::CommandLine& command_line) {
233 fml::InstallCrashHandler();
234 if (command_line.HasOption("help")) {
235 Switches::PrintHelp(std::cout);
236 return true;
237 }
238
239 Switches switches(command_line);
240 if (!switches.AreValid(std::cerr)) {
241 std::cerr << "Invalid flags specified." << std::endl;
242 Switches::PrintHelp(std::cerr);
243 return false;
244 }
245
246 if (!switches.shader_bundle.empty()) {
247 // Invoke the compiler multiple times to build a shader bundle with the
248 // given shader_bundle spec.
249 return GenerateShaderBundle(switches);
250 }
251
252 std::shared_ptr<fml::FileMapping> source_file_mapping =
253 fml::FileMapping::CreateReadOnly(Utf8FromPath(switches.source_file_name));
254 if (!source_file_mapping) {
255 std::cerr << "Could not open input file." << std::endl;
256 return false;
257 }
258
259 if (switches.iplr && !OutputIPLR(switches, source_file_mapping)) {
260 return false;
261 }
262
263 // Create at least one compiler to output the SL file, reflection data, and a
264 // depfile.
265
266 SourceOptions options = switches.CreateSourceOptions();
267
268 // Invoke the compiler and generate reflection data for a single shader.
269
270 Reflector::Options reflector_options =
271 CreateReflectorOptions(options, switches);
272
273 Compiler compiler(source_file_mapping, options, reflector_options);
274 if (!compiler.IsValid()) {
275 std::cerr << "Compilation failed." << std::endl;
276 std::cerr << compiler.GetErrorMessages() << std::endl;
277 return false;
278 }
279
280 auto spriv_file_name = std::filesystem::absolute(
281 std::filesystem::current_path() / switches.spirv_file_name);
282 if (!fml::WriteAtomically(*switches.working_directory,
283 Utf8FromPath(spriv_file_name).c_str(),
284 *compiler.GetSPIRVAssembly())) {
285 std::cerr << "Could not write file to " << switches.spirv_file_name
286 << std::endl;
287 return false;
288 }
289
290 if (!switches.iplr && !OutputSLFile(compiler, switches)) {
291 return false;
292 }
293
294 if (!OutputReflectionData(compiler, switches, options)) {
295 return false;
296 }
297
298 if (!OutputDepfile(compiler, switches)) {
299 return false;
300 }
301
302 return true;
303 }
304
305 } // namespace compiler
306 } // namespace impeller
307
308 int main(int argc, char const* argv[]) {
309 return impeller::compiler::Main(
310 fml::CommandLineFromPlatformOrArgcArgv(argc, argv))
311 ? EXIT_SUCCESS
312 : EXIT_FAILURE;
313 }
impeller::compiler::Compiler
Definition: compiler.h:24
impeller::compiler::Compiler::GetSPIRVAssembly
std::shared_ptr< fml::Mapping > GetSPIRVAssembly() const
Definition: compiler.cc:502
impeller::compiler::Compiler::GetReflector
const Reflector * GetReflector() const
Definition: compiler.cc:563
impeller::compiler::Compiler::CreateDepfileContents
std::unique_ptr< fml::Mapping > CreateDepfileContents(std::initializer_list< std::string > targets) const
Definition: compiler.cc:548
impeller::compiler::Compiler::IsValid
bool IsValid() const
Definition: compiler.cc:510
impeller::compiler::Compiler::GetSLShaderSource
std::shared_ptr< fml::Mapping > GetSLShaderSource() const
Definition: compiler.cc:506
impeller::compiler::Compiler::GetErrorMessages
std::string GetErrorMessages() const
Definition: compiler.cc:520
impeller::compiler::Reflector::GetReflectionJSON
std::shared_ptr< fml::Mapping > GetReflectionJSON() const
Definition: reflector.cc:110
impeller::compiler::Reflector::GetReflectionCC
std::shared_ptr< fml::Mapping > GetReflectionCC() const
Definition: reflector.cc:127
impeller::compiler::Reflector::GetRuntimeStageShaderData
std::shared_ptr< RuntimeStageData::Shader > GetRuntimeStageShaderData() const
Definition: reflector.cc:131
impeller::compiler::Reflector::GetReflectionHeader
std::shared_ptr< fml::Mapping > GetReflectionHeader() const
Definition: reflector.cc:123
impeller::compiler::RuntimeStageData
Definition: runtime_stage_data.h:20
impeller::compiler::RuntimeStageData::CreateMapping
std::shared_ptr< fml::Mapping > CreateMapping() const
Definition: runtime_stage_data.cc:411
impeller::compiler::RuntimeStageData::AddShader
void AddShader(const std::shared_ptr< Shader > &data)
Definition: runtime_stage_data.cc:27
impeller::compiler::RuntimeStageData::CreateJsonMapping
std::shared_ptr< fml::Mapping > CreateJsonMapping() const
Definition: runtime_stage_data.cc:214
impeller::compiler::Switches
Definition: switches.h:22
impeller::compiler::Switches::PlatformsToCompile
std::vector< TargetPlatform > PlatformsToCompile() const
A vector containing at least one valid platform.
Definition: switches.cc:305
impeller::compiler::Switches::reflection_cc_name
std::filesystem::path reflection_cc_name
Definition: switches.h:37
impeller::compiler::Switches::sl_file_name
std::filesystem::path sl_file_name
Definition: switches.h:31
impeller::compiler::Switches::shader_bundle
std::string shader_bundle
Definition: switches.h:33
impeller::compiler::Switches::working_directory
std::shared_ptr< fml::UniqueFD > working_directory
Definition: switches.h:24
impeller::compiler::Switches::CreateSourceOptions
SourceOptions CreateSourceOptions(std::optional< TargetPlatform > target_platform=std::nullopt) const
Definition: switches.cc:320
impeller::compiler::Switches::AreValid
bool AreValid(std::ostream &explain) const
Definition: switches.cc:252
impeller::compiler::Switches::PrintHelp
static void PrintHelp(std::ostream &stream)
Definition: switches.cc:42
impeller::compiler::Switches::iplr
bool iplr
Definition: switches.h:32
impeller::compiler::Switches::reflection_json_name
std::filesystem::path reflection_json_name
Definition: switches.h:35
impeller::compiler::Switches::spirv_file_name
std::filesystem::path spirv_file_name
Definition: switches.h:34
impeller::compiler::Switches::json_format
bool json_format
Definition: switches.h:40
impeller::compiler::Switches::depfile_path
std::filesystem::path depfile_path
Definition: switches.h:38
impeller::compiler::Switches::source_file_name
std::filesystem::path source_file_name
Definition: switches.h:26
impeller::compiler::Switches::reflection_header_name
std::filesystem::path reflection_header_name
Definition: switches.h:36
impeller::compiler::Switches::SelectDefaultTargetPlatform
TargetPlatform SelectDefaultTargetPlatform() const
Definition: switches.cc:312
switches.h
types.h
compiler.h
main
int main(int argc, char const *argv[])
Definition: impellerc_main.cc:308
impeller::compiler::Main
bool Main(const fml::CommandLine &command_line)
Definition: impellerc_main.cc:232
impeller::compiler::SetPermissiveAccess
bool SetPermissiveAccess(const std::filesystem::path &p)
Sets the file access mode of the file at path 'p' to 0644.
Definition: utilities.cc:16
impeller::compiler::InferShaderNameFromPath
std::string InferShaderNameFromPath(const std::filesystem::path &path)
Definition: utilities.cc:34
impeller::compiler::OutputDepfile
static bool OutputDepfile(const Compiler &compiler, const Switches &switches)
Definition: impellerc_main.cc:194
impeller::compiler::GenerateShaderBundle
bool GenerateShaderBundle(Switches &switches)
Parses the JSON shader bundle configuration and invokes the compiler multiple times to produce a shad...
Definition: shader_bundle.cc:212
impeller::compiler::CreateReflectorOptions
static Reflector::Options CreateReflectorOptions(const SourceOptions &options, const Switches &switches)
Definition: impellerc_main.cc:23
impeller::compiler::OutputReflectionData
static bool OutputReflectionData(const Compiler &compiler, const Switches &switches, const SourceOptions &options)
Definition: impellerc_main.cc:144
impeller::compiler::OutputIPLR
static bool OutputIPLR(const Switches &switches, const std::shared_ptr< fml::Mapping > &source_file_mapping)
Definition: impellerc_main.cc:56
impeller::compiler::Utf8FromPath
std::string Utf8FromPath(const std::filesystem::path &path)
Converts a native format path to a utf8 string.
Definition: utilities.cc:30
impeller::compiler::TargetPlatformBundlesSkSL
bool TargetPlatformBundlesSkSL(TargetPlatform platform)
Definition: types.cc:315
impeller::compiler::CompileSkSL
static std::shared_ptr< RuntimeStageData::Shader > CompileSkSL(std::shared_ptr< fml::Mapping > source_file_mapping, const Switches &switches)
Definition: impellerc_main.cc:37
impeller::compiler::TargetPlatformNeedsReflection
bool TargetPlatformNeedsReflection(TargetPlatform platform)
Definition: types.cc:130
impeller::compiler::TargetPlatform::kRuntimeStageMetal
@ kRuntimeStageMetal
impeller::compiler::TargetPlatform::kOpenGLES
@ kOpenGLES
impeller::compiler::TargetPlatform::kUnknown
@ kUnknown
impeller::compiler::TargetPlatform::kRuntimeStageVulkan
@ kRuntimeStageVulkan
impeller::compiler::TargetPlatform::kRuntimeStageGLES3
@ kRuntimeStageGLES3
impeller::compiler::TargetPlatform::kVulkan
@ kVulkan
impeller::compiler::TargetPlatform::kMetalDesktop
@ kMetalDesktop
impeller::compiler::TargetPlatform::kMetalIOS
@ kMetalIOS
impeller::compiler::TargetPlatform::kSkSL
@ kSkSL
impeller::compiler::TargetPlatform::kOpenGLDesktop
@ kOpenGLDesktop
impeller::compiler::TargetPlatform::kRuntimeStageGLES
@ kRuntimeStageGLES
impeller::compiler::OutputSLFile
static bool OutputSLFile(const Compiler &compiler, const Switches &switches)
Definition: impellerc_main.cc:126
impeller
Definition: allocation.cc:12
runtime_stage_data.h
shader_bundle.h
source_options.h
impeller::compiler::Reflector::Options
Definition: reflector.h:162
impeller::compiler::Reflector::Options::target_platform
TargetPlatform target_platform
Definition: reflector.h:163
impeller::compiler::Reflector::Options::entry_point_name
std::string entry_point_name
Definition: reflector.h:164
impeller::compiler::Reflector::Options::shader_name
std::string shader_name
Definition: reflector.h:165
impeller::compiler::Reflector::Options::header_file_name
std::string header_file_name
Definition: reflector.h:166
impeller::compiler::SourceOptions
Definition: source_options.h:20
impeller::compiler::SourceOptions::entry_point_name
std::string entry_point_name
Definition: source_options.h:27
impeller::compiler::SourceOptions::target_platform
TargetPlatform target_platform
Definition: source_options.h:22
utilities.h