mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Refactor all tessellation calls to use builder callback, rename. (flutter/engine#36706)
This commit is contained in:
parent
90d45770d7
commit
62ea6ec9f2
@ -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) {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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; });
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user