Skip to content

Commit

Permalink
[Impeller] simplify text shaders by moving UV computation to contents (
Browse files Browse the repository at this point in the history
…#39989)

[Impeller] simplify text shaders by moving UV computation to contents
  • Loading branch information
jonahwilliams committed Mar 3, 2023
1 parent 6ca9dfd commit 7912b23
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 64 deletions.
32 changes: 21 additions & 11 deletions impeller/entity/contents/text_contents.cc
Expand Up @@ -58,6 +58,12 @@ std::optional<Rect> TextContents::GetCoverage(const Entity& entity) const {
return bounds->TransformBounds(entity.GetTransformation());
}

static Vector4 PositionForGlyphPosition(const Matrix& translation,
Point unit_position,
Size destination_size) {
return translation * (unit_position * destination_size);
}

template <class TPipeline>
static bool CommonRender(
const ContentContext& renderer,
Expand Down Expand Up @@ -94,9 +100,6 @@ static bool CommonRender(

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)};
FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info));

// Common fragment uniforms for all glyphs.
Expand Down Expand Up @@ -136,6 +139,10 @@ static bool CommonRender(
offset += 4;
}

auto atlas_size =
Point{static_cast<Scalar>(atlas->GetTexture()->GetSize().width),
static_cast<Scalar>(atlas->GetTexture()->GetSize().height)};

for (const auto& run : frame.GetRuns()) {
auto font = run.GetFont();

Expand All @@ -147,23 +154,26 @@ static bool CommonRender(
return false;
}

auto atlas_position = atlas_glyph_pos->origin;
auto atlas_glyph_size =
Point{atlas_glyph_pos->size.width, atlas_glyph_pos->size.height};
auto offset_glyph_position =
glyph_position.position + glyph_position.glyph.bounds.origin;

auto uv_scaler_a = atlas_glyph_pos->size / atlas_size;
auto uv_scaler_b = (Point::Round(atlas_glyph_pos->origin) / atlas_size);
auto translation = Matrix::MakeTranslation(
Vector3(offset_glyph_position.x, offset_glyph_position.y, 0));

for (const auto& point : unit_points) {
typename VS::PerVertexData vtx;
vtx.unit_position = point;
vtx.destination_position = offset_glyph_position;
vtx.destination_size = Point(glyph_position.glyph.bounds.size);
vtx.source_position = atlas_position;
vtx.source_glyph_size = atlas_glyph_size;
auto position = PositionForGlyphPosition(
translation, point, glyph_position.glyph.bounds.size);
vtx.uv = point * uv_scaler_a + uv_scaler_b;
vtx.position = position;

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));
}
}
Expand Down
20 changes: 5 additions & 15 deletions impeller/entity/shaders/glyph_atlas.frag
Expand Up @@ -7,29 +7,19 @@
uniform sampler2D glyph_atlas_sampler;

uniform FragInfo {
vec2 atlas_size;
vec4 text_color;
}
frag_info;

in vec2 v_unit_position;
in vec2 v_source_position;
in vec2 v_source_glyph_size;
in vec2 v_uv;
in float v_has_color;

out vec4 frag_color;

void main() {
vec2 uv_size = v_source_glyph_size / frag_info.atlas_size;
vec2 uv_position = v_source_position / frag_info.atlas_size;
if (v_has_color == 1.0) {
frag_color =
texture(glyph_atlas_sampler, v_unit_position * uv_size + uv_position) *
frag_info.text_color.a;
} else {
frag_color =
texture(glyph_atlas_sampler, v_unit_position * uv_size + uv_position)
.aaaa *
frag_info.text_color;
vec4 value = texture(glyph_atlas_sampler, v_uv);
if (v_has_color != 1.0) {
value = value.aaaa;
}
frag_color = value * frag_info.text_color;
}
19 changes: 5 additions & 14 deletions impeller/entity/shaders/glyph_atlas.vert
Expand Up @@ -10,24 +10,15 @@ uniform FrameInfo {
}
frame_info;

in vec2 unit_position;
in vec2 destination_position;
in vec2 destination_size;
in vec2 source_position;
in vec2 source_glyph_size;
in vec4 position;
in vec2 uv;
in float has_color;

out vec2 v_unit_position;
out vec2 v_source_position;
out vec2 v_source_glyph_size;
out vec2 v_uv;
out float v_has_color;

void main() {
gl_Position = IPPositionForGlyphPosition(
frame_info.mvp, unit_position, destination_position, destination_size);
v_unit_position = unit_position;
// Pixel snap the source (sampling) start position.
v_source_position = round(source_position);
v_source_glyph_size = source_glyph_size;
gl_Position = frame_info.mvp * position;
v_uv = uv;
v_has_color = has_color;
}
12 changes: 2 additions & 10 deletions impeller/entity/shaders/glyph_atlas_sdf.frag
Expand Up @@ -7,31 +7,23 @@
uniform sampler2D glyph_atlas_sampler;

uniform FragInfo {
vec2 atlas_size;
vec4 text_color;
}
frag_info;

in vec2 v_unit_position;
in vec2 v_source_position;
in vec2 v_source_glyph_size;
in vec2 v_uv;

out vec4 frag_color;

void main() {
vec2 scale_perspective = v_source_glyph_size / frag_info.atlas_size;
vec2 offset = v_source_position / frag_info.atlas_size;

// 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_unit_position * scale_perspective + offset)
.a;
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)));
Expand Down
18 changes: 5 additions & 13 deletions impeller/entity/shaders/glyph_atlas_sdf.vert
Expand Up @@ -11,20 +11,12 @@ uniform FrameInfo {
}
frame_info;

in vec2 unit_position;
in vec2 destination_position;
in vec2 destination_size;
in vec2 source_position;
in vec2 source_glyph_size;
in vec4 position;
in vec2 uv;

out vec2 v_unit_position;
out vec2 v_source_position;
out vec2 v_source_glyph_size;
out vec2 v_uv;

void main() {
gl_Position = IPPositionForGlyphPosition(
frame_info.mvp, unit_position, destination_position, destination_size);
v_unit_position = unit_position;
v_source_position = source_position;
v_source_glyph_size = source_glyph_size;
gl_Position = frame_info.mvp * position;
v_uv = uv;
}
6 changes: 6 additions & 0 deletions impeller/geometry/point.h
Expand Up @@ -38,6 +38,12 @@ struct TPoint {

static constexpr TPoint<Type> MakeXY(Type x, Type y) { return {x, y}; }

template <class U>
static constexpr TPoint Round(const TPoint<U>& other) {
return TPoint{static_cast<Type>(std::round(other.x)),
static_cast<Type>(std::round(other.y))};
}

constexpr bool operator==(const TPoint& p) const {
return p.x == x && p.y == y;
}
Expand Down
2 changes: 1 addition & 1 deletion impeller/tools/malioc.json

Large diffs are not rendered by default.

0 comments on commit 7912b23

Please sign in to comment.