From ae75a375f2419d7a0fd3cf0555d243f94ccebc6e Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 10 May 2023 09:08:17 -0700 Subject: [PATCH] [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. --- engine/src/flutter/impeller/aiks/canvas.cc | 16 +- .../impeller/entity/entity_unittests.cc | 6 +- .../src/flutter/impeller/entity/geometry.cc | 211 ++++-------------- engine/src/flutter/impeller/entity/geometry.h | 35 --- .../flutter/impeller/geometry/path_builder.h | 16 +- 5 files changed, 64 insertions(+), 220 deletions(-) diff --git a/engine/src/flutter/impeller/aiks/canvas.cc b/engine/src/flutter/impeller/aiks/canvas.cc index 8ccf32f480..8ee384fc5a 100644 --- a/engine/src/flutter/impeller/aiks/canvas.cc +++ b/engine/src/flutter/impeller/aiks/canvas.cc @@ -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); diff --git a/engine/src/flutter/impeller/entity/entity_unittests.cc b/engine/src/flutter/impeller/entity/entity_unittests.cc index 1f0376e846..007664bbf3 100644 --- a/engine/src/flutter/impeller/entity/entity_unittests.cc +++ b/engine/src/flutter/impeller/entity/entity_unittests.cc @@ -224,7 +224,11 @@ TEST_P(EntityTest, CanDrawRect) { TEST_P(EntityTest, CanDrawRRect) { auto contents = std::make_shared(); - 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; diff --git a/engine/src/flutter/impeller/entity/geometry.cc b/engine/src/flutter/impeller/entity/geometry.cc index 8e568c3f2a..bfe5227329 100644 --- a/engine/src/flutter/impeller/entity/geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry.cc @@ -20,7 +20,7 @@ namespace impeller { std::pair, std::vector> TessellateConvex( Path::Polyline polyline) { std::vector output; - std::vector index; + std::vector indices; for (auto j = 0u; j < polyline.contours.size(); j++) { auto [start, end] = polyline.GetContourPointBounds(j); @@ -39,12 +39,12 @@ std::pair, std::vector> 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::MakeFillPath(const Path& path) { return std::make_unique(path); } -// static -std::unique_ptr Geometry::MakeRRect(Rect rect, Scalar corner_radius) { - return std::make_unique(rect, corner_radius); -} - std::unique_ptr 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 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 vertex_builder; auto tesselation_result = renderer.GetTessellator()->Tessellate( path_.GetFillType(), @@ -777,163 +803,4 @@ std::optional 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& vtx_builder) { - for (auto i = 1u; i < polyline.points.size(); i++) { - vtx_builder.AddVertices({ - polyline.points[i - 1], - polyline.points[i], - corner, - }); - } -} - -VertexBufferBuilder RRectGeometry::CreatePositionBuffer( - const Entity& entity) const { - VertexBufferBuilder 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 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 RRectGeometry::GetCoverage(const Matrix& transform) const { - return rect_.TransformBounds(transform); -} - } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry.h b/engine/src/flutter/impeller/entity/geometry.h index 53fd80ba96..e3dd56deda 100644 --- a/engine/src/flutter/impeller/entity/geometry.h +++ b/engine/src/flutter/impeller/entity/geometry.h @@ -46,8 +46,6 @@ class Geometry { static std::unique_ptr MakeFillPath(const Path& path); - static std::unique_ptr MakeRRect(Rect rect, Scalar corner_radius); - static std::unique_ptr 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 GetCoverage(const Matrix& transform) const override; - - VertexBufferBuilder CreatePositionBuffer(const Entity& entity) const; - - Rect rect_; - Scalar corner_radius_; - - FML_DISALLOW_COPY_AND_ASSIGN(RRectGeometry); -}; - } // namespace impeller diff --git a/engine/src/flutter/impeller/geometry/path_builder.h b/engine/src/flutter/impeller/geometry/path_builder.h index 56ac9f4dc3..52a9139f94 100644 --- a/engine/src/flutter/impeller/geometry/path_builder.h +++ b/engine/src/flutter/impeller/geometry/path_builder.h @@ -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;