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

Commit 4f43d91

Browse files
committed
[Impeller] make strokes < 0.5 physical pixels visually thinner.
1 parent 965cb99 commit 4f43d91

10 files changed

+69
-22
lines changed

impeller/entity/contents/conical_gradient_contents.cc

+6-4
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,14 @@ bool ConicalGradientContents::RenderSSBO(const ContentContext& renderer,
7373
};
7474
return ColorSourceContents::DrawGeometry<VS>(
7575
renderer, entity, pass, pipeline_callback, frame_info,
76-
[this, &renderer](RenderPass& pass) {
76+
[this, &renderer, &entity](RenderPass& pass) {
7777
FS::FragInfo frag_info;
7878
frag_info.center = center_;
7979
frag_info.radius = radius_;
8080
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
8181
frag_info.decal_border_color = decal_border_color_;
82-
frag_info.alpha = GetOpacityFactor();
82+
frag_info.alpha =
83+
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
8384
if (focus_) {
8485
frag_info.focus = focus_.value();
8586
frag_info.focus_radius = focus_radius_;
@@ -127,15 +128,16 @@ bool ConicalGradientContents::RenderTexture(const ContentContext& renderer,
127128
};
128129
return ColorSourceContents::DrawGeometry<VS>(
129130
renderer, entity, pass, pipeline_callback, frame_info,
130-
[this, &renderer, &gradient_texture](RenderPass& pass) {
131+
[this, &renderer, &gradient_texture, &entity](RenderPass& pass) {
131132
FS::FragInfo frag_info;
132133
frag_info.center = center_;
133134
frag_info.radius = radius_;
134135
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
135136
frag_info.decal_border_color = decal_border_color_;
136137
frag_info.texture_sampler_y_coord_scale =
137138
gradient_texture->GetYCoordScale();
138-
frag_info.alpha = GetOpacityFactor();
139+
frag_info.alpha =
140+
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
139141
frag_info.half_texel =
140142
Vector2(0.5 / gradient_texture->GetSize().width,
141143
0.5 / gradient_texture->GetSize().height);

impeller/entity/contents/linear_gradient_contents.cc

+7-4
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ bool LinearGradientContents::RenderTexture(const ContentContext& renderer,
7777
};
7878
return ColorSourceContents::DrawGeometry<VS>(
7979
renderer, entity, pass, pipeline_callback, frame_info,
80-
[this, &renderer](RenderPass& pass) {
80+
[this, &renderer, &entity](RenderPass& pass) {
8181
auto gradient_data = CreateGradientBuffer(colors_, stops_);
8282
auto gradient_texture =
8383
CreateGradientTexture(gradient_data, renderer.GetContext());
@@ -92,7 +92,9 @@ bool LinearGradientContents::RenderTexture(const ContentContext& renderer,
9292
frag_info.decal_border_color = decal_border_color_;
9393
frag_info.texture_sampler_y_coord_scale =
9494
gradient_texture->GetYCoordScale();
95-
frag_info.alpha = GetOpacityFactor();
95+
frag_info.alpha =
96+
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
97+
;
9698
frag_info.half_texel =
9799
Vector2(0.5 / gradient_texture->GetSize().width,
98100
0.5 / gradient_texture->GetSize().height);
@@ -137,13 +139,14 @@ bool LinearGradientContents::RenderSSBO(const ContentContext& renderer,
137139
};
138140
return ColorSourceContents::DrawGeometry<VS>(
139141
renderer, entity, pass, pipeline_callback, frame_info,
140-
[this, &renderer](RenderPass& pass) {
142+
[this, &renderer, &entity](RenderPass& pass) {
141143
FS::FragInfo frag_info;
142144
frag_info.start_point = start_point_;
143145
frag_info.end_point = end_point_;
144146
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
145147
frag_info.decal_border_color = decal_border_color_;
146-
frag_info.alpha = GetOpacityFactor();
148+
frag_info.alpha =
149+
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
147150
frag_info.start_to_end = end_point_ - start_point_;
148151
frag_info.inverse_dot_start_to_end =
149152
CalculateInverseDotStartToEnd(start_point_, end_point_);

impeller/entity/contents/radial_gradient_contents.cc

+6-4
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,14 @@ bool RadialGradientContents::RenderSSBO(const ContentContext& renderer,
7979
};
8080
return ColorSourceContents::DrawGeometry<VS>(
8181
renderer, entity, pass, pipeline_callback, frame_info,
82-
[this, &renderer](RenderPass& pass) {
82+
[this, &renderer, &entity](RenderPass& pass) {
8383
FS::FragInfo frag_info;
8484
frag_info.center = center_;
8585
frag_info.radius = radius_;
8686
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
8787
frag_info.decal_border_color = decal_border_color_;
88-
frag_info.alpha = GetOpacityFactor();
88+
frag_info.alpha =
89+
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
8990

9091
auto& host_buffer = renderer.GetTransientsBuffer();
9192
auto colors = CreateGradientColors(colors_, stops_);
@@ -126,15 +127,16 @@ bool RadialGradientContents::RenderTexture(const ContentContext& renderer,
126127
};
127128
return ColorSourceContents::DrawGeometry<VS>(
128129
renderer, entity, pass, pipeline_callback, frame_info,
129-
[this, &renderer, &gradient_texture](RenderPass& pass) {
130+
[this, &renderer, &gradient_texture, &entity](RenderPass& pass) {
130131
FS::FragInfo frag_info;
131132
frag_info.center = center_;
132133
frag_info.radius = radius_;
133134
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
134135
frag_info.decal_border_color = decal_border_color_;
135136
frag_info.texture_sampler_y_coord_scale =
136137
gradient_texture->GetYCoordScale();
137-
frag_info.alpha = GetOpacityFactor();
138+
frag_info.alpha =
139+
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
138140
frag_info.half_texel =
139141
Vector2(0.5 / gradient_texture->GetSize().width,
140142
0.5 / gradient_texture->GetSize().height);

impeller/entity/contents/solid_color_contents.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ bool SolidColorContents::Render(const ContentContext& renderer,
5151
using VS = SolidFillPipeline::VertexShader;
5252

5353
VS::FrameInfo frame_info;
54-
frame_info.color = GetColor().Premultiply();
54+
frame_info.color =
55+
GetColor().Premultiply() * GetGeometry()->ComputeAlphaCoverage(entity);
5556

5657
PipelineBuilderCallback pipeline_callback =
5758
[&renderer](ContentContextOptions options) {

impeller/entity/contents/sweep_gradient_contents.cc

+6-4
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,15 @@ bool SweepGradientContents::RenderSSBO(const ContentContext& renderer,
8787
};
8888
return ColorSourceContents::DrawGeometry<VS>(
8989
renderer, entity, pass, pipeline_callback, frame_info,
90-
[this, &renderer](RenderPass& pass) {
90+
[this, &renderer, &entity](RenderPass& pass) {
9191
FS::FragInfo frag_info;
9292
frag_info.center = center_;
9393
frag_info.bias = bias_;
9494
frag_info.scale = scale_;
9595
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
9696
frag_info.decal_border_color = decal_border_color_;
97-
frag_info.alpha = GetOpacityFactor();
97+
frag_info.alpha =
98+
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
9899

99100
auto& host_buffer = renderer.GetTransientsBuffer();
100101
auto colors = CreateGradientColors(colors_, stops_);
@@ -136,7 +137,7 @@ bool SweepGradientContents::RenderTexture(const ContentContext& renderer,
136137
};
137138
return ColorSourceContents::DrawGeometry<VS>(
138139
renderer, entity, pass, pipeline_callback, frame_info,
139-
[this, &renderer, &gradient_texture](RenderPass& pass) {
140+
[this, &renderer, &gradient_texture, &entity](RenderPass& pass) {
140141
FS::FragInfo frag_info;
141142
frag_info.center = center_;
142143
frag_info.bias = bias_;
@@ -145,7 +146,8 @@ bool SweepGradientContents::RenderTexture(const ContentContext& renderer,
145146
gradient_texture->GetYCoordScale();
146147
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
147148
frag_info.decal_border_color = decal_border_color_;
148-
frag_info.alpha = GetOpacityFactor();
149+
frag_info.alpha =
150+
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
149151
frag_info.half_texel =
150152
Vector2(0.5 / gradient_texture->GetSize().width,
151153
0.5 / gradient_texture->GetSize().height);

impeller/entity/contents/tiled_texture_contents.cc

+5-3
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ bool TiledTextureContents::Render(const ContentContext& renderer,
150150
};
151151
return ColorSourceContents::DrawGeometry<VS>(
152152
renderer, entity, pass, pipeline_callback, frame_info,
153-
[this, &renderer, &is_external_texture](RenderPass& pass) {
153+
[this, &renderer, &is_external_texture, &entity](RenderPass& pass) {
154154
auto& host_buffer = renderer.GetTransientsBuffer();
155155

156156
pass.SetCommandLabel("TextureFill");
@@ -159,13 +159,15 @@ bool TiledTextureContents::Render(const ContentContext& renderer,
159159
FSExternal::FragInfo frag_info;
160160
frag_info.x_tile_mode = static_cast<Scalar>(x_tile_mode_);
161161
frag_info.y_tile_mode = static_cast<Scalar>(y_tile_mode_);
162-
frag_info.alpha = GetOpacityFactor();
162+
frag_info.alpha =
163+
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
163164
FSExternal::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
164165
} else {
165166
FS::FragInfo frag_info;
166167
frag_info.x_tile_mode = static_cast<Scalar>(x_tile_mode_);
167168
frag_info.y_tile_mode = static_cast<Scalar>(y_tile_mode_);
168-
frag_info.alpha = GetOpacityFactor();
169+
frag_info.alpha =
170+
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
169171
FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
170172
}
171173

impeller/entity/geometry/geometry.h

+4
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ class Geometry {
107107

108108
virtual bool CanApplyMaskFilter() const;
109109

110+
virtual Scalar ComputeAlphaCoverage(const Entity& entitys) const {
111+
return 1.0;
112+
}
113+
110114
protected:
111115
static GeometryResult ComputePositionGeometry(
112116
const ContentContext& renderer,

impeller/entity/geometry/geometry_unittests.cc

+18
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
#include <memory>
66
#include "flutter/testing/testing.h"
7+
#include "gtest/gtest.h"
78
#include "impeller/entity/contents/content_context.h"
89
#include "impeller/entity/geometry/geometry.h"
910
#include "impeller/entity/geometry/stroke_path_geometry.h"
11+
#include "impeller/geometry/constants.h"
1012
#include "impeller/geometry/geometry_asserts.h"
1113
#include "impeller/geometry/path_builder.h"
1214
#include "impeller/renderer/testing/mocks.h"
@@ -134,5 +136,21 @@ TEST(EntityGeometryTest, GeometryResultHasReasonableDefaults) {
134136
EXPECT_EQ(result.mode, GeometryResult::Mode::kNormal);
135137
}
136138

139+
TEST(EntityGeometryTest, AlphaCoverageStrokePaths) {
140+
Entity entity;
141+
entity.SetTransform(Matrix::MakeScale(Vector2{3.0, 3.0}));
142+
EXPECT_EQ(Geometry::MakeStrokePath({}, 0.5)->ComputeAlphaCoverage(entity), 1);
143+
EXPECT_EQ(Geometry::MakeStrokePath({}, 0.1)->ComputeAlphaCoverage(entity), 1);
144+
EXPECT_EQ(Geometry::MakeStrokePath({}, 0.05)->ComputeAlphaCoverage(entity),
145+
1);
146+
EXPECT_NEAR(Geometry::MakeStrokePath({}, 0.01)->ComputeAlphaCoverage(entity),
147+
0.6, 0.1);
148+
EXPECT_NEAR(
149+
Geometry::MakeStrokePath({}, 0.0000005)->ComputeAlphaCoverage(entity),
150+
1e-05, 0.001);
151+
EXPECT_EQ(Geometry::MakeStrokePath({}, 0)->ComputeAlphaCoverage(entity), 1);
152+
EXPECT_EQ(Geometry::MakeStrokePath({}, 40)->ComputeAlphaCoverage(entity), 1);
153+
}
154+
137155
} // namespace testing
138156
} // namespace impeller

impeller/entity/geometry/stroke_path_geometry.cc

+13-2
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,18 @@ Join StrokePathGeometry::GetStrokeJoin() const {
525525
return stroke_join_;
526526
}
527527

528+
Scalar StrokePathGeometry::ComputeAlphaCoverage(const Entity& entity) const {
529+
Scalar scaled_stroke_width =
530+
entity.GetTransform().GetMaxBasisLengthXY() * stroke_width_;
531+
// If the stroke width is 0 or greater than kMinStrokeSizeMSAA, don't apply
532+
// any additional alpha. This is intended to match Skia behavior.
533+
if (scaled_stroke_width == 0.0 || scaled_stroke_width >= kMinStrokeSizeMSAA) {
534+
return 1.0;
535+
}
536+
// This scalling is eyeballed from Skia.
537+
return std::clamp(scaled_stroke_width * 20.0f, 0.f, 1.f);
538+
}
539+
528540
GeometryResult StrokePathGeometry::GetPositionBuffer(
529541
const ContentContext& renderer,
530542
const Entity& entity,
@@ -568,8 +580,7 @@ GeometryResult StrokePathGeometry::GetPositionBuffer(
568580
.index_type = IndexType::kNone,
569581
},
570582
.transform = entity.GetShaderTransform(pass),
571-
.mode = GeometryResult::Mode::kPreventOverdraw,
572-
};
583+
.mode = GeometryResult::Mode::kPreventOverdraw};
573584
}
574585

575586
GeometryResult::Mode StrokePathGeometry::GetResultMode() const {

impeller/entity/geometry/stroke_path_geometry.h

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class StrokePathGeometry final : public Geometry {
2828

2929
Join GetStrokeJoin() const;
3030

31+
Scalar ComputeAlphaCoverage(const Entity& entity) const override;
32+
3133
private:
3234
// |Geometry|
3335
GeometryResult GetPositionBuffer(const ContentContext& renderer,

0 commit comments

Comments
 (0)