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/macros.h"
12 #include "flutter/fml/mapping.h"
13 #include "impeller/base/strings.h"
19 #include "third_party/shaderc/libshaderc/include/shaderc/shaderc.hpp"
20 
21 namespace impeller {
22 namespace compiler {
23 
24 // Sets the file access mode of the file at path 'p' to 0644.
25 static bool SetPermissiveAccess(const std::filesystem::path& p) {
26  auto permissions =
27  std::filesystem::perms::owner_read | std::filesystem::perms::owner_write |
28  std::filesystem::perms::group_read | std::filesystem::perms::others_read;
29  std::error_code error;
30  std::filesystem::permissions(p, permissions, error);
31  if (error) {
32  std::cerr << "Failed to set access on file '" << p
33  << "': " << error.message() << std::endl;
34  return false;
35  }
36  return true;
37 }
38 
39 bool Main(const fml::CommandLine& command_line) {
40  fml::InstallCrashHandler();
41  if (command_line.HasOption("help")) {
42  Switches::PrintHelp(std::cout);
43  return true;
44  }
45 
46  Switches switches(command_line);
47  if (!switches.AreValid(std::cerr)) {
48  std::cerr << "Invalid flags specified." << std::endl;
49  Switches::PrintHelp(std::cerr);
50  return false;
51  }
52 
53  std::shared_ptr<fml::FileMapping> source_file_mapping =
54  fml::FileMapping::CreateReadOnly(switches.source_file_name);
55  if (!source_file_mapping) {
56  std::cerr << "Could not open input file." << std::endl;
57  return false;
58  }
59 
60  SourceOptions options;
61  options.target_platform = switches.target_platform;
62  options.source_language = switches.source_language;
63  if (switches.input_type == SourceType::kUnknown) {
64  options.type = SourceTypeFromFileName(switches.source_file_name);
65  } else {
66  options.type = switches.input_type;
67  }
68  options.working_directory = switches.working_directory;
69  options.file_name = switches.source_file_name;
70  options.include_dirs = switches.include_directories;
71  options.defines = switches.defines;
73  switches.source_file_name, options.type, options.source_language,
74  switches.entry_point);
75  options.json_format = switches.json_format;
77  options.metal_version = switches.metal_version;
78  options.use_half_textures = switches.use_half_textures;
79 
80  Reflector::Options reflector_options;
81  reflector_options.target_platform = switches.target_platform;
82  reflector_options.entry_point_name = options.entry_point_name;
83  reflector_options.shader_name =
85  reflector_options.header_file_name = Utf8FromPath(
86  std::filesystem::path{switches.reflection_header_name}.filename());
87 
88  // Generate SkSL if needed.
89  std::shared_ptr<fml::Mapping> sksl_mapping;
90  if (switches.iplr && TargetPlatformBundlesSkSL(switches.target_platform)) {
91  SourceOptions sksl_options = options;
93 
94  Reflector::Options sksl_reflector_options = reflector_options;
95  sksl_reflector_options.target_platform = TargetPlatform::kSkSL;
96 
97  Compiler sksl_compiler =
98  Compiler(source_file_mapping, sksl_options, sksl_reflector_options);
99  if (!sksl_compiler.IsValid()) {
100  std::cerr << "Compilation to SkSL failed." << std::endl;
101  std::cerr << sksl_compiler.GetErrorMessages() << std::endl;
102  return false;
103  }
104  sksl_mapping = sksl_compiler.GetSLShaderSource();
105  }
106 
107  Compiler compiler(source_file_mapping, options, reflector_options);
108  if (!compiler.IsValid()) {
109  std::cerr << "Compilation failed." << std::endl;
110  std::cerr << compiler.GetErrorMessages() << std::endl;
111  return false;
112  }
113 
114  auto spriv_file_name = std::filesystem::absolute(
115  std::filesystem::current_path() / switches.spirv_file_name);
116  if (!fml::WriteAtomically(*switches.working_directory,
117  Utf8FromPath(spriv_file_name).c_str(),
118  *compiler.GetSPIRVAssembly())) {
119  std::cerr << "Could not write file to " << switches.spirv_file_name
120  << std::endl;
121  return false;
122  }
123 
124  auto sl_file_name = std::filesystem::absolute(
125  std::filesystem::current_path() / switches.sl_file_name);
126  if (switches.iplr) {
127  auto reflector = compiler.GetReflector();
128  if (reflector == nullptr) {
129  std::cerr << "Could not create reflector." << std::endl;
130  return false;
131  }
132  auto stage_data = reflector->GetRuntimeStageData();
133  if (!stage_data) {
134  std::cerr << "Runtime stage information was nil." << std::endl;
135  return false;
136  }
137  if (sksl_mapping) {
138  stage_data->SetSkSLData(sksl_mapping);
139  }
140  auto stage_data_mapping = options.json_format
141  ? stage_data->CreateJsonMapping()
142  : stage_data->CreateMapping();
143  if (!stage_data_mapping) {
144  std::cerr << "Runtime stage data could not be created." << std::endl;
145  return false;
146  }
147  if (!fml::WriteAtomically(*switches.working_directory, //
148  Utf8FromPath(sl_file_name).c_str(), //
149  *stage_data_mapping //
150  )) {
151  std::cerr << "Could not write file to " << switches.sl_file_name
152  << std::endl;
153  return false;
154  }
155  // Tools that consume the runtime stage data expect the access mode to
156  // be 0644.
157  if (!SetPermissiveAccess(sl_file_name)) {
158  return false;
159  }
160  } else {
161  if (!fml::WriteAtomically(*switches.working_directory,
162  Utf8FromPath(sl_file_name).c_str(),
163  *compiler.GetSLShaderSource())) {
164  std::cerr << "Could not write file to " << switches.sl_file_name
165  << std::endl;
166  return false;
167  }
168  }
169 
171  if (!switches.reflection_json_name.empty()) {
172  auto reflection_json_name = std::filesystem::absolute(
173  std::filesystem::current_path() / switches.reflection_json_name);
174  if (!fml::WriteAtomically(
175  *switches.working_directory,
176  Utf8FromPath(reflection_json_name).c_str(),
177  *compiler.GetReflector()->GetReflectionJSON())) {
178  std::cerr << "Could not write reflection json to "
179  << switches.reflection_json_name << std::endl;
180  return false;
181  }
182  }
183 
184  if (!switches.reflection_header_name.empty()) {
185  auto reflection_header_name =
186  std::filesystem::absolute(std::filesystem::current_path() /
187  switches.reflection_header_name.c_str());
188  if (!fml::WriteAtomically(
189  *switches.working_directory,
190  Utf8FromPath(reflection_header_name).c_str(),
191  *compiler.GetReflector()->GetReflectionHeader())) {
192  std::cerr << "Could not write reflection header to "
193  << switches.reflection_header_name << std::endl;
194  return false;
195  }
196  }
197 
198  if (!switches.reflection_cc_name.empty()) {
199  auto reflection_cc_name =
200  std::filesystem::absolute(std::filesystem::current_path() /
201  switches.reflection_cc_name.c_str());
202  if (!fml::WriteAtomically(*switches.working_directory,
203  Utf8FromPath(reflection_cc_name).c_str(),
204  *compiler.GetReflector()->GetReflectionCC())) {
205  std::cerr << "Could not write reflection CC to "
206  << switches.reflection_cc_name << std::endl;
207  return false;
208  }
209  }
210  }
211 
212  if (!switches.depfile_path.empty()) {
213  std::string result_file;
214  switch (switches.target_platform) {
224  result_file = switches.sl_file_name;
225  break;
227  result_file = switches.spirv_file_name;
228  break;
229  }
230  auto depfile_path = std::filesystem::absolute(
231  std::filesystem::current_path() / switches.depfile_path.c_str());
232  if (!fml::WriteAtomically(*switches.working_directory,
233  Utf8FromPath(depfile_path).c_str(),
234  *compiler.CreateDepfileContents({result_file}))) {
235  std::cerr << "Could not write depfile to " << switches.depfile_path
236  << std::endl;
237  return false;
238  }
239  }
240 
241  return true;
242 }
243 
244 } // namespace compiler
245 } // namespace impeller
246 
247 int main(int argc, char const* argv[]) {
249  fml::CommandLineFromPlatformOrArgcArgv(argc, argv))
250  ? EXIT_SUCCESS
251  : EXIT_FAILURE;
252 }
impeller::compiler::Switches::gles_language_version
uint32_t gles_language_version
Definition: switches.h:36
impeller::compiler::Compiler
Definition: compiler.h:24
impeller::compiler::Switches::defines
std::vector< std::string > defines
Definition: switches.h:33
impeller::compiler::Switches::entry_point
std::string entry_point
Definition: switches.h:38
impeller::compiler::SourceOptions::type
SourceType type
Definition: source_options.h:20
impeller::compiler::Compiler::CreateDepfileContents
std::unique_ptr< fml::Mapping > CreateDepfileContents(std::initializer_list< std::string > targets) const
Definition: compiler.cc:467
impeller::compiler::Switches
Definition: switches.h:20
impeller::compiler::Switches::target_platform
TargetPlatform target_platform
Definition: switches.h:21
impeller::compiler::SourceOptions::include_dirs
std::vector< IncludeDir > include_dirs
Definition: source_options.h:24
impeller::compiler::SourceType::kUnknown
@ kUnknown
impeller::compiler::Switches::metal_version
std::string metal_version
Definition: switches.h:37
impeller::compiler::TargetPlatform::kMetalDesktop
@ kMetalDesktop
impeller::compiler::Switches::working_directory
std::shared_ptr< fml::UniqueFD > working_directory
Definition: switches.h:22
impeller::compiler::SourceOptions::metal_version
std::string metal_version
Definition: source_options.h:30
impeller::compiler::SourceOptions
Definition: source_options.h:19
impeller::compiler::Switches::include_directories
std::vector< IncludeDir > include_directories
Definition: switches.h:23
impeller::compiler::SourceOptions::use_half_textures
bool use_half_textures
Whether half-precision textures should be supported, requiring opengl semantics. Only used on metal t...
Definition: source_options.h:34
impeller::compiler::TargetPlatformNeedsReflection
bool TargetPlatformNeedsReflection(TargetPlatform platform)
Definition: types.cc:126
impeller::compiler::InferShaderNameFromPath
std::string InferShaderNameFromPath(std::string_view path)
Definition: utilities.cc:18
impeller::compiler::SourceOptions::json_format
bool json_format
Definition: source_options.h:29
impeller::compiler::TargetPlatform::kMetalIOS
@ kMetalIOS
impeller::compiler::Reflector::GetReflectionCC
std::shared_ptr< fml::Mapping > GetReflectionCC() const
Definition: reflector.cc:175
switches.h
impeller::compiler::Reflector::Options::header_file_name
std::string header_file_name
Definition: reflector.h:55
impeller::compiler::Switches::reflection_cc_name
std::string reflection_cc_name
Definition: switches.h:31
impeller::compiler::Reflector::GetReflectionHeader
std::shared_ptr< fml::Mapping > GetReflectionHeader() const
Definition: reflector.cc:171
impeller::compiler::Switches::AreValid
bool AreValid(std::ostream &explain) const
Definition: switches.cc:193
impeller::compiler::Reflector::Options::target_platform
TargetPlatform target_platform
Definition: reflector.h:52
impeller::compiler::Switches::input_type
SourceType input_type
Definition: switches.h:25
impeller::compiler::Main
bool Main(const fml::CommandLine &command_line)
Definition: impellerc_main.cc:39
impeller::compiler::SourceOptions::source_language
SourceLanguage source_language
Definition: source_options.h:22
impeller::compiler::Switches::source_file_name
std::string source_file_name
Definition: switches.h:24
impeller::compiler::TargetPlatform::kVulkan
@ kVulkan
impeller::compiler::Reflector::Options::shader_name
std::string shader_name
Definition: reflector.h:54
impeller::compiler::SourceOptions::entry_point_name
std::string entry_point_name
Definition: source_options.h:26
impeller::compiler::Compiler::GetErrorMessages
std::string GetErrorMessages() const
Definition: compiler.cc:439
impeller::compiler::TargetPlatform::kRuntimeStageVulkan
@ kRuntimeStageVulkan
impeller::compiler::Compiler::GetSPIRVAssembly
std::shared_ptr< fml::Mapping > GetSPIRVAssembly() const
Definition: compiler.cc:421
impeller::compiler::Switches::spirv_file_name
std::string spirv_file_name
Definition: switches.h:28
impeller::compiler::SourceOptions::gles_language_version
uint32_t gles_language_version
Definition: source_options.h:27
impeller::compiler::Switches::source_language
SourceLanguage source_language
Definition: switches.h:35
source_options.h
impeller::compiler::EntryPointFunctionNameFromSourceName
std::string EntryPointFunctionNameFromSourceName(const std::string &file_name, SourceType type, SourceLanguage source_language, const std::string &entry_point_name)
Definition: types.cc:90
impeller::compiler::Compiler::GetReflector
const Reflector * GetReflector() const
Definition: compiler.cc:482
impeller::compiler::SourceOptions::file_name
std::string file_name
Definition: source_options.h:25
impeller::compiler::Reflector::Options
Definition: reflector.h:51
impeller::compiler::SetPermissiveAccess
static bool SetPermissiveAccess(const std::filesystem::path &p)
Definition: impellerc_main.cc:25
compiler.h
impeller::compiler::Reflector::GetRuntimeStageData
std::shared_ptr< RuntimeStageData > GetRuntimeStageData() const
Definition: reflector.cc:179
utilities.h
strings.h
impeller::compiler::SourceOptions::working_directory
std::shared_ptr< fml::UniqueFD > working_directory
Definition: source_options.h:23
impeller::compiler::SourceTypeFromFileName
SourceType SourceTypeFromFileName(const std::string &file_name)
Definition: types.cc:29
impeller::compiler::SourceOptions::target_platform
TargetPlatform target_platform
Definition: source_options.h:21
impeller::compiler::Compiler::IsValid
bool IsValid() const
Definition: compiler.cc:429
impeller::compiler::Switches::depfile_path
std::string depfile_path
Definition: switches.h:32
impeller::compiler::TargetPlatform::kOpenGLDesktop
@ kOpenGLDesktop
impeller::compiler::SourceOptions::defines
std::vector< std::string > defines
Definition: source_options.h:28
impeller::compiler::Switches::sl_file_name
std::string sl_file_name
Definition: switches.h:26
impeller::compiler::TargetPlatform::kUnknown
@ kUnknown
impeller::compiler::Switches::reflection_json_name
std::string reflection_json_name
Definition: switches.h:29
impeller::compiler::TargetPlatform::kOpenGLES
@ kOpenGLES
impeller::compiler::Compiler::GetSLShaderSource
std::shared_ptr< fml::Mapping > GetSLShaderSource() const
Definition: compiler.cc:425
main
int main(int argc, char const *argv[])
Definition: impellerc_main.cc:247
impeller::compiler::Utf8FromPath
std::string Utf8FromPath(const std::filesystem::path &path)
Converts a native format path to a utf8 string.
Definition: utilities.cc:14
impeller::compiler::TargetPlatform::kRuntimeStageMetal
@ kRuntimeStageMetal
impeller::compiler::Switches::use_half_textures
bool use_half_textures
Definition: switches.h:39
impeller::compiler::Switches::iplr
bool iplr
Definition: switches.h:27
impeller::compiler::Switches::json_format
bool json_format
Definition: switches.h:34
impeller::compiler::Reflector::GetReflectionJSON
std::shared_ptr< fml::Mapping > GetReflectionJSON() const
Definition: reflector.cc:158
impeller::compiler::Reflector::Options::entry_point_name
std::string entry_point_name
Definition: reflector.h:53
impeller::compiler::Switches::reflection_header_name
std::string reflection_header_name
Definition: switches.h:30
impeller::compiler::TargetPlatformBundlesSkSL
bool TargetPlatformBundlesSkSL(TargetPlatform platform)
Definition: types.cc:317
impeller
Definition: aiks_context.cc:10
impeller::compiler::Switches::PrintHelp
static void PrintHelp(std::ostream &stream)
Definition: switches.cc:39
types.h
impeller::compiler::TargetPlatform::kSkSL
@ kSkSL
impeller::compiler::TargetPlatform::kRuntimeStageGLES
@ kRuntimeStageGLES