diff --git a/impeller/BUILD.gn b/impeller/BUILD.gn index b206c99e9f584..76e0d6c249875 100644 --- a/impeller/BUILD.gn +++ b/impeller/BUILD.gn @@ -48,6 +48,7 @@ executable("impeller_unittests") { deps = [ "archivist:archivist_unittests", "base:base_unittests", + "blobcat:blobcat_unittests", "compiler:compiler_unittests", "fixtures", "geometry:geometry_unittests", diff --git a/impeller/blobcat/BUILD.gn b/impeller/blobcat/BUILD.gn new file mode 100644 index 0000000000000..4899e5f9708d2 --- /dev/null +++ b/impeller/blobcat/BUILD.gn @@ -0,0 +1,49 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("../tools/impeller.gni") + +impeller_component("blobcat_lib") { + sources = [ + "blob.cc", + "blob.h", + "blob_library.cc", + "blob_library.h", + "blob_writer.cc", + "blob_writer.h", + ] + + deps = [ + "../base", + "//flutter/fml", + ] +} + +impeller_component("blobcat") { + target_type = "executable" + + sources = [ "blobcat_main.cc" ] + + deps = [ + ":blobcat_lib", + "../base", + "//flutter/fml", + + # FML depends on the Dart VM for tracing and getting the current + # timepoint. + "//flutter/runtime:libdart", + ] +} + +impeller_component("blobcat_unittests") { + testonly = true + + sources = [ "blobcat_unittests.cc" ] + + deps = [ + ":blobcat_lib", + "//flutter/fml", + "//flutter/testing", + ] +} diff --git a/impeller/blobcat/blob.cc b/impeller/blobcat/blob.cc new file mode 100644 index 0000000000000..e7f97177af870 --- /dev/null +++ b/impeller/blobcat/blob.cc @@ -0,0 +1,11 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/blobcat/blob.h" + +namespace impeller { + +// + +} // namespace impeller diff --git a/impeller/blobcat/blob.h b/impeller/blobcat/blob.h new file mode 100644 index 0000000000000..70e864191aff9 --- /dev/null +++ b/impeller/blobcat/blob.h @@ -0,0 +1,43 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "flutter/fml/mapping.h" + +namespace impeller { + +constexpr const uint32_t kBlobCatMagic = 0x0B10BCA7; +struct BlobHeader { + uint32_t magic = kBlobCatMagic; + uint32_t blob_count = 0u; +}; + +struct Blob { + enum class ShaderType : uint8_t { + kVertex, + kFragment, + }; + + static constexpr size_t kMaxNameLength = 24u; + + ShaderType type = ShaderType::kVertex; + uint64_t offset = 0; + uint64_t length = 0; + uint8_t name[kMaxNameLength] = {}; +}; + +struct BlobDescription { + Blob::ShaderType type; + std::string name; + std::shared_ptr mapping; +}; + +} // namespace impeller diff --git a/impeller/blobcat/blob_library.cc b/impeller/blobcat/blob_library.cc new file mode 100644 index 0000000000000..809f40ec344b3 --- /dev/null +++ b/impeller/blobcat/blob_library.cc @@ -0,0 +1,94 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/blobcat/blob_library.h" + +#include + +namespace impeller { + +BlobLibrary::BlobLibrary(std::shared_ptr mapping) + : mapping_(std::move(mapping)) { + if (!mapping_ || mapping_->GetMapping() == nullptr) { + FML_LOG(ERROR) << "Invalid mapping."; + return; + } + + BlobHeader header; + std::vector blobs; + + size_t offset = 0u; + + // Read the header. + { + const size_t read_size = sizeof(BlobHeader); + if (mapping_->GetSize() < offset + read_size) { + return; + } + std::memcpy(&header, mapping_->GetMapping() + offset, read_size); + offset += read_size; + + // Validate the header. + if (header.magic != kBlobCatMagic) { + FML_LOG(ERROR) << "Invalid blob magic."; + return; + } + + blobs.resize(header.blob_count); + } + + // Read the blob descriptions. + { + const size_t read_size = sizeof(Blob) * header.blob_count; + ::memcpy(blobs.data(), mapping_->GetMapping() + offset, read_size); + offset += read_size; + } + + // Read the blobs. + { + for (size_t i = 0; i < header.blob_count; i++) { + const auto& blob = blobs[i]; + + BlobKey key; + key.type = blob.type; + key.name = std::string{reinterpret_cast(blob.name)}; + auto mapping = std::make_shared( + mapping_->GetMapping() + blob.offset, // offset + blob.length, // length + [mapping = mapping_](const uint8_t* data, size_t size) {} + // release proc + ); + + auto inserted = blobs_.insert({key, mapping}); + if (!inserted.second) { + FML_LOG(ERROR) << "Shader library had duplicate shader named " + << key.name; + return; + } + } + } + + is_valid_ = true; +} + +BlobLibrary::~BlobLibrary() = default; + +bool BlobLibrary::IsValid() const { + return is_valid_; +} + +size_t BlobLibrary::GetShaderCount() const { + return blobs_.size(); +} + +std::shared_ptr BlobLibrary::GetMapping(Blob::ShaderType type, + std::string name) const { + BlobKey key; + key.type = type; + key.name = name; + auto found = blobs_.find(key); + return found == blobs_.end() ? nullptr : found->second; +} + +} // namespace impeller diff --git a/impeller/blobcat/blob_library.h b/impeller/blobcat/blob_library.h new file mode 100644 index 0000000000000..200d775dc8424 --- /dev/null +++ b/impeller/blobcat/blob_library.h @@ -0,0 +1,63 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/hash_combine.h" +#include "flutter/fml/macros.h" +#include "flutter/fml/mapping.h" +#include "impeller/blobcat/blob.h" + +namespace impeller { + +class BlobLibrary { + public: + BlobLibrary(std::shared_ptr mapping); + + ~BlobLibrary(); + + bool IsValid() const; + + size_t GetShaderCount() const; + + std::shared_ptr GetMapping(Blob::ShaderType type, + std::string name) const; + + private: + struct BlobKey { + Blob::ShaderType type = Blob::ShaderType::kFragment; + std::string name; + + struct Hash { + size_t operator()(const BlobKey& key) const { + return fml::HashCombine( + static_cast>(key.type), + key.name); + } + }; + + struct Equal { + bool operator()(const BlobKey& lhs, const BlobKey& rhs) const { + return lhs.type == rhs.type && lhs.name == rhs.name; + } + }; + }; + + using Blobs = std::unordered_map, + BlobKey::Hash, + BlobKey::Equal>; + + std::shared_ptr mapping_; + Blobs blobs_; + bool is_valid_ = false; + + FML_DISALLOW_COPY_AND_ASSIGN(BlobLibrary); +}; + +} // namespace impeller diff --git a/impeller/blobcat/blob_writer.cc b/impeller/blobcat/blob_writer.cc new file mode 100644 index 0000000000000..82a62edfe0485 --- /dev/null +++ b/impeller/blobcat/blob_writer.cc @@ -0,0 +1,144 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/blobcat/blob_writer.h" + +#include +#include + +namespace impeller { + +BlobWriter::BlobWriter() = default; + +BlobWriter::~BlobWriter() = default; + +std::optional InferShaderTypefromFileExtension( + const std::filesystem::path& path) { + if (path == ".vert") { + return Blob::ShaderType::kVertex; + } else if (path == ".frag") { + return Blob::ShaderType::kFragment; + } + return std::nullopt; +} + +bool BlobWriter::AddBlobAtPath(const std::string& std_path) { + std::filesystem::path path(std_path); + + if (path.stem().empty()) { + FML_LOG(ERROR) << "File path stem was empty for " << path; + return false; + } + + if (path.extension() != ".gles") { + FML_LOG(ERROR) << "File path doesn't have a known shader extension " + << path; + return false; + } + + // Get rid of .gles + path = path.replace_extension(); + + auto shader_type = InferShaderTypefromFileExtension(path.extension()); + + if (!shader_type.has_value()) { + FML_LOG(ERROR) << "Could not infer shader type from file extension."; + return false; + } + + // Get rid of the shader type extension (.vert, .frag, etc..). + path = path.replace_extension(); + + const auto shader_name = path.stem().string(); + if (shader_name.empty()) { + FML_LOG(ERROR) << "Shader name was empty."; + return false; + } + + auto file_mapping = fml::FileMapping::CreateReadOnly(std_path); + if (!file_mapping) { + FML_LOG(ERROR) << "File doesn't exist at path: " << path; + return false; + } + + return AddBlob(shader_type.value(), std::move(shader_name), + std::move(file_mapping)); +} + +bool BlobWriter::AddBlob(Blob::ShaderType type, + std::string name, + std::shared_ptr mapping) { + if (name.empty() || !mapping || mapping->GetMapping() == nullptr) { + return false; + } + + if (name.length() >= Blob::kMaxNameLength) { + FML_LOG(ERROR) << "Blob name length was too long."; + return false; + } + + blob_descriptions_.emplace_back( + BlobDescription{type, std::move(name), std::move(mapping)}); + return true; +} + +std::shared_ptr BlobWriter::CreateMapping() const { + BlobHeader header; + header.blob_count = blob_descriptions_.size(); + + uint64_t offset = sizeof(BlobHeader) + (sizeof(Blob) * header.blob_count); + + std::vector blobs; + { + blobs.resize(header.blob_count); + for (size_t i = 0; i < header.blob_count; i++) { + const auto& desc = blob_descriptions_[i]; + blobs[i].type = desc.type; + blobs[i].offset = offset; + blobs[i].length = desc.mapping->GetSize(); + std::memcpy(reinterpret_cast(blobs[i].name), desc.name.data(), + desc.name.size()); + offset += blobs[i].length; + } + } + + { + auto buffer = std::make_shared>(); + buffer->resize(offset, 0); + + size_t write_offset = 0u; + + // Write the header. + { + const size_t write_length = sizeof(header); + std::memcpy(buffer->data() + write_offset, &header, write_length); + write_offset += write_length; + } + + // Write the blob descriptions. + { + const size_t write_length = blobs.size() * sizeof(Blob); + std::memcpy(buffer->data() + write_offset, blobs.data(), write_length); + write_offset += write_length; + } + + // Write the blobs themselves. + { + for (size_t i = 0; i < header.blob_count; i++) { + const auto& desc = blob_descriptions_[i]; + const size_t write_length = desc.mapping->GetSize(); + std::memcpy(buffer->data() + write_offset, desc.mapping->GetMapping(), + write_length); + write_offset += write_length; + } + } + FML_CHECK(write_offset == offset); + return std::make_shared( + buffer->data(), buffer->size(), + [buffer](const uint8_t* data, size_t size) {}); + } + return nullptr; +} + +} // namespace impeller diff --git a/impeller/blobcat/blob_writer.h b/impeller/blobcat/blob_writer.h new file mode 100644 index 0000000000000..bbf60213ac73a --- /dev/null +++ b/impeller/blobcat/blob_writer.h @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "flutter/fml/mapping.h" +#include "impeller/blobcat/blob.h" + +namespace impeller { + +class BlobWriter { + public: + BlobWriter(); + + ~BlobWriter(); + + [[nodiscard]] bool AddBlobAtPath(const std::string& path); + + [[nodiscard]] bool AddBlob(Blob::ShaderType type, + std::string name, + std::shared_ptr mapping); + + std::shared_ptr CreateMapping() const; + + private: + std::vector blob_descriptions_; + + FML_DISALLOW_COPY_AND_ASSIGN(BlobWriter); +}; + +} // namespace impeller diff --git a/impeller/blobcat/blobcat_main.cc b/impeller/blobcat/blobcat_main.cc new file mode 100644 index 0000000000000..65480a6fe258d --- /dev/null +++ b/impeller/blobcat/blobcat_main.cc @@ -0,0 +1,52 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "flutter/fml/command_line.h" +#include "impeller/blobcat/blob_writer.h" + +namespace impeller { + +bool Main(const fml::CommandLine& command_line) { + BlobWriter writer; + + std::string output; + if (!command_line.GetOptionValue("output", &output)) { + std::cerr << "Output path not specified." << std::endl; + return false; + } + + for (const auto& input : command_line.GetOptionValues("input")) { + if (!writer.AddBlobAtPath(std::string{input})) { + std::cerr << "Could not add blob at path: " << input << std::endl; + return false; + } + } + + auto blob = writer.CreateMapping(); + if (!blob) { + std::cerr << "Could not create combined shader blob." << std::endl; + return false; + } + + auto current_directory = + fml::OpenDirectory(std::filesystem::current_path().native().c_str(), + false, fml::FilePermission::kReadWrite); + if (!fml::WriteAtomically(current_directory, output.c_str(), *blob)) { + std::cerr << "Could not write shader blob to path " << output << std::endl; + return false; + } + + return true; +} + +} // namespace impeller + +int main(int argc, char const* argv[]) { + return impeller::Main(fml::CommandLineFromArgcArgv(argc, argv)) + ? EXIT_SUCCESS + : EXIT_FAILURE; +} diff --git a/impeller/blobcat/blobcat_unittests.cc b/impeller/blobcat/blobcat_unittests.cc new file mode 100644 index 0000000000000..bc5bab227d667 --- /dev/null +++ b/impeller/blobcat/blobcat_unittests.cc @@ -0,0 +1,57 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "flutter/fml/mapping.h" +#include "flutter/testing/testing.h" +#include "impeller/blobcat/blob_library.h" +#include "impeller/blobcat/blob_writer.h" + +namespace impeller { +namespace testing { + +static std::shared_ptr CreateMappingFromString( + std::string p_string) { + auto string = std::make_shared(std::move(p_string)); + return std::make_shared( + reinterpret_cast(string->data()), string->size(), + [string](auto, auto) {}); +} + +const std::string CreateStringFromMapping(const fml::Mapping& mapping) { + return std::string{reinterpret_cast(mapping.GetMapping()), + mapping.GetSize()}; +} + +TEST(BlobTest, CanReadAndWriteBlobs) { + BlobWriter writer; + ASSERT_TRUE(writer.AddBlob(Blob::ShaderType::kVertex, "Hello", + CreateMappingFromString("World"))); + ASSERT_TRUE(writer.AddBlob(Blob::ShaderType::kFragment, "Foo", + CreateMappingFromString("Bar"))); + ASSERT_TRUE(writer.AddBlob(Blob::ShaderType::kVertex, "Baz", + CreateMappingFromString("Bang"))); + ASSERT_TRUE(writer.AddBlob(Blob::ShaderType::kVertex, "Ping", + CreateMappingFromString("Pong"))); + ASSERT_TRUE(writer.AddBlob(Blob::ShaderType::kFragment, "Pang", + CreateMappingFromString("World"))); + + auto mapping = writer.CreateMapping(); + ASSERT_NE(mapping, nullptr); + + BlobLibrary library(mapping); + ASSERT_TRUE(library.IsValid()); + ASSERT_EQ(library.GetShaderCount(), 5u); + + // Wrong type. + ASSERT_EQ(library.GetMapping(Blob::ShaderType::kFragment, "Hello"), nullptr); + + auto hello_vtx = library.GetMapping(Blob::ShaderType::kVertex, "Hello"); + ASSERT_NE(hello_vtx, nullptr); + ASSERT_EQ(CreateStringFromMapping(*hello_vtx), "World"); +} + +} // namespace testing +} // namespace impeller diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index 11cc3c73890f7..b7bf327c606ad 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -129,6 +129,13 @@ Compiler::Compiler(const fml::Mapping& source_mapping, return; } + // Implicit definition that indicates that this compilation is for the device + // (instead of the host). + spirv_options.AddMacroDefinition("IMPELLER_DEVICE"); + for (const auto& define : source_options.defines) { + spirv_options.AddMacroDefinition(define); + } + spirv_options.SetAutoBindUniforms(true); spirv_options.SetAutoMapLocations(true); diff --git a/impeller/compiler/impellerc_main.cc b/impeller/compiler/impellerc_main.cc index ca19e15536990..2ce1b4ac6b61e 100644 --- a/impeller/compiler/impellerc_main.cc +++ b/impeller/compiler/impellerc_main.cc @@ -43,6 +43,7 @@ bool Main(const fml::CommandLine& command_line) { options.working_directory = switches.working_directory; options.file_name = switches.source_file_name; options.include_dirs = switches.include_directories; + options.defines = switches.defines; options.entry_point_name = EntryPointFunctionNameFromSourceName( switches.source_file_name, SourceTypeFromFileName(switches.source_file_name), diff --git a/impeller/compiler/source_options.h b/impeller/compiler/source_options.h index e5a3dc54a9713..636c0a5bf9754 100644 --- a/impeller/compiler/source_options.h +++ b/impeller/compiler/source_options.h @@ -23,6 +23,7 @@ struct SourceOptions { std::vector include_dirs; std::string file_name = "main.glsl"; std::string entry_point_name = "main"; + std::vector defines; SourceOptions(); diff --git a/impeller/compiler/switches.cc b/impeller/compiler/switches.cc index b29dcac31a4cd..d7e7d3beebc7f 100644 --- a/impeller/compiler/switches.cc +++ b/impeller/compiler/switches.cc @@ -35,6 +35,7 @@ void Switches::PrintHelp(std::ostream& stream) { << std::endl; stream << "[optional] --reflection-cc=" << std::endl; stream << "[optional,multiple] --include=" << std::endl; + stream << "[optional,multiple] --define=" << std::endl; stream << "[optional] --depfile=" << std::endl; } @@ -96,6 +97,10 @@ Switches::Switches(const fml::CommandLine& command_line) include_directories.emplace_back(std::move(dir_entry)); } + + for (const auto& define : command_line.GetOptionValues("define")) { + defines.emplace_back(define); + } } bool Switches::AreValid(std::ostream& explain) const { diff --git a/impeller/compiler/switches.h b/impeller/compiler/switches.h index 5e1979d026024..38a0aab318727 100644 --- a/impeller/compiler/switches.h +++ b/impeller/compiler/switches.h @@ -28,6 +28,7 @@ struct Switches { std::string reflection_header_name; std::string reflection_cc_name; std::string depfile_path; + std::vector defines; Switches(); diff --git a/impeller/entity/shaders/glyph_atlas.vert b/impeller/entity/shaders/glyph_atlas.vert index 9320a3465d0b4..9c83d8524adc8 100644 --- a/impeller/entity/shaders/glyph_atlas.vert +++ b/impeller/entity/shaders/glyph_atlas.vert @@ -2,6 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifdef IMPELLER_TARGET_OPENGLES + +void main() { + // Unimplemented because the implementation uses instancing and SSBOs. +} + +#else // IMPELLER_TARGET_OPENGLES + uniform FrameInfo { mat4 mvp; vec2 atlas_size; @@ -53,3 +61,6 @@ void main() { v_atlas_size = frame_info.atlas_size; v_text_color = frame_info.text_color; } + +#endif // IMPELLER_TARGET_OPENGLES + diff --git a/impeller/fixtures/BUILD.gn b/impeller/fixtures/BUILD.gn index 64bf53e9e5b54..d113b2ed4ff82 100644 --- a/impeller/fixtures/BUILD.gn +++ b/impeller/fixtures/BUILD.gn @@ -8,7 +8,7 @@ import("//flutter/testing/testing.gni") import("//flutter/impeller/tools/impeller.gni") impeller_shaders("shader_fixtures") { - name = "shader_fixtures" + name = "fixtures" shaders = [ "box_fade.vert", "box_fade.frag", diff --git a/impeller/fixtures/instanced_draw.vert b/impeller/fixtures/instanced_draw.vert index ff35d518e7221..90890b198e575 100644 --- a/impeller/fixtures/instanced_draw.vert +++ b/impeller/fixtures/instanced_draw.vert @@ -2,6 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + +#ifdef IMPELLER_TARGET_OPENGLES + +void main() { + // Instancing is not supported on legacy targets and test will be disabled. +} + +#else // IMPELLER_TARGET_OPENGLES + uniform FrameInfo { mat4 mvp; } frame_info; @@ -22,3 +31,5 @@ void main () { 1.0); v_color = instance_info.colors[gl_InstanceIndex]; } + +#endif // IMPELLER_TARGET_OPENGLES diff --git a/impeller/playground/backend/metal/playground_impl_mtl.mm b/impeller/playground/backend/metal/playground_impl_mtl.mm index f791df7f16c95..9d81f562134cb 100644 --- a/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -15,7 +15,7 @@ #include "flutter/fml/mapping.h" #include "impeller/entity/mtl/entity_shaders.h" -#include "impeller/fixtures/mtl/shader_fixtures.h" +#include "impeller/fixtures/mtl/fixtures_shaders.h" #include "impeller/playground/imgui/mtl/imgui_shaders.h" #include "impeller/renderer/backend/metal/context_mtl.h" #include "impeller/renderer/backend/metal/formats_mtl.h" @@ -33,8 +33,8 @@ return { std::make_shared(impeller_entity_shaders_data, impeller_entity_shaders_length), - std::make_shared(impeller_shader_fixtures_data, - impeller_shader_fixtures_length), + std::make_shared(impeller_fixtures_shaders_data, + impeller_fixtures_shaders_length), std::make_shared(impeller_imgui_shaders_data, impeller_imgui_shaders_length), diff --git a/impeller/playground/imgui/BUILD.gn b/impeller/playground/imgui/BUILD.gn index c56377f7301f6..fcce7aed70814 100644 --- a/impeller/playground/imgui/BUILD.gn +++ b/impeller/playground/imgui/BUILD.gn @@ -5,7 +5,7 @@ import("//flutter/impeller/tools/impeller.gni") impeller_shaders("imgui_shaders") { - name = "imgui_shaders" + name = "imgui" shaders = [ "imgui_raster.vert", "imgui_raster.frag", diff --git a/impeller/playground/imgui/imgui_raster.vert b/impeller/playground/imgui/imgui_raster.vert index 1afd790022518..038bd579b8f19 100644 --- a/impeller/playground/imgui/imgui_raster.vert +++ b/impeller/playground/imgui/imgui_raster.vert @@ -9,13 +9,23 @@ uniforms; in vec2 vertex_position; in vec2 texture_coordinates; -in uint vertex_color; +in int vertex_color; out vec2 frag_texture_coordinates; out vec4 frag_vertex_color; +vec4 ImVertexColorToVec4(int color) { + const float kScale = 1.0f / 255.0f; + return vec4( + ((color >> 0) & 0xFF) * kScale, + ((color >> 8) & 0xFF) * kScale, + ((color >> 16) & 0xFF) * kScale, + ((color >> 24) & 0xFF) * kScale + ); +} + void main() { gl_Position = uniforms.mvp * vec4(vertex_position.xy, 0.0, 1.0); frag_texture_coordinates = texture_coordinates; - frag_vertex_color = unpackUnorm4x8(vertex_color); + frag_vertex_color = ImVertexColorToVec4(vertex_color); } diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index 1b60ddcc47b44..b037af41c07b4 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -146,44 +146,88 @@ template("metal_library") { } } -# ------------------------------------------------------------------------------ -# @brief Build and reflect shader information. Reflected shader -# information will be added to a generated source set along -# with the shader contents. -# -# @param[required] name The name of the shader library. -# -# @param[required] sources The GLSL (4.60) sources to compiled into the shader -# library. -# -template("impeller_shaders_real") { +template("embed_blob") { + assert(defined(invoker.symbol_name), "The symbol name must be specified.") + assert(defined(invoker.blob), "The blob file to embed must be specified") + assert(defined(invoker.hdr), + "The header file containing the symbol name must be specified.") + assert(defined(invoker.cc), + "The CC file containing the symbol data must be specified.") + assert(defined(invoker.deps), "The target dependencies must be specified") + + gen_blob_target_name = "gen_blob_$target_name" + action(gen_blob_target_name) { + inputs = [ invoker.blob ] + outputs = [ + invoker.hdr, + invoker.cc, + ] + args = [ + "--symbol-name", + invoker.symbol_name, + "--output-header", + rebase_path(invoker.hdr), + "--output-source", + rebase_path(invoker.cc), + "--source", + rebase_path(invoker.blob), + ] + script = "//flutter/impeller/tools/xxd.py" + deps = invoker.deps + } + + embed_config = "embed_$target_name" + config(embed_config) { + include_dirs = [ get_path_info( + get_label_info("//flutter/impeller:impeller", "target_gen_dir"), + "dir") ] + } + + source_set(target_name) { + public_configs = [ ":$embed_config" ] + sources = get_target_outputs(":$gen_blob_target_name") + deps = [ ":$gen_blob_target_name" ] + } +} + +template("impellerc") { + # Optional: invoker.defines specifies a list of valueless macro definitions. assert(defined(invoker.shaders), "Impeller shaders must be specified.") - assert(defined(invoker.name), "Name of the shader library must be specified.") + assert(defined(invoker.sl_file_extension), + "The extension of the SL file must be specified (metal, glsl, etc..).") + assert(defined(invoker.intermediates_subdir), + "The subdirectory in which to put intermediates must be specified.") + assert(defined(invoker.shader_target_flag), + "The flag to impellerc for target selection must be specified.") + + sl_file_extension = invoker.sl_file_extension - base_target_name = target_name - impellerc_target_name = "impellerc_mtl_$target_name" - compiled_action_foreach(impellerc_target_name) { + compiled_action_foreach(target_name) { tool = "//flutter/impeller/compiler:impellerc" sources = invoker.shaders + subdir = invoker.intermediates_subdir + shader_target_flag = invoker.shader_target_flag - metal_intermediate = "$target_gen_dir/mtl/{{source_file_part}}.metal" - spirv_intermediate = "$target_gen_dir/mtl/{{source_file_part}}.spirv" + sl_intermediate = + "$target_gen_dir/$subdir/{{source_file_part}}.$sl_file_extension" + spirv_intermediate = "$target_gen_dir/$subdir/{{source_file_part}}.spirv" reflection_json_intermediate = - "$target_gen_dir/mtl/{{source_file_part}}.json" + "$target_gen_dir/$subdir/{{source_file_part}}.json" reflection_header_intermediate = - "$target_gen_dir/mtl/{{source_file_part}}.h" - reflection_cc_intermediate = "$target_gen_dir/mtl/{{source_file_part}}.cc" + "$target_gen_dir/$subdir/{{source_file_part}}.h" + reflection_cc_intermediate = + "$target_gen_dir/$subdir/{{source_file_part}}.cc" outputs = [ - metal_intermediate, + sl_intermediate, reflection_header_intermediate, reflection_cc_intermediate, ] - depfile_path = "$target_gen_dir/mtl/{{source_file_part}}.d" + depfile_path = "$target_gen_dir/$subdir/{{source_file_part}}.d" - metal_intermediate_path = rebase_path(metal_intermediate, root_build_dir) + sl_intermediate_path = rebase_path(sl_intermediate, root_build_dir) spirv_intermediate_path = rebase_path(spirv_intermediate, root_build_dir) depfile_intermediate_path = rebase_path(depfile_path, root_build_dir) @@ -197,60 +241,41 @@ template("impeller_shaders_real") { args = [ "--input={{source}}", - "--sl=$metal_intermediate_path", + "--sl=$sl_intermediate_path", "--spirv=$spirv_intermediate_path", "--reflection-json=$reflection_json_path", "--reflection-header=$reflection_header_path", "--reflection-cc=$reflection_cc_path", "--include={{source_dir}}", "--depfile=$depfile_intermediate_path", + "$shader_target_flag", ] - - if (is_mac) { - args += [ "--metal-desktop" ] - } - if (is_ios) { - args += [ "--metal-ios" ] + if (defined(invoker.defines)) { + foreach(def, invoker.defines) { + args += [ "--define=$def" ] + } } } +} - metal_library_target_name = "metal_library_$target_name" - metal_library(metal_library_target_name) { - name = invoker.name - sources = filter_include(get_target_outputs(":$impellerc_target_name"), - [ "*.metal" ]) - deps = [ ":$impellerc_target_name" ] - } - - shader_glue_target_name = "glue_$target_name" - shader_glue_config_name = "glue_config_$target_name" +template("impellerc_reflect") { + assert( + defined(invoker.impellerc_invocation), + "The target that specifies the ImpellerC invocation to reflect must be defined.") - config(shader_glue_config_name) { - impeller_root_gen_dir = get_path_info( + reflect_config = "reflect_$target_name" + config(reflect_config) { + include_dirs = [ get_path_info( get_label_info("//flutter/impeller:impeller", "target_gen_dir"), - "dir") - - # Contains the generated header headers. - include_dirs = [ - target_gen_dir, - impeller_root_gen_dir, - ] - - if (impeller_enable_metal) { - include_dirs += [ "$impeller_root_gen_dir/mtl" ] - } - - if (impeller_enable_opengles) { - include_dirs += [ "$impeller_root_gen_dir/gles" ] - } + "dir") ] } - source_set(shader_glue_target_name) { - public_configs = [ ":$shader_glue_config_name" ] + impellerc_invocation = invoker.impellerc_invocation - public = - filter_include(get_target_outputs(":$impellerc_target_name"), [ "*.h" ]) - sources = filter_include(get_target_outputs(":$impellerc_target_name"), + source_set(target_name) { + public_configs = [ ":$reflect_config" ] + public = filter_include(get_target_outputs(impellerc_invocation), [ "*.h" ]) + sources = filter_include(get_target_outputs(impellerc_invocation), [ "*.h", "*.cc", @@ -258,70 +283,159 @@ template("impeller_shaders_real") { ]) deps = [ - ":$impellerc_target_name", "//flutter/impeller/renderer", + impellerc_invocation, ] } +} - generate_embedder_data_sources = "embedded_data_gen_sources_$target_name" - action(generate_embedder_data_sources) { - metal_library_files = get_target_outputs(":$metal_library_target_name") - metal_library_file = metal_library_files[0] - inputs = [ metal_library_file ] - output_header = "$target_gen_dir/mtl/$base_target_name.h" - output_source = "$target_gen_dir/mtl/$base_target_name.c" - outputs = [ - output_header, - output_source, - ] - args = [ - "--symbol-name", - base_target_name, - "--output-header", - rebase_path(output_header), - "--output-source", - rebase_path(output_source), - "--source", - rebase_path(metal_library_file), +template("impeller_shaders_metal") { + assert(defined(invoker.shaders), "Impeller shaders must be specified.") + assert(defined(invoker.name), "Name of the shader library must be specified.") + + shaders_base_name = string_join("", + [ + invoker.name, + "_shaders", + ]) + impellerc_mtl = "impellerc_$target_name" + impellerc(impellerc_mtl) { + shaders = invoker.shaders + sl_file_extension = "metal" + intermediates_subdir = "mtl" + shader_target_flag = "" + defines = [ "IMPELLER_TARGET_METAL" ] + if (is_ios) { + shader_target_flag = "--metal-ios" + defines += [ "IMPELLER_TARGET_METAL_IOS" ] + } else if (is_mac) { + shader_target_flag = "--metal-desktop" + defines += [ "IMPELLER_TARGET_METAL_DESKTOP" ] + } else { + assert(false, "Metal not supported on this platform.") + } + } + + mtl_lib = "genlib_$target_name" + metal_library(mtl_lib) { + name = invoker.name + sources = + filter_include(get_target_outputs(":$impellerc_mtl"), [ "*.metal" ]) + deps = [ ":$impellerc_mtl" ] + } + + reflect_mtl = "reflect_$target_name" + impellerc_reflect(reflect_mtl) { + impellerc_invocation = ":$impellerc_mtl" + } + + embed_mtl_lib = "embed_$target_name" + embed_blob(embed_mtl_lib) { + metal_library_files = get_target_outputs(":$mtl_lib") + symbol_name = shaders_base_name + blob = metal_library_files[0] + hdr = "$target_gen_dir/mtl/$shaders_base_name.h" + cc = "$target_gen_dir/mtl/$shaders_base_name.c" + deps = [ ":$mtl_lib" ] + } + + group(target_name) { + public_deps = [ + ":$embed_mtl_lib", + ":$reflect_mtl", ] - script = "//flutter/impeller/tools/xxd.py" - deps = [ ":$metal_library_target_name" ] } +} + +template("blobcat_library") { + assert(defined(invoker.shaders), + "The shaders to build the library from must be specified.") + assert(defined(invoker.deps), "Target dependencies must be specified.") + + output_file = "$target_gen_dir/$target_name.shaderblob" + compiled_action(target_name) { + tool = "//flutter/impeller/blobcat" + inputs = invoker.shaders + outputs = [ output_file ] + output_path_rebased = rebase_path(output_file, root_build_dir) + args = [ "--output=$output_path_rebased" ] + foreach(shader, invoker.shaders) { + shader_path = rebase_path(shader, root_out_dir) + args += [ "--input=$shader_path" ] + } + deps = invoker.deps + } +} + +template("impeller_shaders_gles") { + assert(defined(invoker.shaders), "Impeller shaders must be specified.") + assert(defined(invoker.name), "Name of the shader library must be specified.") - shader_embedded_data_target_name = "embedded_data_$target_name" - source_set(shader_embedded_data_target_name) { - sources = get_target_outputs(":$generate_embedder_data_sources") - deps = [ ":$generate_embedder_data_sources" ] + shaders_base_name = string_join("", + [ + invoker.name, + "_shaders_gles", + ]) + impellerc_gles = "impellerc_$target_name" + impellerc(impellerc_gles) { + shaders = invoker.shaders + sl_file_extension = "gles" + intermediates_subdir = "gles" + shader_target_flag = "--opengl-es" + defines = [ "IMPELLER_TARGET_OPENGLES" ] + } + + gles_lib = "genlib_$target_name" + blobcat_library(gles_lib) { + shaders = + filter_include(get_target_outputs(":$impellerc_gles"), [ "*.gles" ]) + deps = [ ":$impellerc_gles" ] + } + + reflect_gles = "reflect_$target_name" + impellerc_reflect(reflect_gles) { + impellerc_invocation = ":$impellerc_gles" + } + + embed_gles_lib = "embed_$target_name" + embed_blob(embed_gles_lib) { + gles_library_files = get_target_outputs(":$gles_lib") + symbol_name = shaders_base_name + blob = gles_library_files[0] + hdr = "$target_gen_dir/gles/$shaders_base_name.h" + cc = "$target_gen_dir/gles/$shaders_base_name.c" + deps = [ ":$gles_lib" ] } group(target_name) { public_deps = [ - ":$shader_embedded_data_target_name", - ":$shader_glue_target_name", + ":$embed_gles_lib", + ":$reflect_gles", ] } } -# ------------------------------------------------------------------------------ -# @brief Builds the shader library from shader sources, generates -# reflected shader information as source set, and, generates a -# translation unit added as a source set that allows embedding -# shaders into the final binary. On platforms where Impeller is -# not supported, this is a no-op. -# -# @note For additional information about parameters, see -# `impeller_shaders_real` -# -# @see impeller_shaders_real -# template("impeller_shaders") { - if (impeller_shaders_supports_platform) { - impeller_shaders_real(target_name) { - forward_variables_from(invoker, "*") + mtl_shaders = "mtl_$target_name" + impeller_shaders_metal(mtl_shaders) { + name = invoker.name + shaders = invoker.shaders + } + + gles_shaders = "gles_$target_name" + impeller_shaders_gles(gles_shaders) { + name = invoker.name + shaders = invoker.shaders + } + + group(target_name) { + public_deps = [] + if (impeller_enable_metal) { + public_deps += [ ":$mtl_shaders" ] } - } else { - group(target_name) { - not_needed(invoker, "*") + + if (impeller_enable_opengles) { + public_deps += [ ":$gles_shaders" ] } } }