[Impeller] Create the tessellator in the ContentsContext and reuse, reduce initial bucket size. (flutter/engine#36534)

This commit is contained in:
Jonah Williams 2022-09-30 13:53:17 -07:00 committed by GitHub
parent 3ec5ace549
commit b1dcbda64e
14 changed files with 87 additions and 28 deletions

View File

@ -120,7 +120,7 @@ bool ClipContents::Render(const ContentContext& renderer,
cmd.pipeline = renderer.GetClipPipeline(options);
cmd.BindVertices(CreateSolidFillVertices<VS::PerVertexData>(
path_, pass.GetTransientsBuffer()));
renderer.GetTessellator(), path_, pass.GetTransientsBuffer()));
info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation();

View File

@ -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<PipelineT> CreateDefaultPipeline(
}
ContentContext::ContentContext(std::shared_ptr<Context> context)
: context_(std::move(context)) {
: context_(std::move(context)),
tessellator_(std::make_shared<Tessellator>()) {
if (!context_ || !context_->IsValid()) {
return;
}
@ -285,6 +287,10 @@ std::shared_ptr<Texture> ContentContext::MakeSubpass(
return subpass_texture;
}
std::shared_ptr<Tessellator> ContentContext::GetTessellator() const {
return tessellator_;
}
std::shared_ptr<Context> ContentContext::GetContext() const {
return context_;
}

View File

@ -183,6 +183,8 @@ struct ContentContextOptions {
void ApplyToPipelineDescriptor(PipelineDescriptor& desc) const;
};
class Tessellator;
class ContentContext {
public:
explicit ContentContext(std::shared_ptr<Context> context);
@ -191,6 +193,8 @@ class ContentContext {
bool IsValid() const;
std::shared_ptr<Tessellator> GetTessellator() const;
std::shared_ptr<Pipeline<PipelineDescriptor>> 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> tessellator_;
FML_DISALLOW_COPY_AND_ASSIGN(ContentContext);
};

View File

@ -78,6 +78,7 @@ bool LinearGradientContents::Render(const ContentContext& renderer,
OptionsFromPassAndEntity(pass, entity));
cmd.stencil_reference = entity.GetStencilDepth();
cmd.BindVertices(CreateSolidFillVertices<VS::PerVertexData>(
renderer.GetTessellator(),
GetCover()
? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath()
: GetPath(),

View File

@ -77,6 +77,7 @@ bool RadialGradientContents::Render(const ContentContext& renderer,
OptionsFromPassAndEntity(pass, entity));
cmd.stencil_reference = entity.GetStencilDepth();
cmd.BindVertices(CreateSolidFillVertices<VS::PerVertexData>(
renderer.GetTessellator(),
GetCover()
? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath()
: GetPath(),

View File

@ -63,6 +63,7 @@ bool SolidColorContents::Render(const ContentContext& renderer,
cmd.stencil_reference = entity.GetStencilDepth();
cmd.BindVertices(CreateSolidFillVertices<VS::PerVertexData>(
renderer.GetTessellator(),
cover_
? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath()
: path_,

View File

@ -10,10 +10,12 @@
namespace impeller {
template <typename PerVertexData>
VertexBuffer CreateSolidFillVertices(const Path& path, HostBuffer& buffer) {
VertexBuffer CreateSolidFillVertices(std::shared_ptr<Tessellator> tessellator,
const Path& path,
HostBuffer& buffer) {
VertexBufferBuilder<PerVertexData> 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) {

View File

@ -84,6 +84,7 @@ bool SweepGradientContents::Render(const ContentContext& renderer,
OptionsFromPassAndEntity(pass, entity));
cmd.stencil_reference = entity.GetStencilDepth();
cmd.BindVertices(CreateSolidFillVertices<VS::PerVertexData>(
renderer.GetTessellator(),
GetCover()
? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath()
: GetPath(),

View File

@ -116,7 +116,7 @@ bool TextureContents::Render(const ContentContext& renderer,
VertexBufferBuilder<VS::PerVertexData> 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;

View File

@ -68,6 +68,7 @@ bool TiledTextureContents::Render(const ContentContext& renderer,
renderer.GetTiledTexturePipeline(OptionsFromPassAndEntity(pass, entity));
cmd.stencil_reference = entity.GetStencilDepth();
cmd.BindVertices(CreateSolidFillVertices<VS::PerVertexData>(
renderer.GetTessellator(),
GetCover()
? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath()
: GetPath(),

View File

@ -45,7 +45,6 @@ struct Vertices* Tessellate(PathBuilder* builder,
auto path = builder->CopyPath(static_cast<FillType>(fill_type));
auto smoothing = SmoothingApproximation(scale, angle_tolerance, cusp_limit);
auto polyline = path.CreatePolyline(smoothing);
std::vector<float> points;
if (Tessellator{}.Tessellate(path.GetFillType(), polyline,
[&points](Point vertex) {

View File

@ -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<TESStesselator, decltype(&DestroyTessellator)>;
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<Point> points;
std::vector<uint32_t> 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

View File

@ -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<TESStesselator, decltype(&DestroyTessellator)>;
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);
};

View File

@ -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