| 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
5 #include "impeller/compiler/shader_bundle.h"
6 #include "impeller/compiler/compiler.h"
7 #include "impeller/compiler/reflector.h"
8 #include "impeller/compiler/source_options.h"
9 #include "impeller/compiler/types.h"
10
11 #include "impeller/compiler/utilities.h"
12 #include "impeller/runtime_stage/runtime_stage.h"
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"])
66 : SourceLanguage::kGLSL;
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;
102 options.entry_point_name = EntryPointFunctionNameFromSourceName(
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
175 bool GenerateShaderBundle(Switches& switches) {
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