From 05d77a51fe785820e9b011dc1cec83855beef749 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 4 May 2023 16:28:58 -0700 Subject: [PATCH 01/11] [Impeller] remove SDF code paths to test only --- impeller/entity/contents/content_context.cc | 2 - impeller/entity/contents/content_context.h | 10 -- impeller/entity/contents/text_contents.cc | 46 ++----- impeller/entity/contents/text_contents.h | 5 - impeller/entity/entity_unittests.cc | 28 ---- impeller/typographer/BUILD.gn | 2 + .../backends/skia/text_render_context_skia.cc | 123 ----------------- .../backends/skia/text_sdf_atlas.cc | 126 ++++++++++++++++++ .../backends/skia/text_sdf_atlas.h | 17 +++ impeller/typographer/glyph_atlas.h | 7 - impeller/typographer/typographer_unittests.cc | 27 ++++ 11 files changed, 181 insertions(+), 212 deletions(-) create mode 100644 impeller/typographer/backends/skia/text_sdf_atlas.cc create mode 100644 impeller/typographer/backends/skia/text_sdf_atlas.h diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index a8f1e8e54151b..48257e494006e 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -286,8 +286,6 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); glyph_atlas_pipelines_[{}] = CreateDefaultPipeline(*context_); - glyph_atlas_sdf_pipelines_[{}] = - CreateDefaultPipeline(*context_); geometry_color_pipelines_[{}] = CreateDefaultPipeline(*context_); yuv_to_rgb_filter_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 65941ceda19f4..971b0cc4b082b 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -32,8 +32,6 @@ #include "impeller/entity/conical_gradient_fill.frag.h" #include "impeller/entity/glyph_atlas.frag.h" #include "impeller/entity/glyph_atlas.vert.h" -#include "impeller/entity/glyph_atlas_sdf.frag.h" -#include "impeller/entity/glyph_atlas_sdf.vert.h" #include "impeller/entity/gradient_fill.vert.h" #include "impeller/entity/linear_gradient_fill.frag.h" #include "impeller/entity/linear_to_srgb_filter.frag.h" @@ -173,8 +171,6 @@ using SrgbToLinearFilterPipeline = SrgbToLinearFilterFragmentShader>; using GlyphAtlasPipeline = RenderPipelineT; -using GlyphAtlasSdfPipeline = - RenderPipelineT; using PorterDuffBlendPipeline = RenderPipelineT; // Instead of requiring new shaders for clips, the solid fill stages are used @@ -473,11 +469,6 @@ class ContentContext { return GetPipeline(glyph_atlas_pipelines_, opts); } - std::shared_ptr> GetGlyphAtlasSdfPipeline( - ContentContextOptions opts) const { - return GetPipeline(glyph_atlas_sdf_pipelines_, opts); - } - std::shared_ptr> GetGeometryColorPipeline( ContentContextOptions opts) const { return GetPipeline(geometry_color_pipelines_, opts); @@ -731,7 +722,6 @@ class ContentContext { mutable Variants srgb_to_linear_filter_pipelines_; mutable Variants clip_pipelines_; mutable Variants glyph_atlas_pipelines_; - mutable Variants glyph_atlas_sdf_pipelines_; mutable Variants geometry_color_pipelines_; mutable Variants yuv_to_rgb_filter_pipelines_; mutable Variants porter_duff_blend_pipelines_; diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index 6a4f0be4753c1..9e0662c242fee 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -74,7 +74,6 @@ std::optional TextContents::GetCoverage(const Entity& entity) const { return bounds->TransformBounds(entity.GetTransformation()); } -template static bool CommonRender( const ContentContext& renderer, const Entity& entity, @@ -85,11 +84,11 @@ static bool CommonRender( std::shared_ptr atlas, // NOLINT(performance-unnecessary-value-param) Command& cmd) { - using VS = typename TPipeline::VertexShader; - using FS = typename TPipeline::FragmentShader; + using VS = GlyphAtlasPipeline::VertexShader; + using FS = GlyphAtlasPipeline::FragmentShader; // Common vertex uniforms for all glyphs. - typename VS::FrameInfo frame_info; + VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); @@ -109,7 +108,7 @@ static bool CommonRender( } sampler_desc.mip_filter = MipFilter::kNearest; - typename FS::FragInfo frag_info; + FS::FragInfo frag_info; frag_info.text_color = ToVector(color.Premultiply()); FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info)); @@ -183,7 +182,7 @@ static bool CommonRender( .Round(); for (const auto& point : unit_points) { - typename VS::PerVertexData vtx; + VS::PerVertexData vtx; if (entity.GetTransformation().IsTranslationScaleOnly()) { // Rouding up here prevents the bounds from becoming 1 pixel too small @@ -199,11 +198,8 @@ static bool CommonRender( point * glyph_position.glyph.bounds.size); } vtx.uv = uv_origin + point * uv_size; - - if constexpr (std::is_same_v) { - vtx.has_color = - glyph_position.glyph.type == Glyph::Type::kBitmap ? 1.0 : 0.0; - } + vtx.has_color = + glyph_position.glyph.type == Glyph::Type::kBitmap ? 1.0 : 0.0; vertex_builder.AppendVertex(std::move(vtx)); } @@ -220,30 +216,6 @@ static bool CommonRender( return true; } -bool TextContents::RenderSdf(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - auto atlas = - ResolveAtlas(GlyphAtlas::Type::kSignedDistanceField, - renderer.GetGlyphAtlasContext(), renderer.GetContext()); - - if (!atlas || !atlas->IsValid()) { - VALIDATION_LOG << "Cannot render glyphs without prepared atlas."; - return false; - } - - // Information shared by all glyph draw calls. - Command cmd; - cmd.label = "TextFrameSDF"; - auto opts = OptionsFromPassAndEntity(pass, entity); - opts.primitive_type = PrimitiveType::kTriangle; - cmd.pipeline = renderer.GetGlyphAtlasSdfPipeline(opts); - cmd.stencil_reference = entity.GetStencilDepth(); - - return CommonRender(renderer, entity, pass, GetColor(), - frame_, offset_, atlas, cmd); -} - bool TextContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { @@ -276,8 +248,8 @@ bool TextContents::Render(const ContentContext& renderer, cmd.pipeline = renderer.GetGlyphAtlasPipeline(opts); cmd.stencil_reference = entity.GetStencilDepth(); - return CommonRender(renderer, entity, pass, color, frame_, - offset_, atlas, cmd); + return CommonRender(renderer, entity, pass, color, frame_, offset_, atlas, + cmd); } } // namespace impeller diff --git a/impeller/entity/contents/text_contents.h b/impeller/entity/contents/text_contents.h index b32f37258d91c..e313abad9b715 100644 --- a/impeller/entity/contents/text_contents.h +++ b/impeller/entity/contents/text_contents.h @@ -48,11 +48,6 @@ class TextContents final : public Contents { const Entity& entity, RenderPass& pass) const override; - // TODO(dnfield): remove this https://github.com/flutter/flutter/issues/111640 - bool RenderSdf(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const; - private: TextFrame frame_; Color color_; diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 007c6757a1696..77acc57dd912b 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -2151,34 +2151,6 @@ TEST_P(EntityTest, TTTBlendColor) { } } -TEST_P(EntityTest, SdfText) { - auto callback = [&](ContentContext& context, RenderPass& pass) -> bool { - SkFont font; - font.setSize(30); - auto blob = SkTextBlob::MakeFromString( - "the quick brown fox jumped over the lazy dog (but with sdf).", font); - auto frame = TextFrameFromTextBlob(blob); - auto lazy_glyph_atlas = std::make_shared(); - lazy_glyph_atlas->AddTextFrame(frame); - - EXPECT_FALSE(lazy_glyph_atlas->HasColor()); - - auto text_contents = std::make_shared(); - text_contents->SetTextFrame(frame); - text_contents->SetGlyphAtlas(std::move(lazy_glyph_atlas)); - text_contents->SetColor(Color(1.0, 0.0, 0.0, 1.0)); - Entity entity; - entity.SetTransformation( - Matrix::MakeTranslation(Vector3{200.0, 200.0, 0.0}) * - Matrix::MakeScale(GetContentScale())); - entity.SetContents(text_contents); - - // Force SDF rendering. - return text_contents->RenderSdf(context, entity, pass); - }; - ASSERT_TRUE(OpenPlaygroundHere(callback)); -} - TEST_P(EntityTest, AtlasContentsSubAtlas) { auto boston = CreateTextureForFixture("boston.jpg"); diff --git a/impeller/typographer/BUILD.gn b/impeller/typographer/BUILD.gn index 761b9af1e618c..95acdc59ab6f5 100644 --- a/impeller/typographer/BUILD.gn +++ b/impeller/typographer/BUILD.gn @@ -10,6 +10,8 @@ impeller_component("typographer") { "backends/skia/text_frame_skia.h", "backends/skia/text_render_context_skia.cc", "backends/skia/text_render_context_skia.h", + "backends/skia/text_sdf_atlas.cc", + "backends/skia/text_sdf_atlas.h", "backends/skia/typeface_skia.cc", "backends/skia/typeface_skia.h", "font.cc", diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/text_render_context_skia.cc index 51ec87b712d30..886674ea456f8 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -49,9 +49,6 @@ static FontGlyphPair::Set CollectUniqueFontGlyphPairs( while (const TextFrame* frame = frame_iterator()) { for (const TextRun& run : frame->GetRuns()) { const Font& font = run.GetFont(); - // TODO(dnfield): If we're doing SDF here, we should be using a consistent - // point size. - // https://github.com/flutter/flutter/issues/112016 for (const TextRun::GlyphPosition& glyph_position : run.GetGlyphPositions()) { set.insert({font, glyph_position.glyph}); @@ -171,121 +168,6 @@ ISize OptimumAtlasSizeForFontGlyphPairs( } } // namespace -/// Compute signed-distance field for an 8-bpp grayscale image (values greater -/// than 127 are considered "on") For details of this algorithm, see "The 'dead -/// reckoning' signed distance transform" [Grevera 2004] -static void ConvertBitmapToSignedDistanceField(uint8_t* pixels, - uint16_t width, - uint16_t height) { - if (!pixels || width == 0 || height == 0) { - return; - } - - using ShortPoint = TPoint; - - // distance to nearest boundary point map - std::vector distance_map(width * height); - // nearest boundary point map - std::vector boundary_point_map(width * height); - - // Some helpers for manipulating the above arrays -#define image(_x, _y) (pixels[(_y)*width + (_x)] > 0x7f) -#define distance(_x, _y) distance_map[(_y)*width + (_x)] -#define nearestpt(_x, _y) boundary_point_map[(_y)*width + (_x)] - - const Scalar maxDist = hypot(width, height); - const Scalar distUnit = 1; - const Scalar distDiag = sqrt(2); - - // Initialization phase: set all distances to "infinity"; zero out nearest - // boundary point map - for (uint16_t y = 0; y < height; ++y) { - for (uint16_t x = 0; x < width; ++x) { - distance(x, y) = maxDist; - nearestpt(x, y) = ShortPoint{0, 0}; - } - } - - // Immediate interior/exterior phase: mark all points along the boundary as - // such - for (uint16_t y = 1; y < height - 1; ++y) { - for (uint16_t x = 1; x < width - 1; ++x) { - bool inside = image(x, y); - if (image(x - 1, y) != inside || image(x + 1, y) != inside || - image(x, y - 1) != inside || image(x, y + 1) != inside) { - distance(x, y) = 0; - nearestpt(x, y) = ShortPoint{x, y}; - } - } - } - - // Forward dead-reckoning pass - for (uint16_t y = 1; y < height - 2; ++y) { - for (uint16_t x = 1; x < width - 2; ++x) { - if (distance_map[(y - 1) * width + (x - 1)] + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x - 1, y - 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x, y - 1) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x, y - 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x + 1, y - 1) + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x + 1, y - 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x - 1, y) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x - 1, y); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - } - } - - // Backward dead-reckoning pass - for (uint16_t y = height - 2; y >= 1; --y) { - for (uint16_t x = width - 2; x >= 1; --x) { - if (distance(x + 1, y) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x + 1, y); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x - 1, y + 1) + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x - 1, y + 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x, y + 1) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x, y + 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x + 1, y + 1) + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x + 1, y + 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - } - } - - // Interior distance negation pass; distances outside the figure are - // considered negative - // Also does final quantization. - for (uint16_t y = 0; y < height; ++y) { - for (uint16_t x = 0; x < width; ++x) { - if (!image(x, y)) { - distance(x, y) = -distance(x, y); - } - - float norm_factor = 13.5; - float dist = distance(x, y); - float clamped_dist = fmax(-norm_factor, fmin(dist, norm_factor)); - float scaled_dist = clamped_dist / norm_factor; - uint8_t quantized_value = ((scaled_dist + 1) / 2) * UINT8_MAX; - pixels[y * width + x] = quantized_value; - } - } - -#undef image -#undef distance -#undef nearestpt -} - static void DrawGlyph(SkCanvas* canvas, const FontGlyphPair& font_glyph, const Rect& location, @@ -353,7 +235,6 @@ static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, SkImageInfo image_info; switch (atlas.GetType()) { - case GlyphAtlas::Type::kSignedDistanceField: case GlyphAtlas::Type::kAlphaBitmap: image_info = SkImageInfo::MakeA8(atlas_size.width, atlas_size.height); break; @@ -563,10 +444,6 @@ std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( // --------------------------------------------------------------------------- PixelFormat format; switch (type) { - case GlyphAtlas::Type::kSignedDistanceField: - ConvertBitmapToSignedDistanceField( - reinterpret_cast(bitmap->getPixels()), atlas_size.width, - atlas_size.height); case GlyphAtlas::Type::kAlphaBitmap: format = PixelFormat::kA8UNormInt; break; diff --git a/impeller/typographer/backends/skia/text_sdf_atlas.cc b/impeller/typographer/backends/skia/text_sdf_atlas.cc new file mode 100644 index 0000000000000..fab23d17acf1b --- /dev/null +++ b/impeller/typographer/backends/skia/text_sdf_atlas.cc @@ -0,0 +1,126 @@ +// 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/typographer/backends/skia/text_sdf_atlas.h" + +#include + +#include "impeller/geometry/point.h" +#include "impeller/geometry/scalar.h" + +namespace impeller { + +void ConvertBitmapToSignedDistanceField(uint8_t* pixels, + uint16_t width, + uint16_t height) { + if (!pixels || width == 0 || height == 0) { + return; + } + + using ShortPoint = TPoint; + + // distance to nearest boundary point map + std::vector distance_map(width * height); + // nearest boundary point map + std::vector boundary_point_map(width * height); + + // Some helpers for manipulating the above arrays +#define image(_x, _y) (pixels[(_y)*width + (_x)] > 0x7f) +#define distance(_x, _y) distance_map[(_y)*width + (_x)] +#define nearestpt(_x, _y) boundary_point_map[(_y)*width + (_x)] + + const Scalar maxDist = hypot(width, height); + const Scalar distUnit = 1; + const Scalar distDiag = sqrt(2); + + // Initialization phase: set all distances to "infinity"; zero out nearest + // boundary point map + for (uint16_t y = 0; y < height; ++y) { + for (uint16_t x = 0; x < width; ++x) { + distance(x, y) = maxDist; + nearestpt(x, y) = ShortPoint{0, 0}; + } + } + + // Immediate interior/exterior phase: mark all points along the boundary as + // such + for (uint16_t y = 1; y < height - 1; ++y) { + for (uint16_t x = 1; x < width - 1; ++x) { + bool inside = image(x, y); + if (image(x - 1, y) != inside || image(x + 1, y) != inside || + image(x, y - 1) != inside || image(x, y + 1) != inside) { + distance(x, y) = 0; + nearestpt(x, y) = ShortPoint{x, y}; + } + } + } + + // Forward dead-reckoning pass + for (uint16_t y = 1; y < height - 2; ++y) { + for (uint16_t x = 1; x < width - 2; ++x) { + if (distance_map[(y - 1) * width + (x - 1)] + distDiag < distance(x, y)) { + nearestpt(x, y) = nearestpt(x - 1, y - 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x, y - 1) + distUnit < distance(x, y)) { + nearestpt(x, y) = nearestpt(x, y - 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x + 1, y - 1) + distDiag < distance(x, y)) { + nearestpt(x, y) = nearestpt(x + 1, y - 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x - 1, y) + distUnit < distance(x, y)) { + nearestpt(x, y) = nearestpt(x - 1, y); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + } + } + + // Backward dead-reckoning pass + for (uint16_t y = height - 2; y >= 1; --y) { + for (uint16_t x = width - 2; x >= 1; --x) { + if (distance(x + 1, y) + distUnit < distance(x, y)) { + nearestpt(x, y) = nearestpt(x + 1, y); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x - 1, y + 1) + distDiag < distance(x, y)) { + nearestpt(x, y) = nearestpt(x - 1, y + 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x, y + 1) + distUnit < distance(x, y)) { + nearestpt(x, y) = nearestpt(x, y + 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x + 1, y + 1) + distDiag < distance(x, y)) { + nearestpt(x, y) = nearestpt(x + 1, y + 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + } + } + + // Interior distance negation pass; distances outside the figure are + // considered negative + // Also does final quantization. + for (uint16_t y = 0; y < height; ++y) { + for (uint16_t x = 0; x < width; ++x) { + if (!image(x, y)) { + distance(x, y) = -distance(x, y); + } + + float norm_factor = 13.5; + float dist = distance(x, y); + float clamped_dist = fmax(-norm_factor, fmin(dist, norm_factor)); + float scaled_dist = clamped_dist / norm_factor; + uint8_t quantized_value = ((scaled_dist + 1) / 2) * UINT8_MAX; + pixels[y * width + x] = quantized_value; + } + } + +#undef image +#undef distance +#undef nearestpt +} + +} // namespace impeller diff --git a/impeller/typographer/backends/skia/text_sdf_atlas.h b/impeller/typographer/backends/skia/text_sdf_atlas.h new file mode 100644 index 0000000000000..1831b2db625f7 --- /dev/null +++ b/impeller/typographer/backends/skia/text_sdf_atlas.h @@ -0,0 +1,17 @@ +// 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 + +namespace impeller { + +/// Compute signed-distance field for an 8-bpp grayscale image (values greater +/// than 127 are considered "on") For details of this algorithm, see "The 'dead +/// reckoning' signed distance transform" [Grevera 2004] +void ConvertBitmapToSignedDistanceField(uint8_t* pixels, + uint16_t width, + uint16_t height); +} // namespace impeller diff --git a/impeller/typographer/glyph_atlas.h b/impeller/typographer/glyph_atlas.h index e7282a0cdb6a0..e8f2cbe451309 100644 --- a/impeller/typographer/glyph_atlas.h +++ b/impeller/typographer/glyph_atlas.h @@ -32,13 +32,6 @@ class GlyphAtlas { //---------------------------------------------------------------------------- /// @brief Describes how the glyphs are represented in the texture. enum class Type { - //-------------------------------------------------------------------------- - /// The glyphs are represented at a fixed size in an 8-bit grayscale texture - /// where the value of each pixel represents a signed-distance field that - /// stores the glyph outlines. - /// - kSignedDistanceField, - //-------------------------------------------------------------------------- /// The glyphs are reprsented at their requested size using only an 8-bit /// alpha channel. diff --git a/impeller/typographer/typographer_unittests.cc b/impeller/typographer/typographer_unittests.cc index 445cc283fe6c7..f9b1ce7993981 100644 --- a/impeller/typographer/typographer_unittests.cc +++ b/impeller/typographer/typographer_unittests.cc @@ -6,7 +6,9 @@ #include "impeller/playground/playground_test.h" #include "impeller/typographer/backends/skia/text_frame_skia.h" #include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include "impeller/typographer/backends/skia/text_sdf_atlas.h" #include "impeller/typographer/lazy_glyph_atlas.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkTextBlob.h" @@ -282,5 +284,30 @@ TEST_P(TypographerTest, MaybeHasOverlapping) { ASSERT_TRUE(frame_2.MaybeHasOverlapping()); } +TEST_P(TypographerTest, ValidateSDFFunctions) { + auto context = TextRenderContext::Create(GetContext()); + auto atlas_context = std::make_shared(); + + SkFont sk_font; + auto blob = SkTextBlob::MakeFromString("spooky 1", sk_font); + ASSERT_TRUE(blob); + + auto atlas = + context->CreateGlyphAtlas(GlyphAtlas::Type::kAlphaBitmap, atlas_context, + TextFrameFromTextBlob(blob)); + + auto pixels = + reinterpret_cast(atlas_context->GetBitmap()->getPixels()); + auto atlas_size = atlas_context->GetAtlasSize(); + ConvertBitmapToSignedDistanceField(pixels, atlas_size.width, + atlas_size.height); + // Validate that there is at least one non-zero pixel. + bool non_zero = false; + for (auto i = 0u; i < atlas_size.width * atlas_size.height; i++) { + non_zero |= pixels[i] != 0u; + } + ASSERT_TRUE(non_zero); +} + } // namespace testing } // namespace impeller From 5a7ecc46beed2154cc00498a84ec5c43a7d0673f Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 4 May 2023 16:42:59 -0700 Subject: [PATCH 02/11] license --- ci/licenses_golden/licenses_flutter | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index ffcb36dbe7f3f..b0cd03d0a52ee 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1648,6 +1648,8 @@ ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.cc + ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_sdf_atlas.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_sdf_atlas.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/font.cc + ../../../flutter/LICENSE @@ -4243,6 +4245,8 @@ FILE: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.cc FILE: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.h FILE: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.cc FILE: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.h +FILE: ../../../flutter/impeller/typographer/backends/skia/text_sdf_atlas.cc +FILE: ../../../flutter/impeller/typographer/backends/skia/text_sdf_atlas.h FILE: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.cc FILE: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.h FILE: ../../../flutter/impeller/typographer/font.cc From f24aa9adc7eafa1016429ca5655dd5c9ed4f809b Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 4 May 2023 21:12:44 -0700 Subject: [PATCH 03/11] ++ --- ci/licenses_golden/licenses_flutter | 4 - impeller/typographer/BUILD.gn | 2 - .../backends/skia/text_sdf_atlas.cc | 126 ------------------ .../backends/skia/text_sdf_atlas.h | 17 --- impeller/typographer/typographer_unittests.cc | 26 ---- 5 files changed, 175 deletions(-) delete mode 100644 impeller/typographer/backends/skia/text_sdf_atlas.cc delete mode 100644 impeller/typographer/backends/skia/text_sdf_atlas.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b0cd03d0a52ee..ffcb36dbe7f3f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1648,8 +1648,6 @@ ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.cc + ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_sdf_atlas.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_sdf_atlas.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/font.cc + ../../../flutter/LICENSE @@ -4245,8 +4243,6 @@ FILE: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.cc FILE: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.h FILE: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.cc FILE: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.h -FILE: ../../../flutter/impeller/typographer/backends/skia/text_sdf_atlas.cc -FILE: ../../../flutter/impeller/typographer/backends/skia/text_sdf_atlas.h FILE: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.cc FILE: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.h FILE: ../../../flutter/impeller/typographer/font.cc diff --git a/impeller/typographer/BUILD.gn b/impeller/typographer/BUILD.gn index 95acdc59ab6f5..761b9af1e618c 100644 --- a/impeller/typographer/BUILD.gn +++ b/impeller/typographer/BUILD.gn @@ -10,8 +10,6 @@ impeller_component("typographer") { "backends/skia/text_frame_skia.h", "backends/skia/text_render_context_skia.cc", "backends/skia/text_render_context_skia.h", - "backends/skia/text_sdf_atlas.cc", - "backends/skia/text_sdf_atlas.h", "backends/skia/typeface_skia.cc", "backends/skia/typeface_skia.h", "font.cc", diff --git a/impeller/typographer/backends/skia/text_sdf_atlas.cc b/impeller/typographer/backends/skia/text_sdf_atlas.cc deleted file mode 100644 index fab23d17acf1b..0000000000000 --- a/impeller/typographer/backends/skia/text_sdf_atlas.cc +++ /dev/null @@ -1,126 +0,0 @@ -// 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/typographer/backends/skia/text_sdf_atlas.h" - -#include - -#include "impeller/geometry/point.h" -#include "impeller/geometry/scalar.h" - -namespace impeller { - -void ConvertBitmapToSignedDistanceField(uint8_t* pixels, - uint16_t width, - uint16_t height) { - if (!pixels || width == 0 || height == 0) { - return; - } - - using ShortPoint = TPoint; - - // distance to nearest boundary point map - std::vector distance_map(width * height); - // nearest boundary point map - std::vector boundary_point_map(width * height); - - // Some helpers for manipulating the above arrays -#define image(_x, _y) (pixels[(_y)*width + (_x)] > 0x7f) -#define distance(_x, _y) distance_map[(_y)*width + (_x)] -#define nearestpt(_x, _y) boundary_point_map[(_y)*width + (_x)] - - const Scalar maxDist = hypot(width, height); - const Scalar distUnit = 1; - const Scalar distDiag = sqrt(2); - - // Initialization phase: set all distances to "infinity"; zero out nearest - // boundary point map - for (uint16_t y = 0; y < height; ++y) { - for (uint16_t x = 0; x < width; ++x) { - distance(x, y) = maxDist; - nearestpt(x, y) = ShortPoint{0, 0}; - } - } - - // Immediate interior/exterior phase: mark all points along the boundary as - // such - for (uint16_t y = 1; y < height - 1; ++y) { - for (uint16_t x = 1; x < width - 1; ++x) { - bool inside = image(x, y); - if (image(x - 1, y) != inside || image(x + 1, y) != inside || - image(x, y - 1) != inside || image(x, y + 1) != inside) { - distance(x, y) = 0; - nearestpt(x, y) = ShortPoint{x, y}; - } - } - } - - // Forward dead-reckoning pass - for (uint16_t y = 1; y < height - 2; ++y) { - for (uint16_t x = 1; x < width - 2; ++x) { - if (distance_map[(y - 1) * width + (x - 1)] + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x - 1, y - 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x, y - 1) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x, y - 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x + 1, y - 1) + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x + 1, y - 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x - 1, y) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x - 1, y); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - } - } - - // Backward dead-reckoning pass - for (uint16_t y = height - 2; y >= 1; --y) { - for (uint16_t x = width - 2; x >= 1; --x) { - if (distance(x + 1, y) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x + 1, y); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x - 1, y + 1) + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x - 1, y + 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x, y + 1) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x, y + 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x + 1, y + 1) + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x + 1, y + 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - } - } - - // Interior distance negation pass; distances outside the figure are - // considered negative - // Also does final quantization. - for (uint16_t y = 0; y < height; ++y) { - for (uint16_t x = 0; x < width; ++x) { - if (!image(x, y)) { - distance(x, y) = -distance(x, y); - } - - float norm_factor = 13.5; - float dist = distance(x, y); - float clamped_dist = fmax(-norm_factor, fmin(dist, norm_factor)); - float scaled_dist = clamped_dist / norm_factor; - uint8_t quantized_value = ((scaled_dist + 1) / 2) * UINT8_MAX; - pixels[y * width + x] = quantized_value; - } - } - -#undef image -#undef distance -#undef nearestpt -} - -} // namespace impeller diff --git a/impeller/typographer/backends/skia/text_sdf_atlas.h b/impeller/typographer/backends/skia/text_sdf_atlas.h deleted file mode 100644 index 1831b2db625f7..0000000000000 --- a/impeller/typographer/backends/skia/text_sdf_atlas.h +++ /dev/null @@ -1,17 +0,0 @@ -// 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 - -namespace impeller { - -/// Compute signed-distance field for an 8-bpp grayscale image (values greater -/// than 127 are considered "on") For details of this algorithm, see "The 'dead -/// reckoning' signed distance transform" [Grevera 2004] -void ConvertBitmapToSignedDistanceField(uint8_t* pixels, - uint16_t width, - uint16_t height); -} // namespace impeller diff --git a/impeller/typographer/typographer_unittests.cc b/impeller/typographer/typographer_unittests.cc index f9b1ce7993981..b35e3d7eca6a3 100644 --- a/impeller/typographer/typographer_unittests.cc +++ b/impeller/typographer/typographer_unittests.cc @@ -6,7 +6,6 @@ #include "impeller/playground/playground_test.h" #include "impeller/typographer/backends/skia/text_frame_skia.h" #include "impeller/typographer/backends/skia/text_render_context_skia.h" -#include "impeller/typographer/backends/skia/text_sdf_atlas.h" #include "impeller/typographer/lazy_glyph_atlas.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkData.h" @@ -284,30 +283,5 @@ TEST_P(TypographerTest, MaybeHasOverlapping) { ASSERT_TRUE(frame_2.MaybeHasOverlapping()); } -TEST_P(TypographerTest, ValidateSDFFunctions) { - auto context = TextRenderContext::Create(GetContext()); - auto atlas_context = std::make_shared(); - - SkFont sk_font; - auto blob = SkTextBlob::MakeFromString("spooky 1", sk_font); - ASSERT_TRUE(blob); - - auto atlas = - context->CreateGlyphAtlas(GlyphAtlas::Type::kAlphaBitmap, atlas_context, - TextFrameFromTextBlob(blob)); - - auto pixels = - reinterpret_cast(atlas_context->GetBitmap()->getPixels()); - auto atlas_size = atlas_context->GetAtlasSize(); - ConvertBitmapToSignedDistanceField(pixels, atlas_size.width, - atlas_size.height); - // Validate that there is at least one non-zero pixel. - bool non_zero = false; - for (auto i = 0u; i < atlas_size.width * atlas_size.height; i++) { - non_zero |= pixels[i] != 0u; - } - ASSERT_TRUE(non_zero); -} - } // namespace testing } // namespace impeller From 2585a55b302b98c94386626e44f45cca4df5b8eb Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 5 May 2023 09:27:31 -0700 Subject: [PATCH 04/11] fix std move errors --- impeller/entity/contents/text_contents.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index 9e0662c242fee..1fba560b176f2 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -201,13 +201,13 @@ static bool CommonRender( vtx.has_color = glyph_position.glyph.type == Glyph::Type::kBitmap ? 1.0 : 0.0; - vertex_builder.AppendVertex(std::move(vtx)); + vertex_builder.AppendVertex(vtx); } } } auto vertex_buffer = vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer()); - cmd.BindVertices(std::move(vertex_buffer)); + cmd.BindVertices(vertex_buffer); if (!pass.AddCommand(cmd)) { return false; From ef1cb69d05a0926c792a1247e4f49e95d748ab3b Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 5 May 2023 11:26:56 -0700 Subject: [PATCH 05/11] [Impeller] use separate color and alpha atlases and shaders --- impeller/entity/BUILD.gn | 3 +- impeller/entity/contents/content_context.cc | 12 ++++-- impeller/entity/contents/content_context.h | 15 ++++++- impeller/entity/contents/text_contents.cc | 39 +++++++------------ impeller/entity/shaders/glyph_atlas.frag | 15 +++---- impeller/entity/shaders/glyph_atlas.vert | 5 +-- .../entity/shaders/glyph_atlas_color.frag | 21 ++++++++++ impeller/entity/shaders/glyph_atlas_sdf.frag | 35 ----------------- impeller/entity/shaders/glyph_atlas_sdf.vert | 22 ----------- impeller/typographer/lazy_glyph_atlas.cc | 17 ++++---- impeller/typographer/lazy_glyph_atlas.h | 6 +-- impeller/typographer/text_frame.cc | 5 ++- impeller/typographer/text_frame.h | 5 ++- impeller/typographer/typographer_unittests.cc | 18 ++++++--- 14 files changed, 93 insertions(+), 125 deletions(-) create mode 100644 impeller/entity/shaders/glyph_atlas_color.frag delete mode 100644 impeller/entity/shaders/glyph_atlas_sdf.frag delete mode 100644 impeller/entity/shaders/glyph_atlas_sdf.vert diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 91ffdae65d58b..0cfde08d51875 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -43,9 +43,8 @@ impeller_shaders("entity_shaders") { "shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag", "shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag", "shaders/glyph_atlas.frag", + "shaders/glyph_atlas_color.frag", "shaders/glyph_atlas.vert", - "shaders/glyph_atlas_sdf.frag", - "shaders/glyph_atlas_sdf.vert", "shaders/gradient_fill.vert", "shaders/linear_to_srgb_filter.frag", "shaders/linear_to_srgb_filter.vert", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 48257e494006e..4503b40cdbe6f 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -164,7 +164,8 @@ static std::unique_ptr CreateDefaultPipeline( ContentContext::ContentContext(std::shared_ptr context) : context_(std::move(context)), tessellator_(std::make_shared()), - glyph_atlas_context_(std::make_shared()), + alpha_glyph_atlas_context_(std::make_shared()), + color_glyph_atlas_context_(std::make_shared()), scene_context_(std::make_shared(context_)) { if (!context_ || !context_->IsValid()) { return; @@ -286,6 +287,8 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); glyph_atlas_pipelines_[{}] = CreateDefaultPipeline(*context_); + glyph_atlas_color_pipelines_[{}] = + CreateDefaultPipeline(*context_); geometry_color_pipelines_[{}] = CreateDefaultPipeline(*context_); yuv_to_rgb_filter_pipelines_[{}] = @@ -378,9 +381,10 @@ std::shared_ptr ContentContext::GetTessellator() const { return tessellator_; } -std::shared_ptr ContentContext::GetGlyphAtlasContext() - const { - return glyph_atlas_context_; +std::shared_ptr ContentContext::GetGlyphAtlasContext( + GlyphAtlas::Type type) const { + return type == GlyphAtlas::Type::kAlphaBitmap ? alpha_glyph_atlas_context_ + : color_glyph_atlas_context_; } std::shared_ptr ContentContext::GetContext() const { diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 971b0cc4b082b..5042ff54ff187 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -32,6 +32,7 @@ #include "impeller/entity/conical_gradient_fill.frag.h" #include "impeller/entity/glyph_atlas.frag.h" #include "impeller/entity/glyph_atlas.vert.h" +#include "impeller/entity/glyph_atlas_color.frag.h" #include "impeller/entity/gradient_fill.vert.h" #include "impeller/entity/linear_gradient_fill.frag.h" #include "impeller/entity/linear_to_srgb_filter.frag.h" @@ -171,6 +172,8 @@ using SrgbToLinearFilterPipeline = SrgbToLinearFilterFragmentShader>; using GlyphAtlasPipeline = RenderPipelineT; +using GlyphAtlasColorPipeline = + RenderPipelineT; using PorterDuffBlendPipeline = RenderPipelineT; // Instead of requiring new shaders for clips, the solid fill stages are used @@ -469,6 +472,11 @@ class ContentContext { return GetPipeline(glyph_atlas_pipelines_, opts); } + std::shared_ptr> GetGlyphAtlasColorPipeline( + ContentContextOptions opts) const { + return GetPipeline(glyph_atlas_color_pipelines_, opts); + } + std::shared_ptr> GetGeometryColorPipeline( ContentContextOptions opts) const { return GetPipeline(geometry_color_pipelines_, opts); @@ -654,7 +662,8 @@ class ContentContext { std::shared_ptr GetContext() const; - std::shared_ptr GetGlyphAtlasContext() const; + std::shared_ptr GetGlyphAtlasContext( + GlyphAtlas::Type type) const; const Capabilities& GetDeviceCapabilities() const; @@ -722,6 +731,7 @@ class ContentContext { mutable Variants srgb_to_linear_filter_pipelines_; mutable Variants clip_pipelines_; mutable Variants glyph_atlas_pipelines_; + mutable Variants glyph_atlas_color_pipelines_; mutable Variants geometry_color_pipelines_; mutable Variants yuv_to_rgb_filter_pipelines_; mutable Variants porter_duff_blend_pipelines_; @@ -813,7 +823,8 @@ class ContentContext { bool is_valid_ = false; std::shared_ptr tessellator_; - std::shared_ptr glyph_atlas_context_; + std::shared_ptr alpha_glyph_atlas_context_; + std::shared_ptr color_glyph_atlas_context_; std::shared_ptr scene_context_; bool wireframe_ = false; diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index 1fba560b176f2..dfb52a030ebd1 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -84,15 +84,6 @@ static bool CommonRender( std::shared_ptr atlas, // NOLINT(performance-unnecessary-value-param) Command& cmd) { - using VS = GlyphAtlasPipeline::VertexShader; - using FS = GlyphAtlasPipeline::FragmentShader; - - // Common vertex uniforms for all glyphs. - VS::FrameInfo frame_info; - - frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); - VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); - SamplerDescriptor sampler_desc; if (entity.GetTransformation().IsTranslationScaleOnly()) { sampler_desc.min_filter = MinMagFilter::kNearest; @@ -108,11 +99,17 @@ static bool CommonRender( } sampler_desc.mip_filter = MipFilter::kNearest; + using VS = GlyphAtlasPipeline::VertexShader; + using FS = GlyphAtlasPipeline::FragmentShader; + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + FS::FragInfo frag_info; frag_info.text_color = ToVector(color.Premultiply()); FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info)); - // Common fragment uniforms for all glyphs. FS::BindGlyphAtlasSampler( cmd, // command atlas->GetTexture(), // texture @@ -198,9 +195,6 @@ static bool CommonRender( point * glyph_position.glyph.bounds.size); } vtx.uv = uv_origin + point * uv_size; - vtx.has_color = - glyph_position.glyph.type == Glyph::Type::kBitmap ? 1.0 : 0.0; - vertex_builder.AppendVertex(vtx); } } @@ -224,16 +218,9 @@ bool TextContents::Render(const ContentContext& renderer, return true; } - // This TextContents may be for a frame that doesn't have color, but the - // lazy atlas for this scene already does have color. - // Benchmarks currently show that creating two atlases per pass regresses - // render time. This should get re-evaluated if we start caching atlases - // between frames or get significantly faster at creating atlases, because - // we're potentially trading memory for time here. - auto atlas = - ResolveAtlas(lazy_atlas_->HasColor() ? GlyphAtlas::Type::kColorBitmap - : GlyphAtlas::Type::kAlphaBitmap, - renderer.GetGlyphAtlasContext(), renderer.GetContext()); + auto type = frame_.GetAtlasType(); + auto atlas = ResolveAtlas(type, renderer.GetGlyphAtlasContext(type), + renderer.GetContext()); if (!atlas || !atlas->IsValid()) { VALIDATION_LOG << "Cannot render glyphs without prepared atlas."; @@ -245,7 +232,11 @@ bool TextContents::Render(const ContentContext& renderer, cmd.label = "TextFrame"; auto opts = OptionsFromPassAndEntity(pass, entity); opts.primitive_type = PrimitiveType::kTriangle; - cmd.pipeline = renderer.GetGlyphAtlasPipeline(opts); + if (type == GlyphAtlas::Type::kAlphaBitmap) { + cmd.pipeline = renderer.GetGlyphAtlasPipeline(opts); + } else { + cmd.pipeline = renderer.GetGlyphAtlasColorPipeline(opts); + } cmd.stencil_reference = entity.GetStencilDepth(); return CommonRender(renderer, entity, pass, color, frame_, offset_, atlas, diff --git a/impeller/entity/shaders/glyph_atlas.frag b/impeller/entity/shaders/glyph_atlas.frag index adb1a48f507e7..21b26c976b646 100644 --- a/impeller/entity/shaders/glyph_atlas.frag +++ b/impeller/entity/shaders/glyph_atlas.frag @@ -4,23 +4,18 @@ #include -uniform sampler2D glyph_atlas_sampler; +uniform f16sampler2D glyph_atlas_sampler; uniform FragInfo { - vec4 text_color; + f16vec4 text_color; } frag_info; in vec2 v_uv; -in float v_has_color; -out vec4 frag_color; +out f16vec4 frag_color; void main() { - vec4 value = texture(glyph_atlas_sampler, v_uv); - if (v_has_color != 1.0) { - frag_color = value.aaaa * frag_info.text_color; - } else { - frag_color = value * frag_info.text_color.a; - } + f16vec4 value = texture(glyph_atlas_sampler, v_uv); + frag_color = value.aaaa * frag_info.text_color; } diff --git a/impeller/entity/shaders/glyph_atlas.vert b/impeller/entity/shaders/glyph_atlas.vert index c15ceddaf25c0..3cf2ce7d88854 100644 --- a/impeller/entity/shaders/glyph_atlas.vert +++ b/impeller/entity/shaders/glyph_atlas.vert @@ -10,15 +10,12 @@ uniform FrameInfo { } frame_info; -in vec4 position; +in highp vec4 position; in vec2 uv; -in float has_color; out vec2 v_uv; -out float v_has_color; void main() { gl_Position = frame_info.mvp * position; v_uv = uv; - v_has_color = has_color; } diff --git a/impeller/entity/shaders/glyph_atlas_color.frag b/impeller/entity/shaders/glyph_atlas_color.frag new file mode 100644 index 0000000000000..ded0a3d618e3d --- /dev/null +++ b/impeller/entity/shaders/glyph_atlas_color.frag @@ -0,0 +1,21 @@ +// 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 + +uniform f16sampler2D glyph_atlas_sampler; + +uniform FragInfo { + f16vec4 text_color; +} +frag_info; + +in vec2 v_uv; + +out f16vec4 frag_color; + +void main() { + f16vec4 value = texture(glyph_atlas_sampler, v_uv); + frag_color = value * frag_info.text_color.aaaa; +} diff --git a/impeller/entity/shaders/glyph_atlas_sdf.frag b/impeller/entity/shaders/glyph_atlas_sdf.frag deleted file mode 100644 index 2c45e7072c385..0000000000000 --- a/impeller/entity/shaders/glyph_atlas_sdf.frag +++ /dev/null @@ -1,35 +0,0 @@ -// 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 - -uniform sampler2D glyph_atlas_sampler; - -uniform FragInfo { - vec4 text_color; -} -frag_info; - -in vec2 v_uv; - -out vec4 frag_color; - -void main() { - // Inspired by Metal by Example's SDF text rendering shader: - // https://github.com/metal-by-example/sample-code/blob/master/objc/12-TextRendering/TextRendering/Shaders.metal - - // Outline of glyph is the isocontour with value 50% - float edge_distance = 0.5; - // Sample the signed-distance field to find distance from this fragment to the - // glyph outline - float sample_distance = texture(glyph_atlas_sampler, v_uv).a; - // Use local automatic gradients to find anti-aliased anisotropic edge width, - // cf. Gustavson 2012 - float edge_width = length(vec2(dFdx(sample_distance), dFdy(sample_distance))); - // Smooth the glyph edge by interpolating across the boundary in a band with - // the width determined above - float insideness = smoothstep(edge_distance - edge_width, - edge_distance + edge_width, sample_distance); - frag_color = frag_info.text_color * insideness; -} diff --git a/impeller/entity/shaders/glyph_atlas_sdf.vert b/impeller/entity/shaders/glyph_atlas_sdf.vert deleted file mode 100644 index f859eea762ab6..0000000000000 --- a/impeller/entity/shaders/glyph_atlas_sdf.vert +++ /dev/null @@ -1,22 +0,0 @@ -// 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 - -uniform FrameInfo { - mat4 mvp; -} -frame_info; - -in vec4 position; -in vec2 uv; - -out vec2 v_uv; - -void main() { - gl_Position = frame_info.mvp * position; - v_uv = uv; -} diff --git a/impeller/typographer/lazy_glyph_atlas.cc b/impeller/typographer/lazy_glyph_atlas.cc index 3e415716a528c..d88f0d9b6c577 100644 --- a/impeller/typographer/lazy_glyph_atlas.cc +++ b/impeller/typographer/lazy_glyph_atlas.cc @@ -18,12 +18,11 @@ LazyGlyphAtlas::~LazyGlyphAtlas() = default; void LazyGlyphAtlas::AddTextFrame(const TextFrame& frame) { FML_DCHECK(atlas_map_.empty()); - has_color_ |= frame.HasColor(); - frames_.emplace_back(frame); -} - -bool LazyGlyphAtlas::HasColor() const { - return has_color_; + if (frame.GetAtlasType() == GlyphAtlas::Type::kAlphaBitmap) { + alpha_frames_.emplace_back(frame); + } else { + color_frames_.emplace_back(frame); + } } std::shared_ptr LazyGlyphAtlas::CreateOrGetGlyphAtlas( @@ -42,11 +41,13 @@ std::shared_ptr LazyGlyphAtlas::CreateOrGetGlyphAtlas( return nullptr; } size_t i = 0; + auto frames = + type == GlyphAtlas::Type::kAlphaBitmap ? alpha_frames_ : color_frames_; TextRenderContext::FrameIterator iterator = [&]() -> const TextFrame* { - if (i >= frames_.size()) { + if (i >= frames.size()) { return nullptr; } - const auto& result = frames_[i]; + const auto& result = frames[i]; i++; return &result; }; diff --git a/impeller/typographer/lazy_glyph_atlas.h b/impeller/typographer/lazy_glyph_atlas.h index 841bb4f2e0e46..067601e65e64f 100644 --- a/impeller/typographer/lazy_glyph_atlas.h +++ b/impeller/typographer/lazy_glyph_atlas.h @@ -26,13 +26,11 @@ class LazyGlyphAtlas { std::shared_ptr atlas_context, std::shared_ptr context) const; - bool HasColor() const; - private: - std::vector frames_; + std::vector alpha_frames_; + std::vector color_frames_; mutable std::unordered_map> atlas_map_; - bool has_color_ = false; FML_DISALLOW_COPY_AND_ASSIGN(LazyGlyphAtlas); }; diff --git a/impeller/typographer/text_frame.cc b/impeller/typographer/text_frame.cc index d7c241b899283..ed3c97cc82b3e 100644 --- a/impeller/typographer/text_frame.cc +++ b/impeller/typographer/text_frame.cc @@ -42,8 +42,9 @@ const std::vector& TextFrame::GetRuns() const { return runs_; } -bool TextFrame::HasColor() const { - return has_color_; +GlyphAtlas::Type TextFrame::GetAtlasType() const { + return has_color_ ? GlyphAtlas::Type::kColorBitmap + : GlyphAtlas::Type::kAlphaBitmap; } bool TextFrame::MaybeHasOverlapping() const { diff --git a/impeller/typographer/text_frame.h b/impeller/typographer/text_frame.h index e43af08b2d6ea..a47e4c0e2252a 100644 --- a/impeller/typographer/text_frame.h +++ b/impeller/typographer/text_frame.h @@ -5,6 +5,7 @@ #pragma once #include "flutter/fml/macros.h" +#include "impeller/typographer/glyph_atlas.h" #include "impeller/typographer/text_run.h" namespace impeller { @@ -63,8 +64,8 @@ class TextFrame { bool MaybeHasOverlapping() const; //---------------------------------------------------------------------------- - /// @brief Whether any run in this frame has color. - bool HasColor() const; + /// @brief The type of atlas this run should be emplaced in. + GlyphAtlas::Type GetAtlasType() const; private: std::vector runs_; diff --git a/impeller/typographer/typographer_unittests.cc b/impeller/typographer/typographer_unittests.cc index b35e3d7eca6a3..31c649fab0d4c 100644 --- a/impeller/typographer/typographer_unittests.cc +++ b/impeller/typographer/typographer_unittests.cc @@ -92,22 +92,28 @@ TEST_P(TypographerTest, LazyAtlasTracksColor) { ASSERT_TRUE(blob); auto frame = TextFrameFromTextBlob(blob); - ASSERT_FALSE(frame.HasColor()); + ASSERT_FALSE(frame.GetAtlasType() == GlyphAtlas::Type::kColorBitmap); LazyGlyphAtlas lazy_atlas; - ASSERT_FALSE(lazy_atlas.HasColor()); lazy_atlas.AddTextFrame(frame); - ASSERT_FALSE(lazy_atlas.HasColor()); - frame = TextFrameFromTextBlob(SkTextBlob::MakeFromString("😀 ", emoji_font)); - ASSERT_TRUE(frame.HasColor()); + ASSERT_TRUE(frame.GetAtlasType() == GlyphAtlas::Type::kColorBitmap); lazy_atlas.AddTextFrame(frame); - ASSERT_TRUE(lazy_atlas.HasColor()); + // Creates different atlases for color and alpha bitmap. + auto color_context = std::make_shared(); + auto bitmap_context = std::make_shared(); + auto color_atlas = lazy_atlas.CreateOrGetGlyphAtlas( + GlyphAtlas::Type::kColorBitmap, color_context, GetContext()); + + auto bitmap_atlas = lazy_atlas.CreateOrGetGlyphAtlas( + GlyphAtlas::Type::kAlphaBitmap, bitmap_context, GetContext()); + + ASSERT_FALSE(color_atlas == bitmap_atlas); } TEST_P(TypographerTest, GlyphAtlasWithOddUniqueGlyphSize) { From 3d1edc6115163bc28e16c3a2affdae6b2889524c Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 5 May 2023 12:11:06 -0700 Subject: [PATCH 06/11] licenses --- ci/licenses_golden/licenses_flutter | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index ffcb36dbe7f3f..c5b957aee099f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1297,8 +1297,7 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noa ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.vert + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas_color.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradient_fill.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/linear_gradient_fill.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/linear_gradient_ssbo_fill.frag + ../../../flutter/LICENSE @@ -3891,8 +3890,7 @@ FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalp FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert -FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag -FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.vert +FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_color.frag FILE: ../../../flutter/impeller/entity/shaders/gradient_fill.vert FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_ssbo_fill.frag From b50e132a188de1270dbe13ea1088f223bd3a2a8d Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 5 May 2023 17:58:32 -0700 Subject: [PATCH 07/11] ++ --- impeller/entity/contents/text_contents.cc | 1 - impeller/tools/malioc.json | 530 ++++++---------------- 2 files changed, 135 insertions(+), 396 deletions(-) diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index 2973fb52bf46e..dc5a04096c9af 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -108,7 +108,6 @@ static bool CommonRender( } sampler_desc.mip_filter = MipFilter::kNearest; - FS::FragInfo frag_info; frag_info.text_color = ToVector(color.Premultiply()); FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info)); diff --git a/impeller/tools/malioc.json b/impeller/tools/malioc.json index e9e21d268c9d4..0ea54a4a9d0c4 100644 --- a/impeller/tools/malioc.json +++ b/impeller/tools/malioc.json @@ -7431,15 +7431,16 @@ "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - "varying" + "varying", + "texture" ], "longest_path_cycles": [ - 0.078125, - 0.0625, - 0.078125, + 0.03125, + 0.03125, + 0.03125, 0.0, 0.0, - 0.375, + 0.25, 0.25 ], "pipelines": [ @@ -7452,27 +7453,29 @@ "texture" ], "shortest_path_bound_pipelines": [ - "varying" + "varying", + "texture" ], "shortest_path_cycles": [ - 0.0625, - 0.0625, - 0.046875, + 0.03125, + 0.03125, 0.0, 0.0, - 0.375, + 0.0, + 0.25, 0.25 ], "total_bound_pipelines": [ - "varying" + "varying", + "texture" ], "total_cycles": [ - 0.078125, - 0.0625, - 0.078125, + 0.03125, + 0.03125, + 0.03125, 0.0, 0.0, - 0.375, + 0.25, 0.25 ] }, @@ -7518,10 +7521,11 @@ 1.0 ], "total_bound_pipelines": [ - "arithmetic" + "load_store", + "texture" ], "total_cycles": [ - 1.3333333730697632, + 0.6666666865348816, 1.0, 1.0 ] @@ -7541,16 +7545,16 @@ "type": "Vertex", "variants": { "Position": { - "fp16_arithmetic": 88, + "fp16_arithmetic": 0, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, - 0.046875, + 0.265625, + 0.265625, + 0.0, 0.0, 2.0, 0.0 @@ -7567,9 +7571,9 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, - 0.046875, + 0.265625, + 0.265625, + 0.0, 0.0, 2.0, 0.0 @@ -7578,9 +7582,9 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, - 0.046875, + 0.265625, + 0.265625, + 0.0, 0.0, 2.0, 0.0 @@ -7599,11 +7603,11 @@ "load_store" ], "longest_path_cycles": [ - 0.03125, 0.0, - 0.03125, 0.0, - 4.0, + 0.0, + 0.0, + 3.0, 0.0 ], "pipelines": [ @@ -7618,29 +7622,29 @@ "load_store" ], "shortest_path_cycles": [ - 0.03125, 0.0, - 0.03125, 0.0, - 4.0, + 0.0, + 0.0, + 3.0, 0.0 ], "total_bound_pipelines": [ "load_store" ], "total_cycles": [ - 0.03125, 0.0, - 0.03125, 0.0, - 4.0, + 0.0, + 0.0, + 3.0, 0.0 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, "uniform_registers_used": 8, - "work_registers_used": 9 + "work_registers_used": 6 } } }, @@ -7658,7 +7662,7 @@ ], "longest_path_cycles": [ 2.9700000286102295, - 7.0, + 5.0, 0.0 ], "pipelines": [ @@ -7671,7 +7675,7 @@ ], "shortest_path_cycles": [ 2.9700000286102295, - 7.0, + 5.0, 0.0 ], "total_bound_pipelines": [ @@ -7679,7 +7683,7 @@ ], "total_cycles": [ 3.0, - 7.0, + 5.0, 0.0 ] }, @@ -7690,10 +7694,10 @@ } } }, - "flutter/impeller/entity/gles/glyph_atlas_sdf.frag.gles": { + "flutter/impeller/entity/gles/glyph_atlas_color.frag.gles": { "Mali-G78": { "core": "Mali-G78", - "filename": "flutter/impeller/entity/gles/glyph_atlas_sdf.frag.gles", + "filename": "flutter/impeller/entity/gles/glyph_atlas_color.frag.gles", "has_side_effects": false, "has_uniform_computation": false, "modifies_coverage": false, @@ -7703,19 +7707,18 @@ "uses_late_zs_update": false, "variants": { "Main": { - "fp16_arithmetic": 77, + "fp16_arithmetic": 100, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - "arith_total", - "arith_fma", - "arith_sfu" + "varying", + "texture" ], "longest_path_cycles": [ - 0.3125, - 0.3125, - 0.046875, - 0.3125, + 0.03125, + 0.03125, + 0.03125, + 0.0, 0.0, 0.25, 0.25 @@ -7730,29 +7733,27 @@ "texture" ], "shortest_path_bound_pipelines": [ - "arith_total", - "arith_fma", - "arith_sfu" + "varying", + "texture" ], "shortest_path_cycles": [ - 0.3125, - 0.3125, - 0.015625, - 0.3125, + 0.03125, + 0.03125, + 0.0, + 0.0, 0.0, 0.25, 0.25 ], "total_bound_pipelines": [ - "arith_total", - "arith_fma", - "arith_sfu" + "varying", + "texture" ], "total_cycles": [ - 0.3125, - 0.3125, - 0.046875, - 0.3125, + 0.03125, + 0.03125, + 0.03125, + 0.0, 0.0, 0.25, 0.25 @@ -7760,14 +7761,14 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 8, - "work_registers_used": 20 + "uniform_registers_used": 4, + "work_registers_used": 19 } } }, "Mali-T880": { "core": "Mali-T880", - "filename": "flutter/impeller/entity/gles/glyph_atlas_sdf.frag.gles", + "filename": "flutter/impeller/entity/gles/glyph_atlas_color.frag.gles", "has_uniform_computation": false, "type": "Fragment", "variants": { @@ -7775,194 +7776,42 @@ "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - "arithmetic" - ], - "longest_path_cycles": [ - 3.299999952316284, - 1.0, - 3.0 - ], - "pipelines": [ "arithmetic", "load_store", "texture" ], - "shortest_path_bound_pipelines": [ - "arithmetic" - ], - "shortest_path_cycles": [ - 3.299999952316284, + "longest_path_cycles": [ 1.0, - 3.0 - ], - "total_bound_pipelines": [ - "arithmetic" - ], - "total_cycles": [ - 3.6666667461395264, 1.0, - 3.0 - ] - }, - "thread_occupancy": 100, - "uniform_registers_used": 1, - "work_registers_used": 2 - } - } - } - }, - "flutter/impeller/entity/gles/glyph_atlas_sdf.vert.gles": { - "Mali-G78": { - "core": "Mali-G78", - "filename": "flutter/impeller/entity/gles/glyph_atlas_sdf.vert.gles", - "has_uniform_computation": false, - "type": "Vertex", - "variants": { - "Position": { - "fp16_arithmetic": 88, - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - "load_store" - ], - "longest_path_cycles": [ - 0.140625, - 0.140625, - 0.046875, - 0.0, - 2.0, - 0.0 + 1.0 ], "pipelines": [ - "arith_total", - "arith_fma", - "arith_cvt", - "arith_sfu", + "arithmetic", "load_store", "texture" ], "shortest_path_bound_pipelines": [ - "load_store" - ], - "shortest_path_cycles": [ - 0.140625, - 0.140625, - 0.046875, - 0.0, - 2.0, - 0.0 - ], - "total_bound_pipelines": [ - "load_store" - ], - "total_cycles": [ - 0.140625, - 0.140625, - 0.046875, - 0.0, - 2.0, - 0.0 - ] - }, - "stack_spill_bytes": 0, - "thread_occupancy": 100, - "uniform_registers_used": 16, - "work_registers_used": 32 - }, - "Varying": { - "fp16_arithmetic": null, - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - "load_store" - ], - "longest_path_cycles": [ - 0.0, - 0.0, - 0.0, - 0.0, - 3.0, - 0.0 - ], - "pipelines": [ - "arith_total", - "arith_fma", - "arith_cvt", - "arith_sfu", + "arithmetic", "load_store", "texture" ], - "shortest_path_bound_pipelines": [ - "load_store" - ], "shortest_path_cycles": [ - 0.0, - 0.0, - 0.0, - 0.0, - 3.0, - 0.0 + 1.0, + 1.0, + 1.0 ], "total_bound_pipelines": [ - "load_store" - ], - "total_cycles": [ - 0.0, - 0.0, - 0.0, - 0.0, - 3.0, - 0.0 - ] - }, - "stack_spill_bytes": 0, - "thread_occupancy": 100, - "uniform_registers_used": 8, - "work_registers_used": 6 - } - } - }, - "Mali-T880": { - "core": "Mali-T880", - "filename": "flutter/impeller/entity/gles/glyph_atlas_sdf.vert.gles", - "has_uniform_computation": false, - "type": "Vertex", - "variants": { - "Main": { - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - "load_store" - ], - "longest_path_cycles": [ - 2.9700000286102295, - 5.0, - 0.0 - ], - "pipelines": [ - "arithmetic", "load_store", "texture" ], - "shortest_path_bound_pipelines": [ - "load_store" - ], - "shortest_path_cycles": [ - 2.9700000286102295, - 5.0, - 0.0 - ], - "total_bound_pipelines": [ - "load_store" - ], "total_cycles": [ - 3.0, - 5.0, - 0.0 + 0.6666666865348816, + 1.0, + 1.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 4, + "uniform_registers_used": 1, "work_registers_used": 2 } } @@ -11354,15 +11203,16 @@ "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - "varying" + "varying", + "texture" ], "longest_path_cycles": [ - 0.0625, - 0.0625, - 0.046875, + 0.03125, + 0.03125, 0.0, 0.0, - 0.375, + 0.0, + 0.25, 0.25 ], "pipelines": [ @@ -11375,34 +11225,36 @@ "texture" ], "shortest_path_bound_pipelines": [ - "varying" + "varying", + "texture" ], "shortest_path_cycles": [ - 0.0625, - 0.0625, - 0.046875, + 0.03125, + 0.03125, 0.0, 0.0, - 0.375, + 0.0, + 0.25, 0.25 ], "total_bound_pipelines": [ - "varying" + "varying", + "texture" ], "total_cycles": [ - 0.0625, - 0.0625, - 0.046875, + 0.03125, + 0.03125, 0.0, 0.0, - 0.375, + 0.0, + 0.25, 0.25 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, "uniform_registers_used": 6, - "work_registers_used": 7 + "work_registers_used": 6 } } } @@ -11415,16 +11267,16 @@ "type": "Vertex", "variants": { "Position": { - "fp16_arithmetic": 100, + "fp16_arithmetic": 0, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ "load_store" ], "longest_path_cycles": [ - 0.125, - 0.125, - 0.0625, + 0.25, + 0.25, + 0.0, 0.0, 2.0, 0.0 @@ -11441,9 +11293,9 @@ "load_store" ], "shortest_path_cycles": [ - 0.125, - 0.125, - 0.0625, + 0.25, + 0.25, + 0.0, 0.0, 2.0, 0.0 @@ -11452,9 +11304,9 @@ "load_store" ], "total_cycles": [ - 0.125, - 0.125, - 0.0625, + 0.25, + 0.25, + 0.0, 0.0, 2.0, 0.0 @@ -11462,7 +11314,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 16, + "uniform_registers_used": 24, "work_registers_used": 32 }, "Varying": { @@ -11477,7 +11329,7 @@ 0.0, 0.0, 0.0, - 4.0, + 3.0, 0.0 ], "pipelines": [ @@ -11496,7 +11348,7 @@ 0.0, 0.0, 0.0, - 4.0, + 3.0, 0.0 ], "total_bound_pipelines": [ @@ -11507,22 +11359,22 @@ 0.0, 0.0, 0.0, - 4.0, + 3.0, 0.0 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 16, - "work_registers_used": 7 + "uniform_registers_used": 24, + "work_registers_used": 6 } } } }, - "flutter/impeller/entity/glyph_atlas_sdf.frag.vkspv": { + "flutter/impeller/entity/glyph_atlas_color.frag.vkspv": { "Mali-G78": { "core": "Mali-G78", - "filename": "flutter/impeller/entity/glyph_atlas_sdf.frag.vkspv", + "filename": "flutter/impeller/entity/glyph_atlas_color.frag.vkspv", "has_side_effects": false, "has_uniform_computation": true, "modifies_coverage": false, @@ -11532,87 +11384,21 @@ "uses_late_zs_update": false, "variants": { "Main": { - "fp16_arithmetic": 72, + "fp16_arithmetic": 100, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - "arith_total", - "arith_sfu" - ], - "longest_path_cycles": [ - 0.3125, - 0.25, - 0.015625, - 0.3125, - 0.0, - 0.25, - 0.25 - ], - "pipelines": [ - "arith_total", - "arith_fma", - "arith_cvt", - "arith_sfu", - "load_store", "varying", "texture" ], - "shortest_path_bound_pipelines": [ - "arith_total", - "arith_sfu" - ], - "shortest_path_cycles": [ - 0.3125, - 0.25, - 0.015625, - 0.3125, + "longest_path_cycles": [ + 0.03125, + 0.03125, + 0.0, 0.0, - 0.25, - 0.25 - ], - "total_bound_pipelines": [ - "arith_total", - "arith_sfu" - ], - "total_cycles": [ - 0.3125, - 0.25, - 0.015625, - 0.3125, 0.0, 0.25, 0.25 - ] - }, - "stack_spill_bytes": 0, - "thread_occupancy": 100, - "uniform_registers_used": 6, - "work_registers_used": 6 - } - } - } - }, - "flutter/impeller/entity/glyph_atlas_sdf.vert.vkspv": { - "Mali-G78": { - "core": "Mali-G78", - "filename": "flutter/impeller/entity/glyph_atlas_sdf.vert.vkspv", - "has_uniform_computation": true, - "type": "Vertex", - "variants": { - "Position": { - "fp16_arithmetic": 100, - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - "load_store" - ], - "longest_path_cycles": [ - 0.125, - 0.125, - 0.0625, - 0.0, - 2.0, - 0.0 ], "pipelines": [ "arith_total", @@ -11620,86 +11406,40 @@ "arith_cvt", "arith_sfu", "load_store", + "varying", "texture" ], "shortest_path_bound_pipelines": [ - "load_store" - ], - "shortest_path_cycles": [ - 0.125, - 0.125, - 0.0625, - 0.0, - 2.0, - 0.0 - ], - "total_bound_pipelines": [ - "load_store" - ], - "total_cycles": [ - 0.125, - 0.125, - 0.0625, - 0.0, - 2.0, - 0.0 - ] - }, - "stack_spill_bytes": 0, - "thread_occupancy": 100, - "uniform_registers_used": 16, - "work_registers_used": 32 - }, - "Varying": { - "fp16_arithmetic": null, - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - "load_store" - ], - "longest_path_cycles": [ - 0.0, - 0.0, - 0.0, - 0.0, - 3.0, - 0.0 - ], - "pipelines": [ - "arith_total", - "arith_fma", - "arith_cvt", - "arith_sfu", - "load_store", + "varying", "texture" ], - "shortest_path_bound_pipelines": [ - "load_store" - ], "shortest_path_cycles": [ + 0.03125, + 0.03125, 0.0, 0.0, 0.0, - 0.0, - 3.0, - 0.0 + 0.25, + 0.25 ], "total_bound_pipelines": [ - "load_store" + "varying", + "texture" ], "total_cycles": [ + 0.03125, + 0.03125, 0.0, 0.0, 0.0, - 0.0, - 3.0, - 0.0 + 0.25, + 0.25 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 16, - "work_registers_used": 6 + "uniform_registers_used": 4, + "work_registers_used": 4 } } } From b03be9bf762b50ea7c0b6fde738a7706377b1c7b Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 8 May 2023 14:59:53 -0700 Subject: [PATCH 08/11] ++ --- .../backends/skia/text_render_context_skia.cc | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/text_render_context_skia.cc index 886674ea456f8..408e61792be92 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -170,8 +170,7 @@ ISize OptimumAtlasSizeForFontGlyphPairs( static void DrawGlyph(SkCanvas* canvas, const FontGlyphPair& font_glyph, - const Rect& location, - bool has_color) { + const Rect& location) { const auto& metrics = font_glyph.font.GetMetrics(); const auto position = SkPoint::Make(location.origin.x / metrics.scale, location.origin.y / metrics.scale); @@ -184,10 +183,8 @@ static void DrawGlyph(SkCanvas* canvas, sk_font.setHinting(SkFontHinting::kSlight); sk_font.setEmbolden(metrics.embolden); - auto glyph_color = has_color ? SK_ColorWHITE : SK_ColorBLACK; - SkPaint glyph_paint; - glyph_paint.setColor(glyph_color); + glyph_paint.setColor(SK_ColorWHITE); canvas->resetMatrix(); canvas->scale(metrics.scale, metrics.scale); canvas->drawGlyphs( @@ -216,14 +213,12 @@ static bool UpdateAtlasBitmap(const GlyphAtlas& atlas, return false; } - bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap; - for (const FontGlyphPair& pair : new_pairs) { auto pos = atlas.FindFontGlyphBounds(pair); if (!pos.has_value()) { continue; } - DrawGlyph(canvas, pair, pos.value(), has_color); + DrawGlyph(canvas, pair, pos.value()); } return true; } @@ -257,11 +252,9 @@ static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, return nullptr; } - bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap; - - atlas.IterateGlyphs([canvas, has_color](const FontGlyphPair& font_glyph, + atlas.IterateGlyphs([canvas](const FontGlyphPair& font_glyph, const Rect& location) -> bool { - DrawGlyph(canvas, font_glyph, location, has_color); + DrawGlyph(canvas, font_glyph, location); return true; }); From e4a8b3e790484b68ec55db01a8c079511973169d Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 8 May 2023 15:00:57 -0700 Subject: [PATCH 09/11] ++ --- impeller/entity/shaders/geometry/convex.vert | 27 +++++++++++++++++++ .../backends/skia/text_render_context_skia.cc | 10 +++---- 2 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 impeller/entity/shaders/geometry/convex.vert diff --git a/impeller/entity/shaders/geometry/convex.vert b/impeller/entity/shaders/geometry/convex.vert new file mode 100644 index 0000000000000..d1706486fed51 --- /dev/null +++ b/impeller/entity/shaders/geometry/convex.vert @@ -0,0 +1,27 @@ +// 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 + +uniform FrameInfo { + f16vec2 center; +} +frame_info; + +layout(std430) writeonly buffer GeometryData { + vec2 geometry[]; +} +geometry_data; + +in f16vec2 p1; +in f16vec2 p2; + +void main() { + int bufer_offset = gl_VertexIndex * 3; + + geometry_data[bufer_offset++] = p1; + geometry_data[bufer_offset++] = p2; + geometry_data[bufer_offset++] = vec2(frame_info.center); +} diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/text_render_context_skia.cc index 408e61792be92..343c3f31ede49 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -252,11 +252,11 @@ static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, return nullptr; } - atlas.IterateGlyphs([canvas](const FontGlyphPair& font_glyph, - const Rect& location) -> bool { - DrawGlyph(canvas, font_glyph, location); - return true; - }); + atlas.IterateGlyphs( + [canvas](const FontGlyphPair& font_glyph, const Rect& location) -> bool { + DrawGlyph(canvas, font_glyph, location); + return true; + }); return bitmap; } From 242427dee7dbaf549a3e9fb5c582b46cc4573999 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 8 May 2023 15:01:15 -0700 Subject: [PATCH 10/11] ++ --- impeller/entity/shaders/geometry/convex.vert | 27 -------------------- 1 file changed, 27 deletions(-) delete mode 100644 impeller/entity/shaders/geometry/convex.vert diff --git a/impeller/entity/shaders/geometry/convex.vert b/impeller/entity/shaders/geometry/convex.vert deleted file mode 100644 index d1706486fed51..0000000000000 --- a/impeller/entity/shaders/geometry/convex.vert +++ /dev/null @@ -1,27 +0,0 @@ -// 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 - -uniform FrameInfo { - f16vec2 center; -} -frame_info; - -layout(std430) writeonly buffer GeometryData { - vec2 geometry[]; -} -geometry_data; - -in f16vec2 p1; -in f16vec2 p2; - -void main() { - int bufer_offset = gl_VertexIndex * 3; - - geometry_data[bufer_offset++] = p1; - geometry_data[bufer_offset++] = p2; - geometry_data[bufer_offset++] = vec2(frame_info.center); -} From 144e77bd2f2a68362685775ee5c483f6351b97ee Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 9 May 2023 15:15:50 -0700 Subject: [PATCH 11/11] Add back hascolor check --- .../backends/skia/text_render_context_skia.cc | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/text_render_context_skia.cc index 343c3f31ede49..886674ea456f8 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -170,7 +170,8 @@ ISize OptimumAtlasSizeForFontGlyphPairs( static void DrawGlyph(SkCanvas* canvas, const FontGlyphPair& font_glyph, - const Rect& location) { + const Rect& location, + bool has_color) { const auto& metrics = font_glyph.font.GetMetrics(); const auto position = SkPoint::Make(location.origin.x / metrics.scale, location.origin.y / metrics.scale); @@ -183,8 +184,10 @@ static void DrawGlyph(SkCanvas* canvas, sk_font.setHinting(SkFontHinting::kSlight); sk_font.setEmbolden(metrics.embolden); + auto glyph_color = has_color ? SK_ColorWHITE : SK_ColorBLACK; + SkPaint glyph_paint; - glyph_paint.setColor(SK_ColorWHITE); + glyph_paint.setColor(glyph_color); canvas->resetMatrix(); canvas->scale(metrics.scale, metrics.scale); canvas->drawGlyphs( @@ -213,12 +216,14 @@ static bool UpdateAtlasBitmap(const GlyphAtlas& atlas, return false; } + bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap; + for (const FontGlyphPair& pair : new_pairs) { auto pos = atlas.FindFontGlyphBounds(pair); if (!pos.has_value()) { continue; } - DrawGlyph(canvas, pair, pos.value()); + DrawGlyph(canvas, pair, pos.value(), has_color); } return true; } @@ -252,11 +257,13 @@ static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, return nullptr; } - atlas.IterateGlyphs( - [canvas](const FontGlyphPair& font_glyph, const Rect& location) -> bool { - DrawGlyph(canvas, font_glyph, location); - return true; - }); + bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap; + + atlas.IterateGlyphs([canvas, has_color](const FontGlyphPair& font_glyph, + const Rect& location) -> bool { + DrawGlyph(canvas, font_glyph, location, has_color); + return true; + }); return bitmap; }