Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] revert non-zero tessellation optimization. #48234

Merged
merged 1 commit into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 66 additions & 127 deletions impeller/tessellator/tessellator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,142 +89,81 @@ Tessellator::Result Tessellator::Tessellate(const Path& path,
constexpr int kVertexSize = 2;
constexpr int kPolygonSize = 3;

// If we have a larger polyline and the fill type is non-zero, we can split
// the tessellation up per contour. Since in general the complexity is at
// least nlog(n), this speeds up the processes substantially.
if (polyline.contours.size() > kMultiContourThreshold &&
fill_type == FillType::kNonZero) {
std::vector<Point> points;
std::vector<float> data;
//----------------------------------------------------------------------------
/// 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 //
);
}

//----------------------------------------------------------------------------
/// Feed contour information to the tessellator.
///
size_t total = 0u;
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;
}

int vertex_item_count = tessGetVertexCount(tessellator) * kVertexSize;
auto vertices = tessGetVertices(tessellator);
for (int i = 0; i < vertex_item_count; i += 2) {
points.emplace_back(vertices[i], vertices[i + 1]);
}

int element_item_count = tessGetElementCount(tessellator) * kPolygonSize;
auto elements = tessGetElements(tessellator);
total += element_item_count;
for (int i = 0; i < element_item_count; i++) {
data.emplace_back(points[elements[i]].x);
data.emplace_back(points[elements[i]].y);
}
points.clear();
//----------------------------------------------------------------------------
/// 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;
}

int element_item_count = tessGetElementCount(tessellator) * kPolygonSize;

// We default to using a 16bit index buffer, but in cases where we generate
// more tessellated data than this can contain we need to fall back to
// dropping the index buffer entirely. Instead code could instead switch to
// a uint32 index buffer, but this is done for simplicity with the other
// fast path above.
if (element_item_count < USHRT_MAX) {
int vertex_item_count = tessGetVertexCount(tessellator);
auto vertices = tessGetVertices(tessellator);
auto elements = tessGetElements(tessellator);

// libtess uses an int index internally due to usage of -1 as a sentinel
// value.
std::vector<uint16_t> indices(element_item_count);
for (int i = 0; i < element_item_count; i++) {
indices[i] = static_cast<uint16_t>(elements[i]);
}
if (!callback(data.data(), total, nullptr, 0u)) {
if (!callback(vertices, vertex_item_count, indices.data(),
element_item_count)) {
return Result::kInputError;
}
} else {
//----------------------------------------------------------------------------
/// 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)
);
std::vector<Point> points;
std::vector<float> data;

if (result != 1) {
return Result::kTessellationError;
int vertex_item_count = tessGetVertexCount(tessellator) * kVertexSize;
auto vertices = tessGetVertices(tessellator);
points.reserve(vertex_item_count);
for (int i = 0; i < vertex_item_count; i += 2) {
points.emplace_back(vertices[i], vertices[i + 1]);
}

int element_item_count = tessGetElementCount(tessellator) * kPolygonSize;

// We default to using a 16bit index buffer, but in cases where we generate
// more tessellated data than this can contain we need to fall back to
// dropping the index buffer entirely. Instead code could instead switch to
// a uint32 index buffer, but this is done for simplicity with the other
// fast path above.
if (element_item_count < USHRT_MAX) {
int vertex_item_count = tessGetVertexCount(tessellator);
auto vertices = tessGetVertices(tessellator);
auto elements = tessGetElements(tessellator);

// libtess uses an int index internally due to usage of -1 as a sentinel
// value.
std::vector<uint16_t> indices(element_item_count);
for (int i = 0; i < element_item_count; i++) {
indices[i] = static_cast<uint16_t>(elements[i]);
}
if (!callback(vertices, vertex_item_count, indices.data(),
element_item_count)) {
return Result::kInputError;
}
} else {
std::vector<Point> points;
std::vector<float> data;

int vertex_item_count = tessGetVertexCount(tessellator) * kVertexSize;
auto vertices = tessGetVertices(tessellator);
points.reserve(vertex_item_count);
for (int i = 0; i < vertex_item_count; i += 2) {
points.emplace_back(vertices[i], vertices[i + 1]);
}

int element_item_count = tessGetElementCount(tessellator) * kPolygonSize;
auto elements = tessGetElements(tessellator);
data.reserve(element_item_count);
for (int i = 0; i < element_item_count; i++) {
data.emplace_back(points[elements[i]].x);
data.emplace_back(points[elements[i]].y);
}
if (!callback(data.data(), element_item_count, nullptr, 0u)) {
return Result::kInputError;
}
auto elements = tessGetElements(tessellator);
data.reserve(element_item_count);
for (int i = 0; i < element_item_count; i++) {
data.emplace_back(points[elements[i]].x);
data.emplace_back(points[elements[i]].y);
}
if (!callback(data.data(), element_item_count, nullptr, 0u)) {
return Result::kInputError;
}
}

Expand Down
4 changes: 0 additions & 4 deletions impeller/tessellator/tessellator.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@ class Tessellator {

~Tessellator();

/// @brief An arbitrary value to determine when a multi-contour non-zero fill
/// path should be split into multiple tessellations.
static constexpr size_t kMultiContourThreshold = 30u;

/// @brief A callback that returns the results of the tessellation.
///
/// The index buffer may not be populated, in which case [indices] will
Expand Down
21 changes: 0 additions & 21 deletions impeller/tessellator/tessellator_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,6 @@ TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
ASSERT_EQ(result, Tessellator::Result::kInputError);
}

// More than 30 contours, non-zero fill mode.
{
Tessellator t;
PathBuilder builder = {};
for (auto i = 0u; i < Tessellator::kMultiContourThreshold + 1; i++) {
builder.AddCircle(Point(i, i), 4);
}
auto path = builder.TakePath(FillType::kNonZero);
bool no_indices = false;
Tessellator::Result result = t.Tessellate(
path, 1.0f,
[&no_indices](const float* vertices, size_t vertices_count,
const uint16_t* indices, size_t indices_count) {
no_indices = indices == nullptr;
return true;
});

ASSERT_TRUE(no_indices);
ASSERT_EQ(result, Tessellator::Result::kSuccess);
}

// More than uint16 points, odd fill mode.
{
Tessellator t;
Expand Down