[Impeller] Refactor all tessellation calls to use builder callback, rename. (flutter/engine#36706)

This commit is contained in:
Jonah Williams 2022-10-18 20:00:17 -05:00 committed by GitHub
parent 90d45770d7
commit 62ea6ec9f2
8 changed files with 66 additions and 179 deletions

View File

@ -119,15 +119,24 @@ bool TextureContents::Render(const ContentContext& renderer,
{
const auto tess_result = renderer.GetTessellator()->Tessellate(
path_.GetFillType(), path_.CreatePolyline(),
[this, &vertex_builder, &coverage_rect, &texture_size](Point vtx) {
VS::PerVertexData data;
data.position = vtx;
auto coverage_coords =
(vtx - coverage_rect->origin) / coverage_rect->size;
data.texture_coords =
(source_rect_.origin + source_rect_.size * coverage_coords) /
texture_size;
vertex_builder.AppendVertex(data);
[this, &vertex_builder, &coverage_rect, &texture_size](
const float* vertices, size_t vertices_size,
const uint16_t* indices, size_t indices_size) {
for (auto i = 0u; i < vertices_size; i++) {
VS::PerVertexData data;
Point vtx = {vertices[i], vertices[i + 1]};
data.position = vtx;
auto coverage_coords =
(vtx - coverage_rect->origin) / coverage_rect->size;
data.texture_coords =
(source_rect_.origin + source_rect_.size * coverage_coords) /
texture_size;
vertex_builder.AppendVertex(data);
}
for (auto i = 0u; i < indices_size; i++) {
vertex_builder.AppendIndex(indices[i]);
}
return true;
});
if (tess_result == Tessellator::Result::kInputError) {

View File

@ -184,7 +184,7 @@ GeometryResult PathGeometry::GetPositionBuffer(
std::shared_ptr<Tessellator> tessellator,
ISize render_target_size) {
VertexBuffer vertex_buffer;
auto tesselation_result = tessellator->TessellateBuilder(
auto tesselation_result = tessellator->Tessellate(
path_.GetFillType(), path_.CreatePolyline(),
[&vertex_buffer, &host_buffer](
const float* vertices, size_t vertices_count, const uint16_t* indices,

View File

@ -33,7 +33,10 @@ static void BM_Polyline(benchmark::State& state, Args&&... args) {
single_point_count = polyline.points.size();
point_count += single_point_count;
if (tessellate) {
tess.Tessellate(FillType::kNonZero, polyline, [](Point) {});
tess.Tessellate(
FillType::kNonZero, polyline,
[](const float* vertices, size_t vertices_size,
const uint16_t* indices, size_t indices_size) { return true; });
}
}
state.counters["SinglePointCount"] = single_point_count;

View File

@ -397,18 +397,25 @@ TEST_P(RendererTest, CanRenderInstanced) {
VertexBufferBuilder<VS::PerVertexData> builder;
ASSERT_EQ(
Tessellator::Result::kSuccess,
Tessellator{}.Tessellate(FillType::kPositive,
PathBuilder{}
.AddRect(Rect::MakeXYWH(10, 10, 100, 100))
.TakePath()
.CreatePolyline(),
[&builder](Point vtx) {
VS::PerVertexData data;
data.vtx = vtx;
builder.AppendVertex(data);
}));
ASSERT_EQ(Tessellator::Result::kSuccess,
Tessellator{}.Tessellate(
FillType::kPositive,
PathBuilder{}
.AddRect(Rect::MakeXYWH(10, 10, 100, 100))
.TakePath()
.CreatePolyline(),
[&builder](const float* vertices, size_t vertices_size,
const uint16_t* indices, size_t indices_size) {
for (auto i = 0u; i < vertices_size; i += 2) {
VS::PerVertexData data;
data.vtx = {vertices[i], vertices[i + 1]};
builder.AppendVertex(data);
}
for (auto i = 0u; i < indices_size; i++) {
builder.AppendIndex(indices[i]);
}
return true;
}));
ASSERT_NE(GetContext(), nullptr);
auto pipeline =

View File

@ -46,11 +46,22 @@ struct Vertices* Tessellate(PathBuilder* builder,
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) {
points.push_back(vertex.x);
points.push_back(vertex.y);
}) != Tessellator::Result::kSuccess) {
if (Tessellator{}.Tessellate(
path.GetFillType(), polyline,
[&points](const float* vertices, size_t vertices_size,
const uint16_t* indices, size_t indices_size) {
// Results are expected to be re-duplicated.
std::vector<Point> raw_points;
for (auto i = 0u; i < vertices_size; i += 2) {
raw_points.emplace_back(Point{vertices[i], vertices[i + 1]});
}
for (auto i = 0u; i < indices_size; i++) {
auto point = raw_points[indices[i]];
points.push_back(point.x);
points.push_back(point.y);
}
return true;
}) != Tessellator::Result::kSuccess) {
return nullptr;
}

View File

@ -53,82 +53,6 @@ static int ToTessWindingRule(FillType fill_type) {
}
Tessellator::Result Tessellator::Tessellate(
FillType fill_type,
const Path::Polyline& polyline,
const VertexCallback& callback) const {
if (!callback) {
return Result::kInputError;
}
if (polyline.points.empty()) {
return Result::kInputError;
}
auto tessellator = c_tessellator_.get();
if (!tessellator) {
return Result::kTessellationError;
}
constexpr int kVertexSize = 2;
constexpr int kPolygonSize = 3;
//----------------------------------------------------------------------------
/// Feed contour information to the tessellator.
///
static_assert(sizeof(Point) == 2 * sizeof(float));
for (size_t contour_i = 0; contour_i < polyline.contours.size();
contour_i++) {
size_t start_point_index, end_point_index;
std::tie(start_point_index, end_point_index) =
polyline.GetContourPointBounds(contour_i);
::tessAddContour(tessellator, // the C tessellator
kVertexSize, //
polyline.points.data() + start_point_index, //
sizeof(Point), //
end_point_index - start_point_index //
);
}
//----------------------------------------------------------------------------
/// Let's tessellate.
///
auto result = ::tessTesselate(tessellator, // tessellator
ToTessWindingRule(fill_type), // winding
TESS_POLYGONS, // element type
kPolygonSize, // polygon size
kVertexSize, // vertex size
nullptr // normal (null is automatic)
);
if (result != 1) {
return Result::kTessellationError;
}
// TODO(csg): This copy can be elided entirely for the current use case.
std::vector<Point> points;
std::vector<uint32_t> indices;
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) * kPolygonSize;
auto elements = tessGetElements(tessellator);
for (int i = 0; i < elementItemCount; i++) {
indices.emplace_back(elements[i]);
}
for (auto index : indices) {
auto vtx = points[index];
callback(vtx);
}
return Result::kSuccess;
}
Tessellator::Result Tessellator::TessellateBuilder(
FillType fill_type,
const Path::Polyline& polyline,
const BuilderCallback& callback) const {

View File

@ -43,26 +43,11 @@ class Tessellator {
~Tessellator();
using VertexCallback = std::function<void(Point)>;
using BuilderCallback = std::function<bool(const float* vertices,
size_t vertices_size,
const uint16_t* indices,
size_t indices_size)>;
//----------------------------------------------------------------------------
/// @brief Generates filled triangles from the polyline. A callback is
/// invoked for each vertex of the triangle.
///
/// @param[in] fill_type The fill rule to use when filling.
/// @param[in] polyline The polyline
/// @param[in] callback The callback
///
/// @return The result status of the tessellation.
///
Tessellator::Result Tessellate(FillType fill_type,
const Path::Polyline& polyline,
const VertexCallback& callback) const;
//----------------------------------------------------------------------------
/// @brief Generates filled triangles from the polyline. A callback is
/// invoked once for the entire tessellation.
@ -73,9 +58,9 @@ class Tessellator {
///
/// @return The result status of the tessellation.
///
Tessellator::Result TessellateBuilder(FillType fill_type,
const Path::Polyline& polyline,
const BuilderCallback& callback) const;
Tessellator::Result Tessellate(FillType fill_type,
const Path::Polyline& polyline,
const BuilderCallback& callback) const;
private:
CTessellator c_tessellator_;

View File

@ -10,64 +10,12 @@
namespace impeller {
namespace testing {
TEST(TessellatorTest, TessellatorReturnsCorrectResultStatus) {
// Zero points.
{
Tessellator t;
auto polyline = PathBuilder{}.TakePath().CreatePolyline();
Tessellator::Result result =
t.Tessellate(FillType::kPositive, polyline, [](Point point) {});
ASSERT_EQ(polyline.points.size(), 0u);
ASSERT_EQ(result, Tessellator::Result::kInputError);
}
// One point.
{
Tessellator t;
auto polyline = PathBuilder{}.LineTo({0, 0}).TakePath().CreatePolyline();
Tessellator::Result result =
t.Tessellate(FillType::kPositive, polyline, [](Point point) {});
ASSERT_EQ(polyline.points.size(), 1u);
ASSERT_EQ(result, Tessellator::Result::kSuccess);
}
// Two points.
{
Tessellator t;
auto polyline =
PathBuilder{}.AddLine({0, 0}, {0, 1}).TakePath().CreatePolyline();
Tessellator::Result result =
t.Tessellate(FillType::kPositive, polyline, [](Point point) {});
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);
}
}
TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
// Zero points.
{
Tessellator t;
auto polyline = PathBuilder{}.TakePath().CreatePolyline();
Tessellator::Result result = t.TessellateBuilder(
Tessellator::Result result = t.Tessellate(
FillType::kPositive, polyline,
[](const float* vertices, size_t vertices_size, const uint16_t* indices,
size_t indices_size) { return true; });
@ -80,7 +28,7 @@ TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
{
Tessellator t;
auto polyline = PathBuilder{}.LineTo({0, 0}).TakePath().CreatePolyline();
Tessellator::Result result = t.TessellateBuilder(
Tessellator::Result result = t.Tessellate(
FillType::kPositive, polyline,
[](const float* vertices, size_t vertices_size, const uint16_t* indices,
size_t indices_size) { return true; });
@ -93,7 +41,7 @@ TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
Tessellator t;
auto polyline =
PathBuilder{}.AddLine({0, 0}, {0, 1}).TakePath().CreatePolyline();
Tessellator::Result result = t.TessellateBuilder(
Tessellator::Result result = t.Tessellate(
FillType::kPositive, polyline,
[](const float* vertices, size_t vertices_size, const uint16_t* indices,
size_t indices_size) { return true; });
@ -111,7 +59,7 @@ TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
builder.AddLine({coord, coord}, {coord + 1, coord + 1});
}
auto polyline = builder.TakePath().CreatePolyline();
Tessellator::Result result = t.TessellateBuilder(
Tessellator::Result result = t.Tessellate(
FillType::kPositive, polyline,
[](const float* vertices, size_t vertices_size, const uint16_t* indices,
size_t indices_size) { return true; });
@ -125,7 +73,7 @@ TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
Tessellator t;
auto polyline =
PathBuilder{}.AddLine({0, 0}, {0, 1}).TakePath().CreatePolyline();
Tessellator::Result result = t.TessellateBuilder(
Tessellator::Result result = t.Tessellate(
FillType::kPositive, polyline,
[](const float* vertices, size_t vertices_size, const uint16_t* indices,
size_t indices_size) { return false; });