From b1dcbda64e7d842d07b8041fd3dc061c28fb559c Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 30 Sep 2022 13:53:17 -0700 Subject: [PATCH] [Impeller] Create the tessellator in the ContentsContext and reuse, reduce initial bucket size. (flutter/engine#36534) --- .../impeller/entity/contents/clip_contents.cc | 2 +- .../entity/contents/content_context.cc | 8 ++- .../entity/contents/content_context.h | 5 ++ .../contents/linear_gradient_contents.cc | 1 + .../contents/radial_gradient_contents.cc | 1 + .../entity/contents/solid_color_contents.cc | 1 + .../entity/contents/solid_fill_utils.h | 6 +- .../contents/sweep_gradient_contents.cc | 1 + .../entity/contents/texture_contents.cc | 2 +- .../entity/contents/tiled_texture_contents.cc | 1 + .../impeller/tessellator/c/tessellator.cc | 1 - .../impeller/tessellator/tessellator.cc | 61 ++++++++++++------- .../impeller/tessellator/tessellator.h | 9 +++ .../tessellator/tessellator_unittests.cc | 16 +++++ 14 files changed, 87 insertions(+), 28 deletions(-) diff --git a/engine/src/flutter/impeller/entity/contents/clip_contents.cc b/engine/src/flutter/impeller/entity/contents/clip_contents.cc index b9928fe84d4..1914b833530 100644 --- a/engine/src/flutter/impeller/entity/contents/clip_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/clip_contents.cc @@ -120,7 +120,7 @@ bool ClipContents::Render(const ContentContext& renderer, cmd.pipeline = renderer.GetClipPipeline(options); cmd.BindVertices(CreateSolidFillVertices( - path_, pass.GetTransientsBuffer())); + renderer.GetTessellator(), path_, pass.GetTransientsBuffer())); info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(); diff --git a/engine/src/flutter/impeller/entity/contents/content_context.cc b/engine/src/flutter/impeller/entity/contents/content_context.cc index b3b9e205a37..adc57b746cc 100644 --- a/engine/src/flutter/impeller/entity/contents/content_context.cc +++ b/engine/src/flutter/impeller/entity/contents/content_context.cc @@ -11,6 +11,7 @@ #include "impeller/renderer/formats.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" +#include "impeller/tessellator/tessellator.h" namespace impeller { @@ -142,7 +143,8 @@ static std::unique_ptr CreateDefaultPipeline( } ContentContext::ContentContext(std::shared_ptr context) - : context_(std::move(context)) { + : context_(std::move(context)), + tessellator_(std::make_shared()) { if (!context_ || !context_->IsValid()) { return; } @@ -285,6 +287,10 @@ std::shared_ptr ContentContext::MakeSubpass( return subpass_texture; } +std::shared_ptr ContentContext::GetTessellator() const { + return tessellator_; +} + std::shared_ptr ContentContext::GetContext() const { return context_; } diff --git a/engine/src/flutter/impeller/entity/contents/content_context.h b/engine/src/flutter/impeller/entity/contents/content_context.h index 83089ad08aa..ce96fde7721 100644 --- a/engine/src/flutter/impeller/entity/contents/content_context.h +++ b/engine/src/flutter/impeller/entity/contents/content_context.h @@ -183,6 +183,8 @@ struct ContentContextOptions { void ApplyToPipelineDescriptor(PipelineDescriptor& desc) const; }; +class Tessellator; + class ContentContext { public: explicit ContentContext(std::shared_ptr context); @@ -191,6 +193,8 @@ class ContentContext { bool IsValid() const; + std::shared_ptr GetTessellator() const; + std::shared_ptr> GetLinearGradientFillPipeline( ContentContextOptions opts) const { return GetPipeline(linear_gradient_fill_pipelines_, opts); @@ -458,6 +462,7 @@ class ContentContext { } bool is_valid_ = false; + std::shared_ptr tessellator_; FML_DISALLOW_COPY_AND_ASSIGN(ContentContext); }; diff --git a/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc b/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc index 18fdf1fd601..94de5fc8dd4 100644 --- a/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc @@ -78,6 +78,7 @@ bool LinearGradientContents::Render(const ContentContext& renderer, OptionsFromPassAndEntity(pass, entity)); cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(CreateSolidFillVertices( + renderer.GetTessellator(), GetCover() ? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath() : GetPath(), diff --git a/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.cc b/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.cc index 4a82933ff18..4ea83c93bae 100644 --- a/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.cc @@ -77,6 +77,7 @@ bool RadialGradientContents::Render(const ContentContext& renderer, OptionsFromPassAndEntity(pass, entity)); cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(CreateSolidFillVertices( + renderer.GetTessellator(), GetCover() ? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath() : GetPath(), diff --git a/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc b/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc index e24c6c2edaa..57f022e15bb 100644 --- a/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc @@ -63,6 +63,7 @@ bool SolidColorContents::Render(const ContentContext& renderer, cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(CreateSolidFillVertices( + renderer.GetTessellator(), cover_ ? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath() : path_, diff --git a/engine/src/flutter/impeller/entity/contents/solid_fill_utils.h b/engine/src/flutter/impeller/entity/contents/solid_fill_utils.h index 2a8382fe532..6b5fb427398 100644 --- a/engine/src/flutter/impeller/entity/contents/solid_fill_utils.h +++ b/engine/src/flutter/impeller/entity/contents/solid_fill_utils.h @@ -10,10 +10,12 @@ namespace impeller { template -VertexBuffer CreateSolidFillVertices(const Path& path, HostBuffer& buffer) { +VertexBuffer CreateSolidFillVertices(std::shared_ptr tessellator, + const Path& path, + HostBuffer& buffer) { VertexBufferBuilder vtx_builder; - auto tesselation_result = Tessellator{}.Tessellate( + auto tesselation_result = tessellator->Tessellate( path.GetFillType(), path.CreatePolyline(), [&vtx_builder](auto point) { vtx_builder.AppendVertex({point}); }); if (tesselation_result != Tessellator::Result::kSuccess) { diff --git a/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.cc b/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.cc index dfeff8e9260..fc6bf4aac48 100644 --- a/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.cc @@ -84,6 +84,7 @@ bool SweepGradientContents::Render(const ContentContext& renderer, OptionsFromPassAndEntity(pass, entity)); cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(CreateSolidFillVertices( + renderer.GetTessellator(), GetCover() ? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath() : GetPath(), diff --git a/engine/src/flutter/impeller/entity/contents/texture_contents.cc b/engine/src/flutter/impeller/entity/contents/texture_contents.cc index 282e8c0a54f..119a921bbe5 100644 --- a/engine/src/flutter/impeller/entity/contents/texture_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/texture_contents.cc @@ -116,7 +116,7 @@ bool TextureContents::Render(const ContentContext& renderer, VertexBufferBuilder vertex_builder; { - const auto tess_result = Tessellator{}.Tessellate( + const auto tess_result = renderer.GetTessellator()->Tessellate( path_.GetFillType(), path_.CreatePolyline(), [this, &vertex_builder, &coverage_rect, &texture_size](Point vtx) { VS::PerVertexData data; diff --git a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc index 52c60a5cd57..ab4286d61b6 100644 --- a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc @@ -68,6 +68,7 @@ bool TiledTextureContents::Render(const ContentContext& renderer, renderer.GetTiledTexturePipeline(OptionsFromPassAndEntity(pass, entity)); cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(CreateSolidFillVertices( + renderer.GetTessellator(), GetCover() ? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath() : GetPath(), diff --git a/engine/src/flutter/impeller/tessellator/c/tessellator.cc b/engine/src/flutter/impeller/tessellator/c/tessellator.cc index bb11fb145c8..7a53d9ceded 100644 --- a/engine/src/flutter/impeller/tessellator/c/tessellator.cc +++ b/engine/src/flutter/impeller/tessellator/c/tessellator.cc @@ -45,7 +45,6 @@ struct Vertices* Tessellate(PathBuilder* builder, auto path = builder->CopyPath(static_cast(fill_type)); auto smoothing = SmoothingApproximation(scale, angle_tolerance, cusp_limit); auto polyline = path.CreatePolyline(smoothing); - std::vector points; if (Tessellator{}.Tessellate(path.GetFillType(), polyline, [&points](Point vertex) { diff --git a/engine/src/flutter/impeller/tessellator/tessellator.cc b/engine/src/flutter/impeller/tessellator/tessellator.cc index 0b4176f9309..603532d095c 100644 --- a/engine/src/flutter/impeller/tessellator/tessellator.cc +++ b/engine/src/flutter/impeller/tessellator/tessellator.cc @@ -8,7 +8,31 @@ namespace impeller { -Tessellator::Tessellator() = default; +static void* HeapAlloc(void* userData, unsigned int size) { + return malloc(size); +} + +static void* HeapRealloc(void* userData, void* ptr, unsigned int size) { + return realloc(ptr, size); +} + +static void HeapFree(void* userData, void* ptr) { + free(ptr); +} + +// Note: these units are "number of entities" for bucket size and not in KB. +static TESSalloc alloc = { + HeapAlloc, HeapRealloc, HeapFree, 0, /* =userData */ + 16, /* =meshEdgeBucketSize */ + 16, /* =meshVertexBucketSize */ + 16, /* =meshFaceBucketSize */ + 16, /* =dictNodeBucketSize */ + 16, /* =regionBucketSize */ + 0 /* =extraVertices */ +}; + +Tessellator::Tessellator() + : c_tessellator_(::tessNewTess(&alloc), &DestroyTessellator) {} Tessellator::~Tessellator() = default; @@ -28,12 +52,6 @@ static int ToTessWindingRule(FillType fill_type) { return TESS_WINDING_ODD; } -static void DestroyTessellator(TESStesselator* tessellator) { - if (tessellator != nullptr) { - ::tessDeleteTess(tessellator); - } -} - Tessellator::Result Tessellator::Tessellate( FillType fill_type, const Path::Polyline& polyline, @@ -46,13 +64,7 @@ Tessellator::Result Tessellator::Tessellate( return Result::kInputError; } - using CTessellator = - std::unique_ptr; - - CTessellator tessellator( - ::tessNewTess(nullptr /* the default ::malloc based allocator */), - DestroyTessellator); - + auto tessellator = c_tessellator_.get(); if (!tessellator) { return Result::kTessellationError; } @@ -70,8 +82,8 @@ Tessellator::Result Tessellator::Tessellate( std::tie(start_point_index, end_point_index) = polyline.GetContourPointBounds(contour_i); - ::tessAddContour(tessellator.get(), // the C tessellator - kVertexSize, // + ::tessAddContour(tessellator, // the C tessellator + kVertexSize, // polyline.points.data() + start_point_index, // sizeof(Point), // end_point_index - start_point_index // @@ -81,7 +93,7 @@ Tessellator::Result Tessellator::Tessellate( //---------------------------------------------------------------------------- /// Let's tessellate. /// - auto result = ::tessTesselate(tessellator.get(), // tessellator + auto result = ::tessTesselate(tessellator, // tessellator ToTessWindingRule(fill_type), // winding TESS_POLYGONS, // element type kPolygonSize, // polygon size @@ -97,14 +109,14 @@ Tessellator::Result Tessellator::Tessellate( std::vector points; std::vector indices; - int vertexItemCount = tessGetVertexCount(tessellator.get()) * kVertexSize; - auto vertices = tessGetVertices(tessellator.get()); + int vertexItemCount = tessGetVertexCount(tessellator) * kVertexSize; + auto vertices = tessGetVertices(tessellator); for (int i = 0; i < vertexItemCount; i += 2) { points.emplace_back(vertices[i], vertices[i + 1]); } - int elementItemCount = tessGetElementCount(tessellator.get()) * kPolygonSize; - auto elements = tessGetElements(tessellator.get()); + int elementItemCount = tessGetElementCount(tessellator) * kPolygonSize; + auto elements = tessGetElements(tessellator); for (int i = 0; i < elementItemCount; i++) { indices.emplace_back(elements[i]); } @@ -113,8 +125,13 @@ Tessellator::Result Tessellator::Tessellate( auto vtx = points[index]; callback(vtx); } - return Result::kSuccess; } +void DestroyTessellator(TESStesselator* tessellator) { + if (tessellator != nullptr) { + ::tessDeleteTess(tessellator); + } +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/tessellator/tessellator.h b/engine/src/flutter/impeller/tessellator/tessellator.h index 595fb68acb8..7a2fded0e8e 100644 --- a/engine/src/flutter/impeller/tessellator/tessellator.h +++ b/engine/src/flutter/impeller/tessellator/tessellator.h @@ -11,8 +11,15 @@ #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" +struct TESStesselator; + namespace impeller { +void DestroyTessellator(TESStesselator* tessellator); + +using CTessellator = + std::unique_ptr; + enum class WindingOrder { kClockwise, kCounterClockwise, @@ -52,6 +59,8 @@ class Tessellator { const VertexCallback& callback) const; private: + CTessellator c_tessellator_; + FML_DISALLOW_COPY_AND_ASSIGN(Tessellator); }; diff --git a/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc b/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc index 6f0b6bab804..f9184b6805a 100644 --- a/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc +++ b/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc @@ -44,6 +44,22 @@ TEST(TessellatorTest, TessellatorReturnsCorrectResultStatus) { ASSERT_EQ(polyline.points.size(), 2u); ASSERT_EQ(result, Tessellator::Result::kSuccess); } + + // Many points. + { + Tessellator t; + PathBuilder builder; + for (int i = 0; i < 1000; i++) { + auto coord = i * 1.0f; + builder.AddLine({coord, coord}, {coord + 1, coord + 1}); + } + auto polyline = builder.TakePath().CreatePolyline(); + Tessellator::Result result = + t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); + + ASSERT_EQ(polyline.points.size(), 2000u); + ASSERT_EQ(result, Tessellator::Result::kSuccess); + } } } // namespace testing