Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit f81ac3b

Browse files
authored
Fix glyph sampling overlap (#37764)
1 parent a77dfaf commit f81ac3b

File tree

8 files changed

+104
-98
lines changed

8 files changed

+104
-98
lines changed

impeller/compiler/shader_lib/impeller/transform.glsl

+10-16
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,16 @@ vec2 IPVec2TransformPosition(mat4 matrix, vec2 point) {
1313

1414
// Returns the transformed gl_Position for a given glyph position in a glyph
1515
// atlas.
16-
vec4 IPPositionForGlyphPosition(mat4 mvp, vec2 unit_vertex, vec2 glyph_position, vec2 glyph_size) {
17-
vec4 translate = mvp[0] * glyph_position.x
18-
+ mvp[1] * glyph_position.y
19-
+ mvp[3];
20-
mat4 translated_mvp = mat4(
21-
mvp[0],
22-
mvp[1],
23-
mvp[2],
24-
vec4(
25-
translate.xyz,
26-
mvp[3].w
27-
)
28-
);
29-
return translated_mvp *
30-
vec4(unit_vertex.x * glyph_size.x,
31-
unit_vertex.y * glyph_size.y, 0.0, 1.0);
16+
vec4 IPPositionForGlyphPosition(mat4 mvp,
17+
vec2 unit_position,
18+
vec2 glyph_position,
19+
vec2 glyph_size) {
20+
vec4 translate =
21+
mvp[0] * glyph_position.x + mvp[1] * glyph_position.y + mvp[3];
22+
mat4 translated_mvp =
23+
mat4(mvp[0], mvp[1], mvp[2], vec4(translate.xyz, mvp[3].w));
24+
return translated_mvp * vec4(unit_position.x * glyph_size.x,
25+
unit_position.y * glyph_size.y, 0.0, 1.0);
3226
}
3327

3428
#endif

impeller/entity/contents/text_contents.cc

+13-14
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static bool CommonRender(
8080
SamplerDescriptor sampler_desc;
8181
sampler_desc.min_filter = MinMagFilter::kLinear;
8282
sampler_desc.mag_filter = MinMagFilter::kLinear;
83+
sampler_desc.mip_filter = MipFilter::kNone;
8384

8485
typename FS::FragInfo frag_info;
8586
frag_info.text_color = ToVector(color.Premultiply());
@@ -103,9 +104,9 @@ static bool CommonRender(
103104
// interpolated vertex information is also used in the fragment shader to
104105
// sample from the glyph atlas.
105106

106-
const std::vector<Point> unit_vertex_points = {
107-
{0, 0}, {1, 0}, {0, 1}, {1, 1}};
108-
const std::vector<uint32_t> indices = {0, 1, 2, 1, 2, 3};
107+
const std::array<Point, 4> unit_points = {Point{0, 0}, Point{1, 0},
108+
Point{0, 1}, Point{1, 1}};
109+
const std::array<uint32_t, 6> indices = {0, 1, 2, 1, 2, 3};
109110

110111
VertexBufferBuilder<typename VS::PerVertexData> vertex_builder;
111112

@@ -127,7 +128,7 @@ static bool CommonRender(
127128

128129
for (const auto& run : frame.GetRuns()) {
129130
auto font = run.GetFont();
130-
auto glyph_size_ = ISize::Ceil(font.GetMetrics().GetBoundingBox().size);
131+
auto glyph_size_ = font.GetMetrics().GetBoundingBox().size;
131132
auto glyph_size = Point{static_cast<Scalar>(glyph_size_.width),
132133
static_cast<Scalar>(glyph_size_.height)};
133134
auto metrics_offset =
@@ -141,22 +142,20 @@ static bool CommonRender(
141142
return false;
142143
}
143144

144-
auto atlas_position =
145-
atlas_glyph_pos->origin + Point{1 / atlas_glyph_pos->size.width,
146-
1 / atlas_glyph_pos->size.height};
145+
auto atlas_position = atlas_glyph_pos->origin;
147146
auto atlas_glyph_size =
148147
Point{atlas_glyph_pos->size.width, atlas_glyph_pos->size.height};
149148
auto offset_glyph_position = glyph_position.position + metrics_offset;
150149

151-
for (const auto& point : unit_vertex_points) {
150+
for (const auto& point : unit_points) {
152151
typename VS::PerVertexData vtx;
153-
vtx.unit_vertex = point;
154-
vtx.glyph_position = offset_glyph_position;
155-
vtx.glyph_size = glyph_size;
156-
vtx.atlas_position = atlas_position;
157-
vtx.atlas_glyph_size = atlas_glyph_size;
152+
vtx.unit_position = point;
153+
vtx.destination_position = offset_glyph_position + Point(0.5, 0.5);
154+
vtx.destination_size = glyph_size - Point(1.0, 1.0);
155+
vtx.source_position = atlas_position + Point(0.5, 0.5);
156+
vtx.source_glyph_size = atlas_glyph_size - Point(1.0, 1.0);
158157
if constexpr (std::is_same_v<TPipeline, GlyphAtlasPipeline>) {
159-
vtx.color_glyph =
158+
vtx.has_color =
160159
glyph_position.glyph.type == Glyph::Type::kBitmap ? 1.0 : 0.0;
161160
}
162161
vertex_builder.AppendVertex(std::move(vtx));

impeller/entity/shaders/glyph_atlas.frag

+14-16
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,25 @@ uniform sampler2D glyph_atlas_sampler;
77
uniform FragInfo {
88
vec2 atlas_size;
99
vec4 text_color;
10-
} frag_info;
10+
}
11+
frag_info;
1112

12-
in vec2 v_unit_vertex;
13-
in vec2 v_atlas_position;
14-
in vec2 v_atlas_glyph_size;
15-
in float v_color_glyph;
13+
in vec2 v_unit_position;
14+
in vec2 v_source_position;
15+
in vec2 v_source_glyph_size;
16+
in float v_has_color;
1617

1718
out vec4 frag_color;
1819

1920
void main() {
20-
vec2 scale_perspective = v_atlas_glyph_size / frag_info.atlas_size;
21-
vec2 offset = v_atlas_position / frag_info.atlas_size;
22-
if (v_color_glyph == 1.0) {
23-
frag_color = texture(
24-
glyph_atlas_sampler,
25-
v_unit_vertex * scale_perspective + offset
26-
);
21+
vec2 uv_size = v_source_glyph_size / frag_info.atlas_size;
22+
vec2 offset = v_source_position / frag_info.atlas_size;
23+
if (v_has_color == 1.0) {
24+
frag_color =
25+
texture(glyph_atlas_sampler, v_unit_position * uv_size + offset);
2726
} else {
28-
frag_color = texture(
29-
glyph_atlas_sampler,
30-
v_unit_vertex * scale_perspective + offset
31-
).aaaa * frag_info.text_color;
27+
frag_color =
28+
texture(glyph_atlas_sampler, v_unit_position * uv_size + offset).aaaa *
29+
frag_info.text_color;
3230
}
3331
}

impeller/entity/shaders/glyph_atlas.vert

+18-16
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,26 @@
66

77
uniform FrameInfo {
88
mat4 mvp;
9-
} frame_info;
9+
}
10+
frame_info;
1011

11-
in vec2 unit_vertex;
12-
in vec2 glyph_position;
13-
in vec2 glyph_size;
14-
in vec2 atlas_position;
15-
in vec2 atlas_glyph_size;
16-
in float color_glyph;
12+
in vec2 unit_position;
13+
in vec2 destination_position;
14+
in vec2 destination_size;
15+
in vec2 source_position;
16+
in vec2 source_glyph_size;
17+
in float has_color;
1718

18-
out vec2 v_unit_vertex;
19-
out vec2 v_atlas_position;
20-
out vec2 v_atlas_glyph_size;
21-
out float v_color_glyph;
19+
out vec2 v_unit_position;
20+
out vec2 v_source_position;
21+
out vec2 v_source_glyph_size;
22+
out float v_has_color;
2223

2324
void main() {
24-
gl_Position = IPPositionForGlyphPosition(frame_info.mvp, unit_vertex, glyph_position, glyph_size);
25-
v_unit_vertex = unit_vertex;
26-
v_atlas_position = atlas_position;
27-
v_atlas_glyph_size = atlas_glyph_size;
28-
v_color_glyph = color_glyph;
25+
gl_Position = IPPositionForGlyphPosition(
26+
frame_info.mvp, unit_position, destination_position, destination_size);
27+
v_unit_position = unit_position;
28+
v_source_position = source_position;
29+
v_source_glyph_size = source_glyph_size;
30+
v_has_color = has_color;
2931
}

impeller/entity/shaders/glyph_atlas_sdf.frag

+18-11
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,35 @@ uniform sampler2D glyph_atlas_sampler;
77
uniform FragInfo {
88
vec2 atlas_size;
99
vec4 text_color;
10-
} frag_info;
10+
}
11+
frag_info;
1112

12-
in vec2 v_unit_vertex;
13-
in vec2 v_atlas_position;
14-
in vec2 v_atlas_glyph_size;
13+
in vec2 v_unit_position;
14+
in vec2 v_source_position;
15+
in vec2 v_source_glyph_size;
1516

1617
out vec4 frag_color;
1718

1819
void main() {
19-
vec2 scale_perspective = v_atlas_glyph_size / frag_info.atlas_size;
20-
vec2 offset = v_atlas_position / frag_info.atlas_size;
20+
vec2 scale_perspective = v_source_glyph_size / frag_info.atlas_size;
21+
vec2 offset = v_source_position / frag_info.atlas_size;
2122

2223
// Inspired by Metal by Example's SDF text rendering shader:
2324
// https://github.com/metal-by-example/sample-code/blob/master/objc/12-TextRendering/TextRendering/Shaders.metal
2425

2526
// Outline of glyph is the isocontour with value 50%
2627
float edge_distance = 0.5;
27-
// Sample the signed-distance field to find distance from this fragment to the glyph outline
28-
float sample_distance = texture(glyph_atlas_sampler, v_unit_vertex * scale_perspective + offset).a;
29-
// Use local automatic gradients to find anti-aliased anisotropic edge width, cf. Gustavson 2012
28+
// Sample the signed-distance field to find distance from this fragment to the
29+
// glyph outline
30+
float sample_distance =
31+
texture(glyph_atlas_sampler, v_unit_position * scale_perspective + offset)
32+
.a;
33+
// Use local automatic gradients to find anti-aliased anisotropic edge width,
34+
// cf. Gustavson 2012
3035
float edge_width = length(vec2(dFdx(sample_distance), dFdy(sample_distance)));
31-
// Smooth the glyph edge by interpolating across the boundary in a band with the width determined above
32-
float insideness = smoothstep(edge_distance - edge_width, edge_distance + edge_width, sample_distance);
36+
// Smooth the glyph edge by interpolating across the boundary in a band with
37+
// the width determined above
38+
float insideness = smoothstep(edge_distance - edge_width,
39+
edge_distance + edge_width, sample_distance);
3340
frag_color = frag_info.text_color * insideness;
3441
}

impeller/entity/shaders/glyph_atlas_sdf.vert

+15-13
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,23 @@
66

77
uniform FrameInfo {
88
mat4 mvp;
9-
} frame_info;
9+
}
10+
frame_info;
1011

11-
in vec2 unit_vertex;
12-
in vec2 glyph_position;
13-
in vec2 glyph_size;
14-
in vec2 atlas_position;
15-
in vec2 atlas_glyph_size;
12+
in vec2 unit_position;
13+
in vec2 destination_position;
14+
in vec2 destination_size;
15+
in vec2 source_position;
16+
in vec2 source_glyph_size;
1617

17-
out vec2 v_unit_vertex;
18-
out vec2 v_atlas_position;
19-
out vec2 v_atlas_glyph_size;
18+
out vec2 v_unit_position;
19+
out vec2 v_source_position;
20+
out vec2 v_source_glyph_size;
2021

2122
void main() {
22-
gl_Position = IPPositionForGlyphPosition(frame_info.mvp, unit_vertex, glyph_position, glyph_size);
23-
v_unit_vertex = unit_vertex;
24-
v_atlas_position = atlas_position;
25-
v_atlas_glyph_size = atlas_glyph_size;
23+
gl_Position = IPPositionForGlyphPosition(
24+
frame_info.mvp, unit_position, destination_position, destination_size);
25+
v_unit_position = unit_position;
26+
v_source_position = source_position;
27+
v_source_glyph_size = source_glyph_size;
2628
}

impeller/fixtures/struct_def_bug.vert

+9-9
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@ uniform FrameInfo {
1010

1111
in vec2 unit_vertex;
1212
in mat4 glyph_position; // <--- Causes multiple slots to be used and is a failure.
13-
in vec2 glyph_size;
14-
in vec2 atlas_position;
15-
in vec2 atlas_glyph_size;
13+
in vec2 destination_size;
14+
in vec2 source_position;
15+
in vec2 source_glyph_size;
1616

1717
out vec2 v_unit_vertex;
18-
out vec2 v_atlas_position;
19-
out vec2 v_atlas_glyph_size;
18+
out vec2 v_source_position;
19+
out vec2 v_source_glyph_size;
2020
out vec2 v_atlas_size;
2121
out vec4 v_text_color;
2222

2323
void main() {
2424
gl_Position = frame_info.mvp
2525
* glyph_position
26-
* vec4(unit_vertex.x * glyph_size.x,
27-
unit_vertex.y * glyph_size.y, 0.0, 1.0);
26+
* vec4(unit_vertex.x * destination_size.x,
27+
unit_vertex.y * destination_size.y, 0.0, 1.0);
2828

2929
v_unit_vertex = unit_vertex;
30-
v_atlas_position = atlas_position;
31-
v_atlas_glyph_size = atlas_glyph_size;
30+
v_source_position = source_position;
31+
v_source_glyph_size = source_glyph_size;
3232
v_atlas_size = frame_info.atlas_size;
3333
v_text_color = frame_info.text_color;
3434
}

impeller/typographer/backends/skia/text_render_context_skia.cc

+7-3
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,19 @@ static size_t PairsFitInAtlasOfSize(const FontGlyphPair::Vector& pairs,
7171
glyph_positions.clear();
7272
glyph_positions.reserve(pairs.size());
7373

74+
// TODO(114563): We might be able to remove this per-glyph padding if we fix
75+
// the underlying causes of the overlap.
76+
constexpr auto padding = 2;
77+
7478
for (size_t i = 0; i < pairs.size(); i++) {
7579
const auto& pair = pairs[i];
7680
const auto glyph_size =
7781
ISize::Ceil(pair.font.GetMetrics().GetBoundingBox().size *
7882
pair.font.GetMetrics().scale);
7983
SkIPoint16 location_in_atlas;
80-
if (!rect_packer->addRect(glyph_size.width, //
81-
glyph_size.height, //
82-
&location_in_atlas //
84+
if (!rect_packer->addRect(glyph_size.width + padding, //
85+
glyph_size.height + padding, //
86+
&location_in_atlas //
8387
)) {
8488
return pairs.size() - i;
8589
}

0 commit comments

Comments
 (0)