mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Create the tessellator in the ContentsContext and reuse, reduce initial bucket size. (flutter/engine#36534)
This commit is contained in:
parent
3ec5ace549
commit
b1dcbda64e
@ -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();
|
||||
|
||||
@ -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_;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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_,
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user