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: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,8 @@ FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.frag
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.vert
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/gradient_fill.vert
FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/linear_to_srgb_filter.frag
Expand Down
20 changes: 20 additions & 0 deletions impeller/compiler/shader_lib/impeller/transform.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,24 @@ vec2 IPVec2TransformPosition(mat4 matrix, vec2 point) {
return transformed.xy / transformed.w;
}

// Returns the transformed gl_Position for a given glyph position in a glyph
// atlas.
vec4 IPPositionForGlyphPosition(mat4 mvp, vec2 unit_vertex, vec2 glyph_position, vec2 glyph_size) {
vec4 translate = mvp[0] * glyph_position.x
+ mvp[1] * glyph_position.y
+ mvp[3];
mat4 translated_mvp = mat4(
mvp[0],
mvp[1],
mvp[2],
vec4(
translate.xyz,
mvp[3].w
)
);
return translated_mvp *
vec4(unit_vertex.x * glyph_size.x,
unit_vertex.y * glyph_size.y, 0.0, 1.0);
}

#endif
2 changes: 2 additions & 0 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ impeller_shaders("entity_shaders") {
"shaders/gaussian_blur.vert",
"shaders/glyph_atlas.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",
Expand Down
2 changes: 2 additions & 0 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ ContentContext::ContentContext(std::shared_ptr<Context> context)
CreateDefaultPipeline<SolidStrokePipeline>(*context_);
glyph_atlas_pipelines_[{}] =
CreateDefaultPipeline<GlyphAtlasPipeline>(*context_);
glyph_atlas_sdf_pipelines_[{}] =
CreateDefaultPipeline<GlyphAtlasSdfPipeline>(*context_);
vertices_pipelines_[{}] = CreateDefaultPipeline<VerticesPipeline>(*context_);
atlas_pipelines_[{}] = CreateDefaultPipeline<AtlasPipeline>(*context_);

Expand Down
10 changes: 10 additions & 0 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
#include "impeller/entity/gaussian_blur.vert.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 @@ -144,6 +146,8 @@ using SolidStrokePipeline =
RenderPipelineT<SolidStrokeVertexShader, SolidStrokeFragmentShader>;
using GlyphAtlasPipeline =
RenderPipelineT<GlyphAtlasVertexShader, GlyphAtlasFragmentShader>;
using GlyphAtlasSdfPipeline =
RenderPipelineT<GlyphAtlasSdfVertexShader, GlyphAtlasSdfFragmentShader>;
using VerticesPipeline =
RenderPipelineT<VerticesVertexShader, VerticesFragmentShader>;
using AtlasPipeline =
Expand Down Expand Up @@ -272,6 +276,11 @@ 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>> GetVerticesPipeline(
ContentContextOptions opts) const {
return GetPipeline(vertices_pipelines_, opts);
Expand Down Expand Up @@ -399,6 +408,7 @@ class ContentContext {
mutable Variants<SolidStrokePipeline> solid_stroke_pipelines_;
mutable Variants<ClipPipeline> clip_pipelines_;
mutable Variants<GlyphAtlasPipeline> glyph_atlas_pipelines_;
mutable Variants<GlyphAtlasSdfPipeline> glyph_atlas_sdf_pipelines_;
mutable Variants<VerticesPipeline> vertices_pipelines_;
mutable Variants<AtlasPipeline> atlas_pipelines_;
// Advanced blends.
Expand Down
123 changes: 78 additions & 45 deletions impeller/entity/contents/text_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

#include "impeller/entity/contents/text_contents.h"

#include <iostream>
#include <optional>
#include <type_traits>

#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/entity.h"
Expand All @@ -28,22 +28,16 @@ void TextContents::SetTextFrame(TextFrame frame) {
frame_ = std::move(frame);
}

void TextContents::SetGlyphAtlas(std::shared_ptr<GlyphAtlas> atlas) {
atlas_ = std::move(atlas);
}

void TextContents::SetGlyphAtlas(std::shared_ptr<LazyGlyphAtlas> atlas) {
atlas_ = std::move(atlas);
lazy_atlas_ = std::move(atlas);
}

std::shared_ptr<GlyphAtlas> TextContents::ResolveAtlas(
GlyphAtlas::Type type,
std::shared_ptr<Context> context) const {
if (auto lazy_atlas = std::get_if<std::shared_ptr<LazyGlyphAtlas>>(&atlas_)) {
return lazy_atlas->get()->CreateOrGetGlyphAtlas(context);
}

if (auto atlas = std::get_if<std::shared_ptr<GlyphAtlas>>(&atlas_)) {
return *atlas;
FML_DCHECK(lazy_atlas_);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having the assertion as well as the conditional is redundant. I suggest removing the assert.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional is defensive - the assert is so that we don't get here in a test and return null, which would fail to render text.

if (lazy_atlas_) {
return lazy_atlas_->CreateOrGetGlyphAtlas(type, context);
}

return nullptr;
Expand All @@ -61,33 +55,19 @@ std::optional<Rect> TextContents::GetCoverage(const Entity& entity) const {
return bounds->TransformBounds(entity.GetTransformation());
}

bool TextContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
if (color_.IsTransparent()) {
return true;
}

auto atlas = ResolveAtlas(renderer.GetContext());

if (!atlas || !atlas->IsValid()) {
VALIDATION_LOG << "Cannot render glyphs without prepared atlas.";
return false;
}

using VS = GlyphAtlasPipeline::VertexShader;
using FS = GlyphAtlasPipeline::FragmentShader;

// Information shared by all glyph draw calls.
Command cmd;
cmd.label = "TextFrame";
cmd.primitive_type = PrimitiveType::kTriangle;
cmd.pipeline =
renderer.GetGlyphAtlasPipeline(OptionsFromPassAndEntity(pass, entity));
cmd.stencil_reference = entity.GetStencilDepth();
template <class TPipeline>
static bool CommonRender(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const Color& color,
const TextFrame& frame,
std::shared_ptr<GlyphAtlas> atlas,
Command& cmd) {
using VS = typename TPipeline::VertexShader;
using FS = typename TPipeline::FragmentShader;

// Common vertex uniforms for all glyphs.
VS::FrameInfo frame_info;
typename VS::FrameInfo frame_info;
frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation();
VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info));
Expand All @@ -96,8 +76,8 @@ bool TextContents::Render(const ContentContext& renderer,
sampler_desc.min_filter = MinMagFilter::kLinear;
sampler_desc.mag_filter = MinMagFilter::kLinear;

FS::FragInfo frag_info;
frag_info.text_color = ToVector(color_.Premultiply());
typename FS::FragInfo frag_info;
frag_info.text_color = ToVector(color.Premultiply());
frag_info.atlas_size =
Point{static_cast<Scalar>(atlas->GetTexture()->GetSize().width),
static_cast<Scalar>(atlas->GetTexture()->GetSize().height)};
Expand All @@ -122,16 +102,15 @@ bool TextContents::Render(const ContentContext& renderer,
{0, 0}, {1, 0}, {0, 1}, {1, 0}, {0, 1}, {1, 1},
};

VertexBufferBuilder<VS::PerVertexData> vertex_builder;
for (const auto& run : frame_.GetRuns()) {
VertexBufferBuilder<typename VS::PerVertexData> vertex_builder;
for (const auto& run : frame.GetRuns()) {
auto font = run.GetFont();
auto glyph_size = ISize::Ceil(font.GetMetrics().GetBoundingBox().size);
for (const auto& glyph_position : run.GetGlyphPositions()) {
FontGlyphPair font_glyph_pair{font, glyph_position.glyph};
auto color_glyph =
atlas->IsColorFontGlyphPair(font_glyph_pair) ? 1.0 : 0.0;

for (const auto& point : unit_vertex_points) {
VS::PerVertexData vtx;
typename VS::PerVertexData vtx;
vtx.unit_vertex = point;

auto atlas_glyph_pos = atlas->FindFontGlyphPosition(font_glyph_pair);
Expand All @@ -149,7 +128,10 @@ bool TextContents::Render(const ContentContext& renderer,
1 / atlas_glyph_pos->size.height};
vtx.atlas_glyph_size =
Point{atlas_glyph_pos->size.width, atlas_glyph_pos->size.height};
vtx.color_glyph = color_glyph;
if constexpr (std::is_same_v<TPipeline, GlyphAtlasPipeline>) {
vtx.color_glyph =
glyph_position.glyph.type == Glyph::Type::kBitmap ? 1.0 : 0.0;
}
vertex_builder.AppendVertex(std::move(vtx));
}
}
Expand All @@ -165,4 +147,55 @@ bool TextContents::Render(const ContentContext& renderer,
return true;
}

bool TextContents::RenderSdf(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
auto atlas = ResolveAtlas(GlyphAtlas::Type::kSignedDistanceField,
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";
cmd.primitive_type = PrimitiveType::kTriangle;
cmd.pipeline =
renderer.GetGlyphAtlasSdfPipeline(OptionsFromPassAndEntity(pass, entity));
cmd.stencil_reference = entity.GetStencilDepth();

return CommonRender<GlyphAtlasSdfPipeline>(renderer, entity, pass, color_,
frame_, atlas, cmd);
}

bool TextContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
if (color_.IsTransparent()) {
return true;
}

auto atlas = ResolveAtlas(frame_.HasColor() ? GlyphAtlas::Type::kColorBitmap
: GlyphAtlas::Type::kAlphaBitmap,
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 = "TextFrame";
cmd.primitive_type = PrimitiveType::kTriangle;
cmd.pipeline =
renderer.GetGlyphAtlasPipeline(OptionsFromPassAndEntity(pass, entity));
cmd.stencil_reference = entity.GetStencilDepth();

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

} // namespace impeller
14 changes: 8 additions & 6 deletions impeller/entity/contents/text_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
#include "flutter/fml/macros.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/geometry/color.h"
#include "impeller/typographer/glyph_atlas.h"
#include "impeller/typographer/text_frame.h"

namespace impeller {

class GlyphAtlas;
class LazyGlyphAtlas;
class Context;

Expand All @@ -28,8 +28,6 @@ class TextContents final : public Contents {

void SetTextFrame(TextFrame frame);

void SetGlyphAtlas(std::shared_ptr<GlyphAtlas> atlas);

void SetGlyphAtlas(std::shared_ptr<LazyGlyphAtlas> atlas);

void SetColor(Color color);
Expand All @@ -42,14 +40,18 @@ 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_;
mutable std::variant<std::shared_ptr<GlyphAtlas>,
std::shared_ptr<LazyGlyphAtlas>>
atlas_;
mutable std::shared_ptr<LazyGlyphAtlas> lazy_atlas_;

std::shared_ptr<GlyphAtlas> ResolveAtlas(
GlyphAtlas::Type type,
std::shared_ptr<Context> context) const;

FML_DISALLOW_COPY_AND_ASSIGN(TextContents);
Expand Down
30 changes: 30 additions & 0 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "impeller/entity/contents/rrect_shadow_contents.h"
#include "impeller/entity/contents/solid_color_contents.h"
#include "impeller/entity/contents/solid_stroke_contents.h"
#include "impeller/entity/contents/text_contents.h"
#include "impeller/entity/contents/texture_contents.h"
#include "impeller/entity/contents/vertices_contents.h"
#include "impeller/entity/entity.h"
Expand All @@ -35,8 +36,11 @@
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/vertex_buffer_builder.h"
#include "impeller/tessellator/tessellator.h"
#include "impeller/typographer/backends/skia/text_frame_skia.h"
#include "impeller/typographer/backends/skia/text_render_context_skia.h"
#include "include/core/SkBlendMode.h"
#include "third_party/imgui/imgui.h"
#include "third_party/skia/include/core/SkTextBlob.h"

namespace impeller {
namespace testing {
Expand Down Expand Up @@ -1976,5 +1980,31 @@ 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);

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

} // namespace testing
} // namespace impeller
Loading