Flutter Engine
The Flutter Engine
switches.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
6
7#include <algorithm>
8#include <cctype>
9#include <filesystem>
10#include <map>
11
12#include "flutter/fml/file.h"
13#include "fml/command_line.h"
16
17namespace impeller {
18namespace compiler {
19
20static const std::map<std::string, TargetPlatform> kKnownPlatforms = {
21 {"metal-desktop", TargetPlatform::kMetalDesktop},
22 {"metal-ios", TargetPlatform::kMetalIOS},
23 {"vulkan", TargetPlatform::kVulkan},
24 {"opengl-es", TargetPlatform::kOpenGLES},
25 {"opengl-desktop", TargetPlatform::kOpenGLDesktop},
26};
27
28static const std::map<std::string, TargetPlatform> kKnownRuntimeStages = {
29 {"sksl", TargetPlatform::kSkSL},
30 {"runtime-stage-metal", TargetPlatform::kRuntimeStageMetal},
31 {"runtime-stage-gles", TargetPlatform::kRuntimeStageGLES},
32 {"runtime-stage-vulkan", TargetPlatform::kRuntimeStageVulkan},
33};
34
35static const std::map<std::string, SourceType> kKnownSourceTypes = {
39};
40
41void Switches::PrintHelp(std::ostream& stream) {
42 // clang-format off
43 const std::string optional_prefix = "[optional] ";
44 const std::string optional_multiple_prefix = "[optional,multiple] ";
45 // clang-format on
46
47 stream << std::endl;
48 stream << "ImpellerC is an offline shader processor and reflection engine."
49 << std::endl;
50 stream << "---------------------------------------------------------------"
51 << std::endl;
52 stream << "Expected invocation is:" << std::endl << std::endl;
53 stream << "./impellerc <One platform or multiple runtime stages> "
54 "--input=<source_file> --sl=<sl_output_file> <optional arguments>"
55 << std::endl
56 << std::endl;
57
58 stream << "Valid platforms are:" << std::endl << std::endl;
59 stream << "One of [";
60 for (const auto& platform : kKnownPlatforms) {
61 stream << " --" << platform.first;
62 }
63 stream << " ]" << std::endl << std::endl;
64
65 stream << "Valid runtime stages are:" << std::endl << std::endl;
66 stream << "At least one of [";
67 for (const auto& platform : kKnownRuntimeStages) {
68 stream << " --" << platform.first;
69 }
70 stream << " ]" << std::endl << std::endl;
71
72 stream << "Optional arguments:" << std::endl << std::endl;
73 stream << optional_prefix
74 << "--spirv=<spirv_output_file> (ignored for --shader-bundle)"
75 << std::endl;
76 stream << optional_prefix << "--input-type={";
77 for (const auto& source_type : kKnownSourceTypes) {
78 stream << source_type.first << ", ";
79 }
80 stream << "}" << std::endl;
81 stream << optional_prefix << "--source-language=glsl|hlsl (default: glsl)"
82 << std::endl;
83 stream << optional_prefix
84 << "--entry-point=<entry_point_name> (default: main; "
85 "ignored for glsl)"
86 << std::endl;
87 stream << optional_prefix
88 << "--iplr (causes --sl file to be emitted in "
89 "iplr format)"
90 << std::endl;
91 stream << optional_prefix
92 << "--shader-bundle=<bundle_spec> (causes --sl "
93 "file to be "
94 "emitted in Flutter GPU's shader bundle format)"
95 << std::endl;
96 stream << optional_prefix << "--reflection-json=<reflection_json_file>"
97 << std::endl;
98 stream << optional_prefix << "--reflection-header=<reflection_header_file>"
99 << std::endl;
100 stream << optional_prefix << "--reflection-cc=<reflection_cc_file>"
101 << std::endl;
102 stream << optional_multiple_prefix << "--include=<include_directory>"
103 << std::endl;
104 stream << optional_multiple_prefix << "--define=<define>" << std::endl;
105 stream << optional_prefix << "--depfile=<depfile_path>" << std::endl;
106 stream << optional_prefix << "--gles-language-version=<number>" << std::endl;
107 stream << optional_prefix << "--json" << std::endl;
108 stream << optional_prefix
109 << "--use-half-textures (force openGL semantics when "
110 "targeting metal)"
111 << std::endl;
112 stream << optional_prefix << "--require-framebuffer-fetch" << std::endl;
113}
114
115Switches::Switches() = default;
116
117Switches::~Switches() = default;
118
120 const fml::CommandLine& command_line) {
122 for (const auto& platform : kKnownPlatforms) {
123 if (command_line.HasOption(platform.first)) {
124 // If the platform has already been determined, the caller may have
125 // specified multiple platforms. This is an error and only one must be
126 // selected.
129 }
130 target = platform.second;
131 // Keep going to detect duplicates.
132 }
133 }
134 return target;
135}
136
137static std::vector<TargetPlatform> RuntimeStagesFromCommandLine(
138 const fml::CommandLine& command_line) {
139 std::vector<TargetPlatform> stages;
140 for (const auto& platform : kKnownRuntimeStages) {
141 if (command_line.HasOption(platform.first)) {
142 stages.push_back(platform.second);
143 }
144 }
145 return stages;
146}
147
149 const fml::CommandLine& command_line) {
150 auto source_type_option =
151 command_line.GetOptionValueWithDefault("input-type", "");
152 auto source_type_search = kKnownSourceTypes.find(source_type_option);
153 if (source_type_search == kKnownSourceTypes.end()) {
155 }
156 return source_type_search->second;
157}
158
160 : working_directory(std::make_shared<fml::UniqueFD>(fml::OpenDirectory(
161 Utf8FromPath(std::filesystem::current_path()).c_str(),
162 false, // create if necessary,
163 fml::FilePermission::kRead))),
164 source_file_name(command_line.GetOptionValueWithDefault("input", "")),
165 input_type(SourceTypeFromCommandLine(command_line)),
166 sl_file_name(command_line.GetOptionValueWithDefault("sl", "")),
167 iplr(command_line.HasOption("iplr")),
168 shader_bundle(
169 command_line.GetOptionValueWithDefault("shader-bundle", "")),
170 spirv_file_name(command_line.GetOptionValueWithDefault("spirv", "")),
171 reflection_json_name(
172 command_line.GetOptionValueWithDefault("reflection-json", "")),
173 reflection_header_name(
174 command_line.GetOptionValueWithDefault("reflection-header", "")),
175 reflection_cc_name(
176 command_line.GetOptionValueWithDefault("reflection-cc", "")),
177 depfile_path(command_line.GetOptionValueWithDefault("depfile", "")),
178 json_format(command_line.HasOption("json")),
179 gles_language_version(
180 stoi(command_line.GetOptionValueWithDefault("gles-language-version",
181 "0"))),
182 metal_version(
183 command_line.GetOptionValueWithDefault("metal-version", "1.2")),
184 entry_point(
185 command_line.GetOptionValueWithDefault("entry-point", "main")),
186 use_half_textures(command_line.HasOption("use-half-textures")),
187 require_framebuffer_fetch(
188 command_line.HasOption("require-framebuffer-fetch")),
189 target_platform_(TargetPlatformFromCommandLine(command_line)),
190 runtime_stages_(RuntimeStagesFromCommandLine(command_line)) {
191 auto language = ToLowerCase(
192 command_line.GetOptionValueWithDefault("source-language", "glsl"));
193
195
196 if (!working_directory || !working_directory->is_valid()) {
197 return;
198 }
199
200 for (const auto& include_dir_path : command_line.GetOptionValues("include")) {
201 if (!include_dir_path.data()) {
202 continue;
203 }
204
205 // fml::OpenDirectoryReadOnly for Windows doesn't handle relative paths
206 // beginning with `../` well, so we build an absolute path.
207
208 // Get the current working directory as a utf8 encoded string.
209 // Note that the `include_dir_path` is already utf8 encoded, and so we
210 // mustn't attempt to double-convert it to utf8 lest multi-byte characters
211 // will become mangled.
212 std::filesystem::path include_dir_absolute;
213 if (std::filesystem::path(include_dir_path).is_absolute()) {
214 include_dir_absolute = std::filesystem::path(include_dir_path);
215 } else {
216 auto cwd = Utf8FromPath(std::filesystem::current_path());
217 include_dir_absolute = std::filesystem::absolute(
218 std::filesystem::path(cwd) / include_dir_path);
219 }
220
221 auto dir = std::make_shared<fml::UniqueFD>(fml::OpenDirectoryReadOnly(
222 *working_directory, include_dir_absolute.string().c_str()));
223 if (!dir || !dir->is_valid()) {
224 continue;
225 }
226
227 IncludeDir dir_entry;
228 dir_entry.name = include_dir_path;
229 dir_entry.dir = std::move(dir);
230
231 include_directories.emplace_back(std::move(dir_entry));
232 }
233
234 for (const auto& define : command_line.GetOptionValues("define")) {
235 defines.emplace_back(define);
236 }
237}
238
239bool Switches::AreValid(std::ostream& explain) const {
240 // When producing a shader bundle, all flags related to single shader inputs
241 // and outputs such as `--input` and `--spirv-file-name` are ignored. Instead,
242 // input files are read from the shader bundle spec and a single flatbuffer
243 // containing all compiled shaders and reflection state is output to `--sl`.
244 const bool shader_bundle_mode = !shader_bundle.empty();
245
246 bool valid = true;
247 if (target_platform_ == TargetPlatform::kUnknown && runtime_stages_.empty() &&
248 !shader_bundle_mode) {
249 explain << "Either a target platform was not specified, or no runtime "
250 "stages were specified."
251 << std::endl;
252 valid = false;
253 }
254
255 if (source_language == SourceLanguage::kUnknown && !shader_bundle_mode) {
256 explain << "Invalid source language type." << std::endl;
257 valid = false;
258 }
259
260 if (!working_directory || !working_directory->is_valid()) {
261 explain << "Could not open the working directory: \""
262 << Utf8FromPath(std::filesystem::current_path()).c_str() << "\""
263 << std::endl;
264 valid = false;
265 }
266
267 if (source_file_name.empty() && !shader_bundle_mode) {
268 explain << "Input file name was empty." << std::endl;
269 valid = false;
270 }
271
272 if (sl_file_name.empty()) {
273 explain << "Target shading language file name was empty." << std::endl;
274 valid = false;
275 }
276
277 if (spirv_file_name.empty() && !shader_bundle_mode) {
278 explain << "Spirv file name was empty." << std::endl;
279 valid = false;
280 }
281
282 if (iplr && shader_bundle_mode) {
283 explain << "--iplr and --shader-bundle flag cannot be specified at the "
284 "same time"
285 << std::endl;
286 valid = false;
287 }
288
289 return valid;
290}
291
292std::vector<TargetPlatform> Switches::PlatformsToCompile() const {
293 if (target_platform_ == TargetPlatform::kUnknown) {
294 return runtime_stages_;
295 }
296 return {target_platform_};
297}
298
300 if (target_platform_ == TargetPlatform::kUnknown &&
301 !runtime_stages_.empty()) {
302 return runtime_stages_.front();
303 }
304 return target_platform_;
305}
306
308 std::optional<TargetPlatform> target_platform) const {
310 options.target_platform =
311 target_platform.value_or(SelectDefaultTargetPlatform());
312 options.source_language = source_language;
315 } else {
316 options.type = input_type;
317 }
318 options.working_directory = working_directory;
319 options.file_name = source_file_name;
320 options.include_dirs = include_directories;
321 options.defines = defines;
323 source_file_name, options.type, options.source_language, entry_point);
324 options.json_format = json_format;
325 options.gles_language_version = gles_language_version;
326 options.metal_version = metal_version;
327 options.use_half_textures = use_half_textures;
328 options.require_framebuffer_fetch = require_framebuffer_fetch;
329 return options;
330}
331
332} // namespace compiler
333} // namespace impeller
const char * options
std::vector< std::string_view > GetOptionValues(std::string_view name) const
Definition: command_line.cc:61
std::string GetOptionValueWithDefault(std::string_view name, std::string_view default_value) const
Definition: command_line.cc:72
bool HasOption(std::string_view name, size_t *index=nullptr) const
Definition: command_line.cc:40
std::vector< TargetPlatform > PlatformsToCompile() const
A vector containing at least one valid platform.
Definition: switches.cc:292
SourceLanguage source_language
Definition: switches.h:40
std::vector< std::string > defines
Definition: switches.h:38
std::shared_ptr< fml::UniqueFD > working_directory
Definition: switches.h:23
SourceOptions CreateSourceOptions(std::optional< TargetPlatform > target_platform=std::nullopt) const
Definition: switches.cc:307
std::string spirv_file_name
Definition: switches.h:33
bool AreValid(std::ostream &explain) const
Definition: switches.cc:239
static void PrintHelp(std::ostream &stream)
Definition: switches.cc:41
std::string source_file_name
Definition: switches.h:25
std::vector< IncludeDir > include_directories
Definition: switches.h:24
TargetPlatform SelectDefaultTargetPlatform() const
Definition: switches.cc:299
uint32_t * target
bool stoi(std::string_view s, SKSL_INT *value)
Definition: SkSLString.cpp:66
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
Definition: ascii_trie.cc:9
fml::UniqueFD OpenDirectoryReadOnly(const fml::UniqueFD &base_directory, const char *path)
Definition: file.cc:97
fml::UniqueFD OpenDirectory(const char *path, bool create_if_necessary, FilePermission permission)
Definition: file_posix.cc:97
UniqueObject< int, internal::os_unix::UniqueFDTraits > UniqueFD
Definition: unique_fd.h:100
FilePermission
Definition: file.h:24
std::string ToLowerCase(std::string_view string)
Definition: utilities.cc:62
static std::vector< TargetPlatform > RuntimeStagesFromCommandLine(const fml::CommandLine &command_line)
Definition: switches.cc:137
static const std::map< std::string, TargetPlatform > kKnownPlatforms
Definition: switches.cc:20
SourceType SourceTypeFromFileName(const std::string &file_name)
Definition: types.cc:30
std::string EntryPointFunctionNameFromSourceName(const std::string &file_name, SourceType type, SourceLanguage source_language, const std::string &entry_point_name)
Definition: types.cc:111
static const std::map< std::string, TargetPlatform > kKnownRuntimeStages
Definition: switches.cc:28
std::string Utf8FromPath(const std::filesystem::path &path)
Converts a native format path to a utf8 string.
Definition: utilities.cc:30
static TargetPlatform TargetPlatformFromCommandLine(const fml::CommandLine &command_line)
Definition: switches.cc:119
SourceLanguage ToSourceLanguage(const std::string &source_language)
Definition: types.cc:64
static const std::map< std::string, SourceType > kKnownSourceTypes
Definition: switches.cc:35
static SourceType SourceTypeFromCommandLine(const fml::CommandLine &command_line)
Definition: switches.cc:148
Definition: ref_ptr.h:256
std::shared_ptr< fml::UniqueFD > dir
Definition: include_dir.h:17