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

[Impeller] geometry changes to support line/point style. #56340

Merged
merged 6 commits into from
Nov 11, 2024
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
54 changes: 54 additions & 0 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "gtest/gtest.h"
#include "impeller/core/device_buffer.h"
#include "impeller/core/formats.h"
#include "impeller/core/host_buffer.h"
#include "impeller/core/texture_descriptor.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/contents/conical_gradient_contents.h"
Expand Down Expand Up @@ -2424,6 +2425,59 @@ TEST_P(EntityTest, GiantStrokePathAllocation) {
EXPECT_NEAR(point.y, expected[4].y, 0.1);
}

TEST_P(EntityTest, GiantLineStripPathAllocation) {
PathBuilder builder{};
for (int i = 0; i < 10000; i++) {
builder.LineTo(Point(i, i));
}
Path path = builder.TakePath();

ContentContext content_context(GetContext(), /*typographer_context=*/nullptr);
Entity entity;

auto host_buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(),
GetContext()->GetIdleWaiter());
auto tessellator = Tessellator();

auto vertex_buffer = tessellator.GenerateLineStrip(path, *host_buffer, 1.0);

// Validate the buffer data overflowed the small buffer
EXPECT_GT(vertex_buffer.vertex_count, kPointArenaSize);

// Validate that there are no uninitialized points near the gap.
Point* written_data = reinterpret_cast<Point*>(
(vertex_buffer.vertex_buffer.GetBuffer()->OnGetContents() +
vertex_buffer.vertex_buffer.GetRange().offset));

std::vector<Point> expected = {
Point(4093, 4093), //
Point(4094, 4094), //
Point(4095, 4095), //
Point(4096, 4096), //
Point(4097, 4097) //
};

Point point = written_data[kPointArenaSize - 2];
EXPECT_NEAR(point.x, expected[0].x, 0.1);
EXPECT_NEAR(point.y, expected[0].y, 0.1);

point = written_data[kPointArenaSize - 1];
EXPECT_NEAR(point.x, expected[1].x, 0.1);
EXPECT_NEAR(point.y, expected[1].y, 0.1);

point = written_data[kPointArenaSize];
EXPECT_NEAR(point.x, expected[2].x, 0.1);
EXPECT_NEAR(point.y, expected[2].y, 0.1);

point = written_data[kPointArenaSize + 1];
EXPECT_NEAR(point.x, expected[3].x, 0.1);
EXPECT_NEAR(point.y, expected[3].y, 0.1);

point = written_data[kPointArenaSize + 2];
EXPECT_NEAR(point.x, expected[4].x, 0.1);
EXPECT_NEAR(point.y, expected[4].y, 0.1);
}

} // namespace testing
} // namespace impeller

Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/geometry/stroke_path_geometry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class PositionWriter {

bool HasOversizedBuffer() const { return !oversized_.empty(); }

const std::vector<Point>& GetOveriszedBuffer() const { return oversized_; }
const std::vector<Point>& GetOversizedBuffer() const { return oversized_; }

private:
std::vector<Point>& points_;
Expand Down Expand Up @@ -618,7 +618,7 @@ GeometryResult StrokePathGeometry::GetPositionBuffer(
.mode = GeometryResult::Mode::kPreventOverdraw};
}
const std::vector<Point>& oversized_data =
position_writer.GetOveriszedBuffer();
position_writer.GetOversizedBuffer();
BufferView buffer_view = host_buffer.Emplace(
/*buffer=*/nullptr, //
(arena_length + oversized_length) * sizeof(Point), //
Expand Down
4 changes: 4 additions & 0 deletions impeller/geometry/path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ bool Path::IsEmpty() const {
data_->components[0] == ComponentType::kContour);
}

bool Path::IsSingleContour() const {
return data_->single_countour;
}

/// Determine required storage for points and indices.
std::pair<size_t, size_t> Path::CountStorage(Scalar scale) const {
size_t points = 0;
Expand Down
4 changes: 4 additions & 0 deletions impeller/geometry/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ class Path {

bool IsEmpty() const;

/// @brief Whether the line contains a single contour.
bool IsSingleContour() const;

bool GetLinearComponentAtIndex(size_t index,
LinearPathComponent& linear) const;

Expand Down Expand Up @@ -219,6 +222,7 @@ class Path {

FillType fill = FillType::kNonZero;
Convexity convexity = Convexity::kUnknown;
bool single_countour = true;
std::optional<Rect> bounds;
std::vector<Point> points;
std::vector<ComponentType> components;
Expand Down
11 changes: 11 additions & 0 deletions impeller/geometry/path_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,22 @@ PathBuilder::~PathBuilder() = default;

Path PathBuilder::CopyPath(FillType fill) {
prototype_.fill = fill;
prototype_.single_countour =
current_contour_location_ == 0u ||
(contour_count_ == 2 &&
prototype_.components.back() == Path::ComponentType::kContour);
return Path(prototype_);
}

Path PathBuilder::TakePath(FillType fill) {
prototype_.fill = fill;
UpdateBounds();
prototype_.single_countour =
current_contour_location_ == 0u ||
(contour_count_ == 2 &&
prototype_.components.back() == Path::ComponentType::kContour);
current_contour_location_ = 0u;
contour_count_ = 1;
return Path(std::move(prototype_));
}

Expand Down Expand Up @@ -276,6 +285,7 @@ void PathBuilder::AddContourComponent(const Point& destination,
points.push_back(destination);
points.push_back(closed);
components.push_back(Path::ComponentType::kContour);
contour_count_ += 1;
}
prototype_.bounds.reset();
}
Expand Down Expand Up @@ -450,6 +460,7 @@ PathBuilder& PathBuilder::AddPath(const Path& path) {
for (auto component : path.data_->components) {
if (component == Path::ComponentType::kContour) {
current_contour_location_ = source_offset;
contour_count_ += 1;
}
source_offset += Path::VerbToOffset(component);
}
Expand Down
1 change: 1 addition & 0 deletions impeller/geometry/path_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class PathBuilder {
Point subpath_start_;
Point current_;
size_t current_contour_location_ = 0u;
size_t contour_count_ = 0u;
Path::Data prototype_;

PathBuilder& AddRoundedRectTopLeft(Rect rect, RoundingRadii radii);
Expand Down
24 changes: 24 additions & 0 deletions impeller/geometry/path_component.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "path_component.h"

#include <cmath>
#include <utility>

#include "impeller/geometry/scalar.h"
#include "impeller/geometry/wangs_formula.h"
Expand Down Expand Up @@ -77,6 +78,29 @@ void StripVertexWriter::Write(Point point) {
point_buffer_[count_++] = point;
}

/////////// LineStripVertexWriter ////////

LineStripVertexWriter::LineStripVertexWriter(std::vector<Point>& points)
: points_(points) {}

void LineStripVertexWriter::EndContour() {}

void LineStripVertexWriter::Write(Point point) {
if (offset_ >= points_.size()) {
overflow_.push_back(point);
} else {
points_[offset_++] = point;
}
}

const std::vector<Point>& LineStripVertexWriter::GetOversizedBuffer() const {
return overflow_;
}

std::pair<size_t, size_t> LineStripVertexWriter::GetVertexCount() const {
return std::make_pair(offset_, overflow_.size());
}

/////////// GLESVertexWriter ///////////

GLESVertexWriter::GLESVertexWriter(std::vector<Point>& points,
Expand Down
21 changes: 21 additions & 0 deletions impeller/geometry/path_component.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ class StripVertexWriter : public VertexWriter {
uint16_t* index_buffer_ = nullptr;
};

/// @brief A vertex writer that generates a line strip topology.
class LineStripVertexWriter : public VertexWriter {
public:
explicit LineStripVertexWriter(std::vector<Point>& points);

~LineStripVertexWriter() = default;

void EndContour() override;

void Write(Point point) override;

std::pair<size_t, size_t> GetVertexCount() const;

const std::vector<Point>& GetOversizedBuffer() const;

private:
size_t offset_ = 0u;
std::vector<Point>& points_;
std::vector<Point> overflow_;
};

/// @brief A vertex writer that has no hardware requirements.
class GLESVertexWriter : public VertexWriter {
public:
Expand Down
136 changes: 136 additions & 0 deletions impeller/geometry/path_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,142 @@ TEST(PathTest, PathCreatePolyLineDoesNotDuplicatePoints) {
ASSERT_EQ(polyline.GetPoint(4).x, 50);
}

TEST(PathTest, PathSingleContour) {
// Closed shapes.
{
Path path = PathBuilder{}.AddCircle({100, 100}, 50).TakePath();
EXPECT_TRUE(path.IsSingleContour());
}

{
Path path =
PathBuilder{}.AddOval(Rect::MakeXYWH(100, 100, 100, 100)).TakePath();

EXPECT_TRUE(path.IsSingleContour());
}

{
Path path =
PathBuilder{}.AddRect(Rect::MakeXYWH(100, 100, 100, 100)).TakePath();

EXPECT_TRUE(path.IsSingleContour());
}

{
Path path = PathBuilder{}
.AddRoundRect(RoundRect::MakeRectRadius(
Rect::MakeXYWH(100, 100, 100, 100), 10))
.TakePath();

EXPECT_TRUE(path.IsSingleContour());
}

// Open shapes.
{
Point p(100, 100);
Path path = PathBuilder{}.AddLine(p, {200, 100}).TakePath();

EXPECT_TRUE(path.IsSingleContour());
}

{
Path path =
PathBuilder{}
.AddCubicCurve({100, 100}, {100, 50}, {100, 150}, {200, 100})
.TakePath();

EXPECT_TRUE(path.IsSingleContour());
}

{
Path path = PathBuilder{}
.AddQuadraticCurve({100, 100}, {100, 50}, {200, 100})
.TakePath();

EXPECT_TRUE(path.IsSingleContour());
}
}

TEST(PathTest, PathSingleContourDoubleShapes) {
// Closed shapes.
{
Path path = PathBuilder{}
.AddCircle({100, 100}, 50)
.AddCircle({100, 100}, 50)
.TakePath();
EXPECT_FALSE(path.IsSingleContour());
}

{
Path path = PathBuilder{}
.AddOval(Rect::MakeXYWH(100, 100, 100, 100))
.AddOval(Rect::MakeXYWH(100, 100, 100, 100))
.TakePath();

EXPECT_FALSE(path.IsSingleContour());
}

{
Path path = PathBuilder{}
.AddRect(Rect::MakeXYWH(100, 100, 100, 100))
.AddRect(Rect::MakeXYWH(100, 100, 100, 100))
.TakePath();

EXPECT_FALSE(path.IsSingleContour());
}

{
Path path = PathBuilder{}
.AddRoundRect(RoundRect::MakeRectRadius(
Rect::MakeXYWH(100, 100, 100, 100), 10))
.AddRoundRect(RoundRect::MakeRectRadius(
Rect::MakeXYWH(100, 100, 100, 100), 10))
.TakePath();

EXPECT_FALSE(path.IsSingleContour());
}

{
Path path = PathBuilder{}
.AddRoundRect(RoundRect::MakeRectXY(
Rect::MakeXYWH(100, 100, 100, 100), Size(10, 20)))
.AddRoundRect(RoundRect::MakeRectXY(
Rect::MakeXYWH(100, 100, 100, 100), Size(10, 20)))
.TakePath();

EXPECT_FALSE(path.IsSingleContour());
}

// Open shapes.
{
Point p(100, 100);
Path path =
PathBuilder{}.AddLine(p, {200, 100}).AddLine(p, {200, 100}).TakePath();

EXPECT_FALSE(path.IsSingleContour());
}

{
Path path =
PathBuilder{}
.AddCubicCurve({100, 100}, {100, 50}, {100, 150}, {200, 100})
.AddCubicCurve({100, 100}, {100, 50}, {100, 150}, {200, 100})
.TakePath();

EXPECT_FALSE(path.IsSingleContour());
}

{
Path path = PathBuilder{}
.AddQuadraticCurve({100, 100}, {100, 50}, {200, 100})
.Close()
.AddQuadraticCurve({100, 100}, {100, 50}, {200, 100})
.TakePath();

EXPECT_FALSE(path.IsSingleContour());
}
}

TEST(PathTest, PathBuilderSetsCorrectContourPropertiesForAddCommands) {
// Closed shapes.
{
Expand Down
Loading