[Impeller] delete special handling of RRect. (flutter/engine#41872)
The convex path tessellator is more general purpose than the RRect and shouldn't be any slower. BY removing this class, we make it easier to switch to GPU polyline generation and tessellation for convex shapes.
This commit is contained in:
@@ -241,18 +241,22 @@ void Canvas::DrawRRect(Rect rect, Scalar corner_radius, const Paint& paint) {
|
||||
if (AttemptDrawBlurredRRect(rect, corner_radius, paint)) {
|
||||
return;
|
||||
}
|
||||
auto path = PathBuilder{}
|
||||
.SetConvexity(Convexity::kConvex)
|
||||
.AddRoundedRect(rect, corner_radius)
|
||||
.TakePath();
|
||||
if (paint.style == Paint::Style::kFill) {
|
||||
Entity entity;
|
||||
entity.SetTransformation(GetCurrentTransformation());
|
||||
entity.SetStencilDepth(GetStencilDepth());
|
||||
entity.SetBlendMode(paint.blend_mode);
|
||||
entity.SetContents(paint.WithFilters(paint.CreateContentsForGeometry(
|
||||
Geometry::MakeRRect(rect, corner_radius))));
|
||||
entity.SetContents(paint.WithFilters(
|
||||
paint.CreateContentsForGeometry(Geometry::MakeFillPath(path))));
|
||||
|
||||
GetCurrentPass().AddEntity(entity);
|
||||
return;
|
||||
}
|
||||
DrawPath(PathBuilder{}.AddRoundedRect(rect, corner_radius).TakePath(), paint);
|
||||
DrawPath(path, paint);
|
||||
}
|
||||
|
||||
void Canvas::DrawCircle(Point center, Scalar radius, const Paint& paint) {
|
||||
@@ -293,7 +297,11 @@ void Canvas::ClipRect(const Rect& rect, Entity::ClipOperation clip_op) {
|
||||
void Canvas::ClipRRect(const Rect& rect,
|
||||
Scalar corner_radius,
|
||||
Entity::ClipOperation clip_op) {
|
||||
ClipGeometry(Geometry::MakeRRect(rect, corner_radius), clip_op);
|
||||
auto path = PathBuilder{}
|
||||
.SetConvexity(Convexity::kConvex)
|
||||
.AddRoundedRect(rect, corner_radius)
|
||||
.TakePath();
|
||||
ClipGeometry(Geometry::MakeFillPath(path), clip_op);
|
||||
switch (clip_op) {
|
||||
case Entity::ClipOperation::kIntersect:
|
||||
IntersectCulling(rect);
|
||||
|
||||
@@ -224,7 +224,11 @@ TEST_P(EntityTest, CanDrawRect) {
|
||||
|
||||
TEST_P(EntityTest, CanDrawRRect) {
|
||||
auto contents = std::make_shared<SolidColorContents>();
|
||||
contents->SetGeometry(Geometry::MakeRRect({100, 100, 100, 100}, 10.0));
|
||||
auto path = PathBuilder{}
|
||||
.SetConvexity(Convexity::kConvex)
|
||||
.AddRoundedRect({100, 100, 100, 100}, 10.0)
|
||||
.TakePath();
|
||||
contents->SetGeometry(Geometry::MakeFillPath(path));
|
||||
contents->SetColor(Color::Red());
|
||||
|
||||
Entity entity;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace impeller {
|
||||
std::pair<std::vector<Point>, std::vector<uint16_t>> TessellateConvex(
|
||||
Path::Polyline polyline) {
|
||||
std::vector<Point> output;
|
||||
std::vector<uint16_t> index;
|
||||
std::vector<uint16_t> indices;
|
||||
|
||||
for (auto j = 0u; j < polyline.contours.size(); j++) {
|
||||
auto [start, end] = polyline.GetContourPointBounds(j);
|
||||
@@ -39,12 +39,12 @@ std::pair<std::vector<Point>, std::vector<uint16_t>> TessellateConvex(
|
||||
const auto& point_b = polyline.points[i];
|
||||
output.emplace_back(point_b);
|
||||
|
||||
index.emplace_back(0);
|
||||
index.emplace_back(i - 1);
|
||||
index.emplace_back(i);
|
||||
indices.emplace_back(0);
|
||||
indices.emplace_back(i - 1);
|
||||
indices.emplace_back(i);
|
||||
}
|
||||
}
|
||||
return std::make_pair(output, index);
|
||||
return std::make_pair(output, indices);
|
||||
}
|
||||
|
||||
Geometry::Geometry() = default;
|
||||
@@ -64,11 +64,6 @@ std::unique_ptr<Geometry> Geometry::MakeFillPath(const Path& path) {
|
||||
return std::make_unique<FillPathGeometry>(path);
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<Geometry> Geometry::MakeRRect(Rect rect, Scalar corner_radius) {
|
||||
return std::make_unique<RRectGeometry>(rect, corner_radius);
|
||||
}
|
||||
|
||||
std::unique_ptr<Geometry> Geometry::MakeStrokePath(const Path& path,
|
||||
Scalar stroke_width,
|
||||
Scalar miter_limit,
|
||||
@@ -139,14 +134,14 @@ GeometryResult FillPathGeometry::GetPositionBuffer(
|
||||
|
||||
if (path_.GetFillType() == FillType::kNonZero && //
|
||||
path_.IsConvex()) {
|
||||
auto [points, indicies] = TessellateConvex(
|
||||
auto [points, indices] = TessellateConvex(
|
||||
path_.CreatePolyline(entity.GetTransformation().GetMaxBasisLength()));
|
||||
|
||||
vertex_buffer.vertex_buffer = host_buffer.Emplace(
|
||||
points.data(), points.size() * sizeof(Point), alignof(Point));
|
||||
vertex_buffer.index_buffer = host_buffer.Emplace(
|
||||
indicies.data(), indicies.size() * sizeof(uint16_t), alignof(uint16_t));
|
||||
vertex_buffer.index_count = indicies.size();
|
||||
indices.data(), indices.size() * sizeof(uint16_t), alignof(uint16_t));
|
||||
vertex_buffer.index_count = indices.size();
|
||||
vertex_buffer.index_type = IndexType::k16bit;
|
||||
|
||||
return GeometryResult{
|
||||
@@ -193,6 +188,37 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer(
|
||||
RenderPass& pass) {
|
||||
using VS = TextureFillVertexShader;
|
||||
|
||||
if (path_.GetFillType() == FillType::kNonZero && //
|
||||
path_.IsConvex()) {
|
||||
auto [points, indices] = TessellateConvex(
|
||||
path_.CreatePolyline(entity.GetTransformation().GetMaxBasisLength()));
|
||||
|
||||
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
|
||||
vertex_builder.Reserve(points.size());
|
||||
vertex_builder.ReserveIndices(indices.size());
|
||||
for (auto i = 0u; i < points.size(); i++) {
|
||||
VS::PerVertexData data;
|
||||
data.position = points[i];
|
||||
auto coverage_coords =
|
||||
((points[i] - texture_coverage.origin) / texture_coverage.size) /
|
||||
texture_coverage.size;
|
||||
data.texture_coords = effect_transform * coverage_coords;
|
||||
vertex_builder.AppendVertex(data);
|
||||
}
|
||||
for (auto i = 0u; i < indices.size(); i++) {
|
||||
vertex_builder.AppendIndex(indices[i]);
|
||||
}
|
||||
|
||||
return GeometryResult{
|
||||
.type = PrimitiveType::kTriangle,
|
||||
.vertex_buffer =
|
||||
vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer()),
|
||||
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
|
||||
entity.GetTransformation(),
|
||||
.prevent_overdraw = false,
|
||||
};
|
||||
}
|
||||
|
||||
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
|
||||
auto tesselation_result = renderer.GetTessellator()->Tessellate(
|
||||
path_.GetFillType(),
|
||||
@@ -777,163 +803,4 @@ std::optional<Rect> RectGeometry::GetCoverage(const Matrix& transform) const {
|
||||
return rect_.TransformBounds(transform);
|
||||
}
|
||||
|
||||
/////// RRect Geometry ///////
|
||||
|
||||
RRectGeometry::RRectGeometry(Rect rect, Scalar corner_radius)
|
||||
: rect_(rect), corner_radius_(corner_radius) {}
|
||||
|
||||
RRectGeometry::~RRectGeometry() = default;
|
||||
|
||||
static void AppendRRectCorner(Path::Polyline polyline,
|
||||
Point corner,
|
||||
VertexBufferBuilder<Point>& vtx_builder) {
|
||||
for (auto i = 1u; i < polyline.points.size(); i++) {
|
||||
vtx_builder.AddVertices({
|
||||
polyline.points[i - 1],
|
||||
polyline.points[i],
|
||||
corner,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
VertexBufferBuilder<Point> RRectGeometry::CreatePositionBuffer(
|
||||
const Entity& entity) const {
|
||||
VertexBufferBuilder<Point> vtx_builder;
|
||||
|
||||
// The rounded rectangle is split into parts:
|
||||
// * four corner sections defined by an arc
|
||||
// * An interior shape composed of three rectangles.
|
||||
|
||||
auto left = rect_.GetLeft();
|
||||
auto right = rect_.GetRight();
|
||||
auto bottom = rect_.GetBottom();
|
||||
auto top = rect_.GetTop();
|
||||
auto radii = PathBuilder::RoundingRadii(corner_radius_, corner_radius_,
|
||||
corner_radius_, corner_radius_);
|
||||
|
||||
auto topLeft =
|
||||
PathBuilder{}
|
||||
.MoveTo({rect_.origin.x, rect_.origin.y + corner_radius_})
|
||||
.AddRoundedRectTopLeft(rect_, radii)
|
||||
.TakePath()
|
||||
.CreatePolyline(entity.GetTransformation().GetMaxBasisLength());
|
||||
auto topRight =
|
||||
PathBuilder{}
|
||||
.MoveTo({right - radii.top_right.x, rect_.origin.y})
|
||||
.AddRoundedRectTopRight(rect_, radii)
|
||||
.TakePath()
|
||||
.CreatePolyline(entity.GetTransformation().GetMaxBasisLength());
|
||||
auto bottomLeft =
|
||||
PathBuilder{}
|
||||
.MoveTo({left + corner_radius_, bottom})
|
||||
.AddRoundedRectBottomLeft(rect_, radii)
|
||||
.TakePath()
|
||||
.CreatePolyline(entity.GetTransformation().GetMaxBasisLength());
|
||||
auto bottomRight =
|
||||
PathBuilder{}
|
||||
.MoveTo({right, bottom - corner_radius_})
|
||||
.AddRoundedRectBottomRight(rect_, radii)
|
||||
.TakePath()
|
||||
.CreatePolyline(entity.GetTransformation().GetMaxBasisLength());
|
||||
|
||||
vtx_builder.Reserve(12 * (topLeft.points.size() - 1) + 18);
|
||||
|
||||
AppendRRectCorner(topLeft, Point(left + corner_radius_, top + corner_radius_),
|
||||
vtx_builder);
|
||||
|
||||
AppendRRectCorner(topRight,
|
||||
Point(right - corner_radius_, top + corner_radius_),
|
||||
vtx_builder);
|
||||
|
||||
AppendRRectCorner(bottomLeft,
|
||||
Point(left + corner_radius_, bottom - corner_radius_),
|
||||
vtx_builder);
|
||||
|
||||
AppendRRectCorner(bottomRight,
|
||||
Point(right - corner_radius_, bottom - corner_radius_),
|
||||
vtx_builder);
|
||||
vtx_builder.AddVertices({
|
||||
// Top Component.
|
||||
Point(left + corner_radius_, top + corner_radius_),
|
||||
Point(left + corner_radius_, top),
|
||||
Point(right - corner_radius_, top + corner_radius_),
|
||||
|
||||
Point(left + corner_radius_, top),
|
||||
Point(right - corner_radius_, top + corner_radius_),
|
||||
Point(right - corner_radius_, top),
|
||||
|
||||
// Bottom Component.
|
||||
Point(left + corner_radius_, bottom - corner_radius_),
|
||||
Point(left + corner_radius_, bottom),
|
||||
Point(right - corner_radius_, bottom - corner_radius_),
|
||||
|
||||
Point(left + corner_radius_, bottom),
|
||||
Point(right - corner_radius_, bottom - corner_radius_),
|
||||
Point(right - corner_radius_, bottom),
|
||||
|
||||
// // Center Component.
|
||||
Point(left, top + corner_radius_),
|
||||
Point(right, top + corner_radius_),
|
||||
Point(right, bottom - corner_radius_),
|
||||
|
||||
Point(left, top + corner_radius_),
|
||||
Point(left, bottom - corner_radius_),
|
||||
Point(right, bottom - corner_radius_),
|
||||
});
|
||||
|
||||
return vtx_builder;
|
||||
}
|
||||
|
||||
GeometryResult RRectGeometry::GetPositionBuffer(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass) {
|
||||
auto vtx_builder = CreatePositionBuffer(entity);
|
||||
|
||||
return GeometryResult{
|
||||
.type = PrimitiveType::kTriangle,
|
||||
.vertex_buffer =
|
||||
vtx_builder.CreateVertexBuffer(pass.GetTransientsBuffer()),
|
||||
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
|
||||
entity.GetTransformation(),
|
||||
.prevent_overdraw = false,
|
||||
};
|
||||
}
|
||||
|
||||
GeometryResult RRectGeometry::GetPositionUVBuffer(
|
||||
Rect texture_coverage,
|
||||
Matrix effect_transform,
|
||||
const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass) {
|
||||
auto vtx_builder = CreatePositionBuffer(entity);
|
||||
|
||||
VertexBufferBuilder<TextureFillVertexShader::PerVertexData> vertex_builder;
|
||||
vtx_builder.IterateVertices(
|
||||
[&vertex_builder, &texture_coverage, &effect_transform](Point position) {
|
||||
TextureFillVertexShader::PerVertexData data;
|
||||
data.position = position;
|
||||
auto coverage_coords =
|
||||
(position - texture_coverage.origin) / texture_coverage.size;
|
||||
data.texture_coords = effect_transform * coverage_coords;
|
||||
vertex_builder.AppendVertex(data);
|
||||
});
|
||||
|
||||
return GeometryResult{
|
||||
.type = PrimitiveType::kTriangle,
|
||||
.vertex_buffer =
|
||||
vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer()),
|
||||
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
|
||||
entity.GetTransformation(),
|
||||
.prevent_overdraw = true,
|
||||
};
|
||||
}
|
||||
|
||||
GeometryVertexType RRectGeometry::GetVertexType() const {
|
||||
return GeometryVertexType::kPosition;
|
||||
}
|
||||
|
||||
std::optional<Rect> RRectGeometry::GetCoverage(const Matrix& transform) const {
|
||||
return rect_.TransformBounds(transform);
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -46,8 +46,6 @@ class Geometry {
|
||||
|
||||
static std::unique_ptr<Geometry> MakeFillPath(const Path& path);
|
||||
|
||||
static std::unique_ptr<Geometry> MakeRRect(Rect rect, Scalar corner_radius);
|
||||
|
||||
static std::unique_ptr<Geometry> MakeStrokePath(
|
||||
const Path& path,
|
||||
Scalar stroke_width = 0.0,
|
||||
@@ -262,37 +260,4 @@ class RectGeometry : public Geometry {
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(RectGeometry);
|
||||
};
|
||||
|
||||
class RRectGeometry : public Geometry {
|
||||
public:
|
||||
explicit RRectGeometry(Rect rect, Scalar corner_radius);
|
||||
|
||||
~RRectGeometry();
|
||||
|
||||
private:
|
||||
// |Geometry|
|
||||
GeometryResult GetPositionBuffer(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass) override;
|
||||
|
||||
// |Geometry|
|
||||
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
|
||||
Matrix effect_transform,
|
||||
const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass) override;
|
||||
|
||||
// |Geometry|
|
||||
GeometryVertexType GetVertexType() const override;
|
||||
|
||||
// |Geometry|
|
||||
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
|
||||
|
||||
VertexBufferBuilder<Point> CreatePositionBuffer(const Entity& entity) const;
|
||||
|
||||
Rect rect_;
|
||||
Scalar corner_radius_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(RRectGeometry);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -104,14 +104,6 @@ class PathBuilder {
|
||||
|
||||
PathBuilder& AddRoundedRect(Rect rect, Scalar radius);
|
||||
|
||||
PathBuilder& AddRoundedRectTopLeft(Rect rect, RoundingRadii radii);
|
||||
|
||||
PathBuilder& AddRoundedRectTopRight(Rect rect, RoundingRadii radii);
|
||||
|
||||
PathBuilder& AddRoundedRectBottomRight(Rect rect, RoundingRadii radii);
|
||||
|
||||
PathBuilder& AddRoundedRectBottomLeft(Rect rect, RoundingRadii radii);
|
||||
|
||||
PathBuilder& AddPath(const Path& path);
|
||||
|
||||
private:
|
||||
@@ -120,6 +112,14 @@ class PathBuilder {
|
||||
Path prototype_;
|
||||
Convexity convexity_;
|
||||
|
||||
PathBuilder& AddRoundedRectTopLeft(Rect rect, RoundingRadii radii);
|
||||
|
||||
PathBuilder& AddRoundedRectTopRight(Rect rect, RoundingRadii radii);
|
||||
|
||||
PathBuilder& AddRoundedRectBottomRight(Rect rect, RoundingRadii radii);
|
||||
|
||||
PathBuilder& AddRoundedRectBottomLeft(Rect rect, RoundingRadii radii);
|
||||
|
||||
Point ReflectedQuadraticControlPoint1() const;
|
||||
|
||||
Point ReflectedCubicControlPoint1() const;
|
||||
|
||||
Reference in New Issue
Block a user