Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,6 @@ ContentContext::ContentContext(std::shared_ptr<Context> context)
CreateDefaultPipeline<SrgbToLinearFilterPipeline>(*context_);
glyph_atlas_pipelines_[{}] =
CreateDefaultPipeline<GlyphAtlasPipeline>(*context_);
glyph_atlas_sdf_pipelines_[{}] =
CreateDefaultPipeline<GlyphAtlasSdfPipeline>(*context_);
geometry_color_pipelines_[{}] =
CreateDefaultPipeline<GeometryColorPipeline>(*context_);
yuv_to_rgb_filter_pipelines_[{}] =
Expand Down
10 changes: 0 additions & 10 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -173,8 +171,6 @@ using SrgbToLinearFilterPipeline =
SrgbToLinearFilterFragmentShader>;
using GlyphAtlasPipeline =
RenderPipelineT<GlyphAtlasVertexShader, GlyphAtlasFragmentShader>;
using GlyphAtlasSdfPipeline =
RenderPipelineT<GlyphAtlasSdfVertexShader, GlyphAtlasSdfFragmentShader>;
using PorterDuffBlendPipeline =
RenderPipelineT<BlendVertexShader, PorterDuffBlendFragmentShader>;
// Instead of requiring new shaders for clips, the solid fill stages are used
Expand Down Expand Up @@ -473,11 +469,6 @@ class ContentContext {
return GetPipeline(glyph_atlas_pipelines_, opts);
}

std::shared_ptr<Pipeline<PipelineDescriptor>> GetGlyphAtlasSdfPipeline(
ContentContextOptions opts) const {
return GetPipeline(glyph_atlas_sdf_pipelines_, opts);
}

std::shared_ptr<Pipeline<PipelineDescriptor>> GetGeometryColorPipeline(
ContentContextOptions opts) const {
return GetPipeline(geometry_color_pipelines_, opts);
Expand Down Expand Up @@ -731,7 +722,6 @@ class ContentContext {
mutable Variants<SrgbToLinearFilterPipeline> srgb_to_linear_filter_pipelines_;
mutable Variants<ClipPipeline> clip_pipelines_;
mutable Variants<GlyphAtlasPipeline> glyph_atlas_pipelines_;
mutable Variants<GlyphAtlasSdfPipeline> glyph_atlas_sdf_pipelines_;
mutable Variants<GeometryColorPipeline> geometry_color_pipelines_;
mutable Variants<YUVToRGBFilterPipeline> yuv_to_rgb_filter_pipelines_;
mutable Variants<PorterDuffBlendPipeline> porter_duff_blend_pipelines_;
Expand Down
50 changes: 11 additions & 39 deletions impeller/entity/contents/text_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ std::optional<Rect> TextContents::GetCoverage(const Entity& entity) const {
return bounds->TransformBounds(entity.GetTransformation());
}

template <class TPipeline>
static bool CommonRender(
const ContentContext& renderer,
const Entity& entity,
Expand All @@ -85,11 +84,11 @@ static bool CommonRender(
std::shared_ptr<GlyphAtlas>
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));
Expand All @@ -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));

Expand Down Expand Up @@ -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
Expand All @@ -199,19 +198,16 @@ 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;

if constexpr (std::is_same_v<TPipeline, GlyphAtlasPipeline>) {
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;
Expand All @@ -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<GlyphAtlasSdfPipeline>(renderer, entity, pass, GetColor(),
frame_, offset_, atlas, cmd);
}

bool TextContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
Expand Down Expand Up @@ -276,8 +248,8 @@ bool TextContents::Render(const ContentContext& renderer,
cmd.pipeline = renderer.GetGlyphAtlasPipeline(opts);
cmd.stencil_reference = entity.GetStencilDepth();

return CommonRender<GlyphAtlasPipeline>(renderer, entity, pass, color, frame_,
offset_, atlas, cmd);
return CommonRender(renderer, entity, pass, color, frame_, offset_, atlas,
cmd);
}

} // namespace impeller
5 changes: 0 additions & 5 deletions impeller/entity/contents/text_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down
28 changes: 0 additions & 28 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<LazyGlyphAtlas>();
lazy_glyph_atlas->AddTextFrame(frame);

EXPECT_FALSE(lazy_glyph_atlas->HasColor());

auto text_contents = std::make_shared<TextContents>();
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");

Expand Down
123 changes: 0 additions & 123 deletions impeller/typographer/backends/skia/text_render_context_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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});
Expand Down Expand Up @@ -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<uint16_t>;

// distance to nearest boundary point map
std::vector<Scalar> distance_map(width * height);
// nearest boundary point map
std::vector<ShortPoint> 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,
Expand Down Expand Up @@ -353,7 +235,6 @@ static std::shared_ptr<SkBitmap> 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;
Expand Down Expand Up @@ -563,10 +444,6 @@ std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
// ---------------------------------------------------------------------------
PixelFormat format;
switch (type) {
case GlyphAtlas::Type::kSignedDistanceField:
ConvertBitmapToSignedDistanceField(
reinterpret_cast<uint8_t*>(bitmap->getPixels()), atlas_size.width,
atlas_size.height);
case GlyphAtlas::Type::kAlphaBitmap:
format = PixelFormat::kA8UNormInt;
break;
Expand Down
7 changes: 0 additions & 7 deletions impeller/typographer/glyph_atlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down