19#include "impeller/shader_bundle/shader_bundle_flatbuffers.h"
20#include "third_party/json/include/nlohmann/json.hpp"
26 const std::string& bundle_config_json,
27 std::ostream& error_stream) {
28 auto json = nlohmann::json::parse(bundle_config_json,
nullptr,
false);
29 if (json.is_discarded() || !json.is_object()) {
30 error_stream <<
"The shader bundle is not a valid JSON object."
36 for (
auto& [shader_name, shader_value] : json.items()) {
37 if (bundle.find(shader_name) != bundle.end()) {
38 error_stream <<
"Duplicate shader \"" << shader_name <<
"\"."
42 if (!shader_value.is_object()) {
43 error_stream <<
"Invalid shader entry \"" << shader_name
44 <<
"\": Entry is not a JSON object." << std::endl;
50 if (!shader_value.contains(
"file")) {
51 error_stream <<
"Invalid shader entry \"" << shader_name
52 <<
"\": Missing required \"file\" field." << std::endl;
57 if (!shader_value.contains(
"type")) {
58 error_stream <<
"Invalid shader entry \"" << shader_name
59 <<
"\": Missing required \"type\" field." << std::endl;
64 error_stream <<
"Invalid shader entry \"" << shader_name
65 <<
"\": Shader type " << shader_value[
"type"]
66 <<
" is unknown." << std::endl;
70 shader.
language = shader_value.contains(
"language")
74 error_stream <<
"Invalid shader entry \"" << shader_name
75 <<
"\": Unknown language type " << shader_value[
"language"]
80 shader.
entry_point = shader_value.contains(
"entry_point")
81 ? shader_value[
"entry_point"]
84 bundle[shader_name] = shader;
94 return {
"IMPELLER_TARGET_METAL",
"IMPELLER_TARGET_METAL_IOS"};
96 return {
"IMPELLER_TARGET_METAL",
"IMPELLER_TARGET_METAL_DESKTOP"};
98 return {
"IMPELLER_TARGET_OPENGLES"};
100 return {
"IMPELLER_TARGET_OPENGL"};
102 return {
"IMPELLER_TARGET_VULKAN"};
114static std::unique_ptr<fb::shaderbundle::BackendShaderT>
117 const std::string& shader_name,
119 std::set<std::string>* out_dependencies) {
120 auto result = std::make_unique<fb::shaderbundle::BackendShaderT>();
122 std::shared_ptr<fml::FileMapping> source_file_mapping =
124 if (!source_file_mapping) {
125 std::cerr <<
"Could not open file for bundled shader \"" << shader_name
126 <<
"\"." << std::endl;
146 for (
const auto& define :
148 backend_options.
defines.emplace_back(define);
156 Compiler compiler(source_file_mapping, backend_options, reflector_options);
158 std::cerr <<
"Compilation failed for bundled shader \"" << shader_name
159 <<
"\"." << std::endl;
168 if (out_dependencies) {
171 out_dependencies->insert(included);
176 if (reflector ==
nullptr) {
177 std::cerr <<
"Could not create reflector for bundled shader \""
178 << shader_name <<
"\"." << std::endl;
184 std::cerr <<
"Bundled shader information was nil for \"" << shader_name
185 <<
"\"." << std::endl;
189 result = bundle_data->CreateFlatbuffer();
191 std::cerr <<
"Failed to create flatbuffer for bundled shader \""
192 << shader_name <<
"\"." << std::endl;
201 const std::string& shader_name,
203 std::set<std::string>* out_dependencies) {
204 auto result = std::make_unique<fb::shaderbundle::ShaderT>();
205 result->name = shader_name;
208 shader_config, out_dependencies);
209 if (!result->metal_ios) {
212 result->metal_desktop =
214 shader_name, shader_config, out_dependencies);
215 if (!result->metal_desktop) {
220 shader_config, out_dependencies);
221 if (!result->opengl_es) {
224 result->opengl_desktop =
226 shader_name, shader_config, out_dependencies);
227 if (!result->opengl_desktop) {
232 shader_config, out_dependencies);
233 if (!result->vulkan) {
240 const std::string& bundle_config_json,
242 std::set<std::string>* out_dependencies) {
247 std::optional<ShaderBundleConfig> bundle_config =
249 if (!bundle_config) {
257 fb::shaderbundle::ShaderBundleT shader_bundle;
258 shader_bundle.format_version =
static_cast<uint32_t
>(
259 fb::shaderbundle::ShaderBundleFormatVersion::kVersion);
261 for (
const auto& [shader_name, shader_config] : bundle_config.value()) {
262 std::unique_ptr<fb::shaderbundle::ShaderT> shader =
267 shader_bundle.shaders.push_back(std::move(shader));
270 return shader_bundle;
282 const std::string&
target,
283 const std::set<std::string>& dependencies) {
284 std::stringstream stream;
286 for (
const auto& dep : dependencies) {
287 stream <<
" " << dep;
290 const auto contents = std::make_shared<std::string>(stream.str());
292 reinterpret_cast<const uint8_t*
>(contents->data()), contents->size(),
293 [contents](
auto,
auto) {});
302 std::cerr <<
"Could not write depfile to " << switches.
depfile_path
318 std::set<std::string> dependencies;
319 const bool want_depfile = !switches.
depfile_path.empty();
322 want_depfile ? &dependencies :
nullptr);
323 if (!shader_bundle.has_value()) {
333 auto builder = std::make_shared<flatbuffers::FlatBufferBuilder>();
334 builder->Finish(fb::shaderbundle::ShaderBundle::Pack(*builder.get(),
335 &shader_bundle.value()),
336 fb::shaderbundle::ShaderBundleIdentifier());
337 auto mapping = std::make_shared<fml::NonOwnedMapping>(
338 builder->GetBufferPointer(), builder->GetSize(),
339 [builder](
auto,
auto) {});
341 auto sl_file_name = std::filesystem::absolute(
342 std::filesystem::current_path() / switches.
sl_file_name);
348 std::cerr <<
"Could not write file to " << switches.
sl_file_name
static std::unique_ptr< FileMapping > CreateReadOnly(const std::string &path)
const Reflector * GetReflector() const
const std::vector< std::string > & GetIncludedFileNames() const
std::string GetErrorMessages() const
std::shared_ptr< ShaderBundleData > GetShaderBundleData() const
std::filesystem::path sl_file_name
std::string shader_bundle
std::shared_ptr< fml::UniqueFD > working_directory
SourceOptions CreateSourceOptions() const
std::filesystem::path depfile_path
bool WriteAtomically(const fml::UniqueFD &base_directory, const char *file_name, const Mapping &mapping)
bool SetPermissiveAccess(const std::filesystem::path &p)
Sets the file access mode of the file at path 'p' to 0644.
std::vector< std::string_view > GetShaderBundleTargetPlatformDefines(TargetPlatform platform)
The platform-discriminating preprocessor defines injected when compiling a bundled shader for platfor...
static std::unique_ptr< fb::shaderbundle::ShaderT > GenerateShaderFB(SourceOptions options, const std::string &shader_name, const ShaderConfig &shader_config, std::set< std::string > *out_dependencies)
static std::unique_ptr< fb::shaderbundle::BackendShaderT > GenerateShaderBackendFB(TargetPlatform target_platform, SourceOptions &options, const std::string &shader_name, const ShaderConfig &shader_config, std::set< std::string > *out_dependencies)
std::optional< fb::shaderbundle::ShaderBundleT > GenerateShaderBundleFlatbuffer(const std::string &bundle_config_json, const SourceOptions &options, std::set< std::string > *out_dependencies)
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
std::string EntryPointFunctionNameFromSourceName(const std::filesystem::path &file_name, SourceType type, SourceLanguage source_language, const std::string &entry_point_name)
SourceType SourceTypeFromString(std::string name)
std::optional< ShaderBundleConfig > ParseShaderBundleConfig(const std::string &bundle_config_json, std::ostream &error_stream)
Parse a shader bundle configuration from a given JSON string.
static bool OutputBundleDepfile(const Switches &switches, const std::string &target, const std::set< std::string > &dependencies)
std::string Utf8FromPath(const std::filesystem::path &path)
Converts a native format path to a utf8 string.
SourceLanguage ToSourceLanguage(const std::string &source_language)
TargetPlatform target_platform
std::string entry_point_name
A shader config parsed as part of a ShaderBundleConfig.
std::string source_file_name
SourceLanguage source_language
std::filesystem::path file_name
std::string entry_point_name
TargetPlatform target_platform
std::vector< std::string > defines