Flutter Engine
The Flutter Engine
shader_bundle.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
10
13#include "impeller/shader_bundle/shader_bundle_flatbuffers.h"
14#include "third_party/json/include/nlohmann/json.hpp"
15
16namespace impeller {
17namespace compiler {
18
19std::optional<ShaderBundleConfig> ParseShaderBundleConfig(
20 const std::string& bundle_config_json,
21 std::ostream& error_stream) {
22 auto json = nlohmann::json::parse(bundle_config_json, nullptr, false);
23 if (json.is_discarded() || !json.is_object()) {
24 error_stream << "The shader bundle is not a valid JSON object."
25 << std::endl;
26 return std::nullopt;
27 }
28
29 ShaderBundleConfig bundle;
30 for (auto& [shader_name, shader_value] : json.items()) {
31 if (bundle.find(shader_name) != bundle.end()) {
32 error_stream << "Duplicate shader \"" << shader_name << "\"."
33 << std::endl;
34 return std::nullopt;
35 }
36 if (!shader_value.is_object()) {
37 error_stream << "Invalid shader entry \"" << shader_name
38 << "\": Entry is not a JSON object." << std::endl;
39 return std::nullopt;
40 }
41
42 ShaderConfig shader;
43
44 if (!shader_value.contains("file")) {
45 error_stream << "Invalid shader entry \"" << shader_name
46 << "\": Missing required \"file\" field." << std::endl;
47 return std::nullopt;
48 }
49 shader.source_file_name = shader_value["file"];
50
51 if (!shader_value.contains("type")) {
52 error_stream << "Invalid shader entry \"" << shader_name
53 << "\": Missing required \"type\" field." << std::endl;
54 return std::nullopt;
55 }
56 shader.type = SourceTypeFromString(shader_value["type"]);
57 if (shader.type == SourceType::kUnknown) {
58 error_stream << "Invalid shader entry \"" << shader_name
59 << "\": Shader type " << shader_value["type"]
60 << " is unknown." << std::endl;
61 return std::nullopt;
62 }
63
64 shader.language = shader_value.contains("language")
65 ? ToSourceLanguage(shader_value["language"])
67 if (shader.language == SourceLanguage::kUnknown) {
68 error_stream << "Invalid shader entry \"" << shader_name
69 << "\": Unknown language type " << shader_value["language"]
70 << "." << std::endl;
71 return std::nullopt;
72 }
73
74 shader.entry_point = shader_value.contains("entry_point")
75 ? shader_value["entry_point"]
76 : "main";
77
78 bundle[shader_name] = shader;
79 }
80
81 return bundle;
82}
83
84static std::unique_ptr<fb::shaderbundle::BackendShaderT>
87 const std::string& shader_name,
88 const ShaderConfig& shader_config) {
89 auto result = std::make_unique<fb::shaderbundle::BackendShaderT>();
90
91 std::shared_ptr<fml::FileMapping> source_file_mapping =
93 if (!source_file_mapping) {
94 std::cerr << "Could not open file for bundled shader \"" << shader_name
95 << "\"." << std::endl;
96 return nullptr;
97 }
98
99 /// Override options.
100 options.target_platform = target_platform;
101 options.file_name = shader_name; // This is just used for error messages.
102 options.type = shader_config.type;
103 options.source_language = shader_config.language;
105 shader_config.source_file_name, options.type, options.source_language,
106 shader_config.entry_point);
107
108 Reflector::Options reflector_options;
109 reflector_options.target_platform = options.target_platform;
110 reflector_options.entry_point_name = options.entry_point_name;
111 reflector_options.shader_name = shader_name;
112
113 Compiler compiler(source_file_mapping, options, reflector_options);
114 if (!compiler.IsValid()) {
115 std::cerr << "Compilation failed for bundled shader \"" << shader_name
116 << "\"." << std::endl;
117 std::cerr << compiler.GetErrorMessages() << std::endl;
118 return nullptr;
119 }
120
121 auto reflector = compiler.GetReflector();
122 if (reflector == nullptr) {
123 std::cerr << "Could not create reflector for bundled shader \""
124 << shader_name << "\"." << std::endl;
125 return nullptr;
126 }
127
128 auto bundle_data = reflector->GetShaderBundleData();
129 if (!bundle_data) {
130 std::cerr << "Bundled shader information was nil for \"" << shader_name
131 << "\"." << std::endl;
132 return nullptr;
133 }
134
135 result = bundle_data->CreateFlatbuffer();
136 if (!result) {
137 std::cerr << "Failed to create flatbuffer for bundled shader \""
138 << shader_name << "\"." << std::endl;
139 return nullptr;
140 }
141
142 return result;
143}
144
145static std::unique_ptr<fb::shaderbundle::ShaderT> GenerateShaderFB(
147 const std::string& shader_name,
148 const ShaderConfig& shader_config) {
149 auto result = std::make_unique<fb::shaderbundle::ShaderT>();
150 result->name = shader_name;
151 result->metal_ios = GenerateShaderBackendFB(
152 TargetPlatform::kMetalIOS, options, shader_name, shader_config);
153 if (!result->metal_ios) {
154 return nullptr;
155 }
156 result->metal_desktop = GenerateShaderBackendFB(
157 TargetPlatform::kMetalDesktop, options, shader_name, shader_config);
158 if (!result->metal_desktop) {
159 return nullptr;
160 }
161 result->opengl_es = GenerateShaderBackendFB(
162 TargetPlatform::kOpenGLES, options, shader_name, shader_config);
163 if (!result->opengl_es) {
164 return nullptr;
165 }
166 result->opengl_desktop = GenerateShaderBackendFB(
167 TargetPlatform::kOpenGLDesktop, options, shader_name, shader_config);
168 if (!result->opengl_desktop) {
169 return nullptr;
170 }
172 shader_name, shader_config);
173 if (!result->vulkan) {
174 return nullptr;
175 }
176 return result;
177}
178
179std::optional<fb::shaderbundle::ShaderBundleT> GenerateShaderBundleFlatbuffer(
180 const std::string& bundle_config_json,
181 const SourceOptions& options) {
182 // --------------------------------------------------------------------------
183 /// 1. Parse the bundle configuration.
184 ///
185
186 std::optional<ShaderBundleConfig> bundle_config =
187 ParseShaderBundleConfig(bundle_config_json, std::cerr);
188 if (!bundle_config) {
189 return std::nullopt;
190 }
191
192 // --------------------------------------------------------------------------
193 /// 2. Build the deserialized shader bundle.
194 ///
195
196 fb::shaderbundle::ShaderBundleT shader_bundle;
197
198 for (const auto& [shader_name, shader_config] : bundle_config.value()) {
199 std::unique_ptr<fb::shaderbundle::ShaderT> shader =
200 GenerateShaderFB(options, shader_name, shader_config);
201 if (!shader) {
202 return std::nullopt;
203 }
204 shader_bundle.shaders.push_back(std::move(shader));
205 }
206
207 return shader_bundle;
208}
209
211 // --------------------------------------------------------------------------
212 /// 1. Parse the shader bundle and generate the flatbuffer result.
213 ///
214
215 auto shader_bundle = GenerateShaderBundleFlatbuffer(
216 switches.shader_bundle, switches.CreateSourceOptions());
217 if (!shader_bundle.has_value()) {
218 // Specific error messages are already handled by
219 // GenerateShaderBundleFlatbuffer.
220 return false;
221 }
222
223 // --------------------------------------------------------------------------
224 /// 2. Serialize the shader bundle and write to disk.
225 ///
226
227 auto builder = std::make_shared<flatbuffers::FlatBufferBuilder>();
229 &shader_bundle.value()),
230 fb::shaderbundle::ShaderBundleIdentifier());
231 auto mapping = std::make_shared<fml::NonOwnedMapping>(
232 builder->GetBufferPointer(), builder->GetSize(),
233 [builder](auto, auto) {});
234
235 auto sl_file_name = std::filesystem::absolute(
236 std::filesystem::current_path() / switches.sl_file_name);
237
238 if (!fml::WriteAtomically(*switches.working_directory, //
239 Utf8FromPath(sl_file_name).c_str(), //
240 *mapping //
241 )) {
242 std::cerr << "Could not write file to " << switches.sl_file_name
243 << std::endl;
244 return false;
245 }
246 // Tools that consume the runtime stage data expect the access mode to
247 // be 0644.
248 if (!SetPermissiveAccess(sl_file_name)) {
249 return false;
250 }
251
252 return true;
253}
254
255} // namespace compiler
256} // namespace impeller
const char * options
static std::unique_ptr< FileMapping > CreateReadOnly(const std::string &path)
Definition: mapping.cc:20
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
GAsyncResult * result
static void * Pack(const T &ctx, SkArenaAlloc *alloc)
bool WriteAtomically(const fml::UniqueFD &base_directory, const char *file_name, const Mapping &mapping)
Definition: file_posix.cc:191
static std::unique_ptr< fb::shaderbundle::ShaderT > GenerateShaderFB(SourceOptions options, const std::string &shader_name, const ShaderConfig &shader_config)
bool SetPermissiveAccess(const std::filesystem::path &p)
Sets the file access mode of the file at path 'p' to 0644.
Definition: utilities.cc:16
static std::unique_ptr< fb::shaderbundle::BackendShaderT > GenerateShaderBackendFB(TargetPlatform target_platform, SourceOptions &options, const std::string &shader_name, const ShaderConfig &shader_config)
std::optional< fb::shaderbundle::ShaderBundleT > GenerateShaderBundleFlatbuffer(const std::string &bundle_config_json, const SourceOptions &options)
Parses the JSON shader bundle configuration and invokes the compiler multiple times to produce a shad...
bool GenerateShaderBundle(Switches &switches)
Parses the JSON shader bundle configuration and invokes the compiler multiple times to produce a shad...
std::unordered_map< std::string, ShaderConfig > ShaderBundleConfig
Definition: types.h:81
SourceType SourceTypeFromString(std::string name)
Definition: types.cc:46
std::optional< ShaderBundleConfig > ParseShaderBundleConfig(const std::string &bundle_config_json, std::ostream &error_stream)
Parse a shader bundle configuration from a given JSON string.
std::string EntryPointFunctionNameFromSourceName(const std::string &file_name, SourceType type, SourceLanguage source_language, const std::string &entry_point_name)
Definition: types.cc:111
std::string Utf8FromPath(const std::filesystem::path &path)
Converts a native format path to a utf8 string.
Definition: utilities.cc:30
SourceLanguage ToSourceLanguage(const std::string &source_language)
Definition: types.cc:64
compiler
Definition: malisc.py:17
def parse(repo_root, recipes_cfg_path)
Definition: recipes.py:56
A shader config parsed as part of a ShaderBundleConfig.
Definition: types.h:74
std::string source_file_name
Definition: types.h:75
SourceLanguage language
Definition: types.h:77