Flutter Impeller
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 
16 namespace impeller {
17 namespace compiler {
18 
19 std::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 
84 static std::unique_ptr<fb::ShaderT> GenerateShaderFB(
85  SourceOptions options,
86  const std::string& shader_name,
87  const ShaderConfig& shader_config) {
88  auto result = std::make_unique<fb::ShaderT>();
89  result->name = shader_name;
90 
91  std::shared_ptr<fml::FileMapping> source_file_mapping =
92  fml::FileMapping::CreateReadOnly(shader_config.source_file_name);
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.type = shader_config.type;
101  options.source_language = shader_config.language;
103  shader_config.source_file_name, options.type, options.source_language,
104  shader_config.entry_point);
105 
106  Reflector::Options reflector_options;
107  reflector_options.target_platform = options.target_platform;
108  reflector_options.entry_point_name = options.entry_point_name;
109  reflector_options.shader_name = shader_name;
110 
111  Compiler compiler(source_file_mapping, options, reflector_options);
112  if (!compiler.IsValid()) {
113  std::cerr << "Compilation failed for bundled shader \"" << shader_name
114  << "\"." << std::endl;
115  std::cerr << compiler.GetErrorMessages() << std::endl;
116  return nullptr;
117  }
118 
119  auto reflector = compiler.GetReflector();
120  if (reflector == nullptr) {
121  std::cerr << "Could not create reflector for bundled shader \""
122  << shader_name << "\"." << std::endl;
123  return nullptr;
124  }
125 
126  auto stage_data = reflector->GetRuntimeStageShaderData();
127  if (!stage_data) {
128  std::cerr << "Runtime stage information was nil for bundled shader \""
129  << shader_name << "\"." << std::endl;
130  return nullptr;
131  }
132  RuntimeStageData stages;
133  stages.AddShader(stage_data);
134  result->shader = stages.CreateFlatbuffer();
135  if (!result->shader) {
136  std::cerr << "Failed to create flatbuffer for bundled shader \""
137  << shader_name << "\"." << std::endl;
138  return nullptr;
139  }
140 
141  return result;
142 }
143 
144 std::optional<fb::ShaderBundleT> GenerateShaderBundleFlatbuffer(
145  const std::string& bundle_config_json,
146  const SourceOptions& options) {
147  // --------------------------------------------------------------------------
148  /// 1. Parse the bundle configuration.
149  ///
150 
151  std::optional<ShaderBundleConfig> bundle_config =
152  ParseShaderBundleConfig(bundle_config_json, std::cerr);
153  if (!bundle_config) {
154  return std::nullopt;
155  }
156 
157  // --------------------------------------------------------------------------
158  /// 2. Build the deserialized shader bundle.
159  ///
160 
161  fb::ShaderBundleT shader_bundle;
162 
163  for (const auto& [shader_name, shader_config] : bundle_config.value()) {
164  std::unique_ptr<fb::ShaderT> shader =
165  GenerateShaderFB(options, shader_name, shader_config);
166  if (!shader) {
167  return std::nullopt;
168  }
169  shader_bundle.shaders.push_back(std::move(shader));
170  }
171 
172  return shader_bundle;
173 }
174 
176  // --------------------------------------------------------------------------
177  /// 1. Parse the shader bundle and generate the flatbuffer result.
178  ///
179 
180  auto shader_bundle = GenerateShaderBundleFlatbuffer(
181  switches.shader_bundle, switches.CreateSourceOptions());
182  if (!shader_bundle.has_value()) {
183  // Specific error messages are already handled by
184  // GenerateShaderBundleFlatbuffer.
185  return false;
186  }
187 
188  // --------------------------------------------------------------------------
189  /// 2. Serialize the shader bundle and write to disk.
190  ///
191 
192  auto builder = std::make_shared<flatbuffers::FlatBufferBuilder>();
193  builder->Finish(
194  fb::ShaderBundle::Pack(*builder.get(), &shader_bundle.value()),
195  fb::ShaderBundleIdentifier());
196  auto mapping = std::make_shared<fml::NonOwnedMapping>(
197  builder->GetBufferPointer(), builder->GetSize(),
198  [builder](auto, auto) {});
199 
200  auto sl_file_name = std::filesystem::absolute(
201  std::filesystem::current_path() / switches.sl_file_name);
202 
203  if (!fml::WriteAtomically(*switches.working_directory, //
204  Utf8FromPath(sl_file_name).c_str(), //
205  *mapping //
206  )) {
207  std::cerr << "Could not write file to " << switches.sl_file_name
208  << std::endl;
209  return false;
210  }
211  // Tools that consume the runtime stage data expect the access mode to
212  // be 0644.
213  if (!SetPermissiveAccess(sl_file_name)) {
214  return false;
215  }
216 
217  return true;
218 }
219 
220 } // namespace compiler
221 } // namespace impeller
impeller::compiler::ShaderConfig::entry_point
std::string entry_point
Definition: types.h:52
impeller::compiler::Compiler
Definition: compiler.h:25
impeller::compiler::SourceOptions::type
SourceType type
Definition: source_options.h:21
shader_bundle.h
impeller::compiler::ShaderConfig::language
SourceLanguage language
Definition: types.h:51
impeller::compiler::SourceType::kUnknown
@ kUnknown
impeller::compiler::RuntimeStageData
Definition: runtime_stage_data.h:44
impeller::compiler::SourceOptions
Definition: source_options.h:20
impeller::compiler::RuntimeStageData::AddShader
void AddShader(const std::shared_ptr< Shader > &data)
Definition: runtime_stage_data.cc:27
impeller::compiler::ParseShaderBundleConfig
std::optional< ShaderBundleConfig > ParseShaderBundleConfig(const std::string &bundle_config_json, std::ostream &error_stream)
Parse a shader bundle configuration from a given JSON string.
Definition: shader_bundle.cc:19
impeller::compiler::SourceLanguage::kGLSL
@ kGLSL
impeller::compiler::Reflector::Options::target_platform
TargetPlatform target_platform
Definition: reflector.h:54
reflector.h
impeller::compiler::Reflector::GetRuntimeStageShaderData
std::shared_ptr< RuntimeStageData::Shader > GetRuntimeStageShaderData() const
Definition: reflector.cc:164
impeller::compiler::ShaderConfig::type
SourceType type
Definition: types.h:50
impeller::compiler::SourceOptions::source_language
SourceLanguage source_language
Definition: source_options.h:23
runtime_stage.h
impeller::compiler::ToSourceLanguage
SourceLanguage ToSourceLanguage(const std::string &source_language)
Definition: types.cc:64
impeller::compiler::GenerateShaderFB
static std::unique_ptr< fb::ShaderT > GenerateShaderFB(SourceOptions options, const std::string &shader_name, const ShaderConfig &shader_config)
Definition: shader_bundle.cc:84
impeller::compiler::Reflector::Options::shader_name
std::string shader_name
Definition: reflector.h:56
impeller::compiler::SourceOptions::entry_point_name
std::string entry_point_name
Definition: source_options.h:27
impeller::compiler::Compiler::GetErrorMessages
std::string GetErrorMessages() const
Definition: compiler.cc:450
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:111
impeller::compiler::Compiler::GetReflector
const Reflector * GetReflector() const
Definition: compiler.cc:493
impeller::compiler::Reflector::Options
Definition: reflector.h:53
compiler.h
utilities.h
impeller::compiler::SourceLanguage::kUnknown
@ kUnknown
impeller::compiler::Switches::sl_file_name
std::string sl_file_name
Definition: switches.h:30
impeller::compiler::SourceOptions::target_platform
TargetPlatform target_platform
Definition: source_options.h:22
impeller::compiler::ShaderBundleConfig
std::unordered_map< std::string, ShaderConfig > ShaderBundleConfig
Definition: types.h:55
impeller::compiler::Compiler::IsValid
bool IsValid() const
Definition: compiler.cc:440
impeller::compiler::GenerateShaderBundleFlatbuffer
std::optional< fb::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...
Definition: shader_bundle.cc:144
impeller::compiler::SourceTypeFromString
SourceType SourceTypeFromString(std::string name)
Definition: types.cc:46
impeller::compiler::ShaderConfig::source_file_name
std::string source_file_name
Definition: types.h:49
impeller::compiler::Switches::CreateSourceOptions
SourceOptions CreateSourceOptions(std::optional< TargetPlatform > target_platform=std::nullopt) const
Definition: switches.cc:305
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::Utf8FromPath
std::string Utf8FromPath(const std::filesystem::path &path)
Converts a native format path to a utf8 string.
Definition: utilities.cc:30
impeller::compiler::Switches
Definition: switches.h:21
impeller::compiler::Reflector::Options::entry_point_name
std::string entry_point_name
Definition: reflector.h:55
impeller::compiler::RuntimeStageData::CreateFlatbuffer
std::unique_ptr< fb::RuntimeStagesT > CreateFlatbuffer() const
Definition: runtime_stage_data.cc:296
impeller
Definition: aiks_context.cc:10
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:175
impeller::compiler::ShaderConfig
A shader config parsed as part of a ShaderBundleConfig.
Definition: types.h:48
impeller::compiler::Switches::working_directory
std::shared_ptr< fml::UniqueFD > working_directory
Definition: switches.h:23
types.h
impeller::compiler::Switches::shader_bundle
std::string shader_bundle
Definition: switches.h:32