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

Commit 2561ea1

Browse files
author
Jonah Williams
authored
[Impeller] add triangle fan support and remove drawVertices copying. (#55236)
Vulkan and GLES backends support triangle fans, so only "un-fan" these geometries when necessary. Now that dispatch gives the vertices geometry as a shared_ptr, we can hold onto that directly without performing another copy.
1 parent a99c747 commit 2561ea1

20 files changed

+321
-292
lines changed

impeller/core/formats.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,13 +350,13 @@ enum class IndexType {
350350

351351
/// Decides how backend draws pixels based on input vertices.
352352
enum class PrimitiveType : uint8_t {
353-
/// Draws a triage for each separate set of three vertices.
353+
/// Draws a triangle for each separate set of three vertices.
354354
///
355355
/// Vertices [A, B, C, D, E, F] will produce triages
356356
/// [ABC, DEF].
357357
kTriangle,
358358

359-
/// Draws a triage for every adjacent three vertices.
359+
/// Draws a triangle for every adjacent three vertices.
360360
///
361361
/// Vertices [A, B, C, D, E, F] will produce triages
362362
/// [ABC, BCD, CDE, DEF].
@@ -376,8 +376,14 @@ enum class PrimitiveType : uint8_t {
376376

377377
/// Draws a point at each input vertex.
378378
kPoint,
379-
// Triangle fans are implementation dependent and need extra extensions
380-
// checks. Hence, they are not supported here.
379+
380+
/// Draws a triangle for every two vertices, after the first.
381+
///
382+
/// The first vertex acts as the hub, all following vertices connect with
383+
/// this hub to "fan" out from the first vertex.
384+
///
385+
/// Triangle fans are not supported in Metal and need a capability check.
386+
kTriangleFan,
381387
};
382388

383389
enum class PolygonMode {

impeller/display_list/aiks_dl_blur_unittests.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,7 @@ TEST_P(AiksTest, GaussianBlurWithoutDecalSupport) {
10771077
FLT_FORWARD(mock_capabilities, old_capabilities,
10781078
SupportsTextureToTextureBlits);
10791079
FLT_FORWARD(mock_capabilities, old_capabilities, GetDefaultGlyphAtlasFormat);
1080+
FLT_FORWARD(mock_capabilities, old_capabilities, SupportsTriangleFan);
10801081
ASSERT_TRUE(SetCapabilities(mock_capabilities).ok());
10811082

10821083
auto texture = DlImageImpeller::Make(CreateTextureForFixture("boston.jpg"));

impeller/display_list/dl_dispatcher.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,14 +1076,19 @@ void DlDispatcherBase::drawPoints(PointMode mode,
10761076
}
10771077
}
10781078

1079-
// |flutter::DlOpReceiver|
10801079
void DlDispatcherBase::drawVertices(
1080+
const std::shared_ptr<flutter::DlVertices>& vertices,
1081+
flutter::DlBlendMode dl_mode) {}
1082+
1083+
// |flutter::DlOpReceiver|
1084+
void ExperimentalDlDispatcher::drawVertices(
10811085
const std::shared_ptr<flutter::DlVertices>& vertices,
10821086
flutter::DlBlendMode dl_mode) {
10831087
AUTO_DEPTH_WATCHER(1u);
10841088

1085-
GetCanvas().DrawVertices(MakeVertices(vertices), ToBlendMode(dl_mode),
1086-
paint_);
1089+
GetCanvas().DrawVertices(
1090+
std::make_shared<DlVerticesGeometry>(vertices, renderer_),
1091+
ToBlendMode(dl_mode), paint_);
10871092
}
10881093

10891094
// |flutter::DlOpReceiver|
@@ -1349,7 +1354,8 @@ ExperimentalDlDispatcher::ExperimentalDlDispatcher(
13491354
bool has_root_backdrop_filter,
13501355
flutter::DlBlendMode max_root_blend_mode,
13511356
IRect cull_rect)
1352-
: canvas_(renderer,
1357+
: renderer_(renderer),
1358+
canvas_(renderer,
13531359
render_target,
13541360
has_root_backdrop_filter ||
13551361
RequiresReadbackForBlends(renderer, max_root_blend_mode),

impeller/display_list/dl_dispatcher.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "impeller/aiks/experimental_canvas.h"
1515
#include "impeller/aiks/paint.h"
1616
#include "impeller/entity/contents/content_context.h"
17-
#include "impeller/geometry/color.h"
1817

1918
namespace impeller {
2019

@@ -236,7 +235,7 @@ class DlDispatcherBase : public flutter::DlOpReceiver {
236235

237236
virtual Canvas& GetCanvas() = 0;
238237

239-
private:
238+
protected:
240239
Paint paint_;
241240
Matrix initial_matrix_;
242241

@@ -314,7 +313,12 @@ class ExperimentalDlDispatcher : public DlDispatcherBase {
314313

315314
void FinishRecording() { canvas_.EndReplay(); }
316315

316+
// |flutter::DlOpReceiver|
317+
void drawVertices(const std::shared_ptr<flutter::DlVertices>& vertices,
318+
flutter::DlBlendMode dl_mode) override;
319+
317320
private:
321+
const ContentContext& renderer_;
318322
ExperimentalCanvas canvas_;
319323

320324
Canvas& GetCanvas() override;

impeller/display_list/dl_vertices_geometry.cc

Lines changed: 197 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,61 +5,220 @@
55
#include "impeller/display_list/dl_vertices_geometry.h"
66

77
#include "display_list/dl_vertices.h"
8+
#include "impeller/core/formats.h"
89
#include "impeller/display_list/skia_conversions.h"
9-
#include "impeller/entity/geometry/vertices_geometry.h"
1010
#include "impeller/geometry/point.h"
1111
#include "third_party/skia/include/core/SkPoint.h"
12-
#include "third_party/skia/include/core/SkRect.h"
1312

1413
namespace impeller {
1514

16-
static Rect ToRect(const SkRect& rect) {
17-
return Rect::MakeLTRB(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
15+
namespace {
16+
17+
// Fan mode isn't natively supported on Metal backends. Unroll into triangle
18+
// mode by manipulating the index array.
19+
//
20+
// In Triangle fan, the first vertex is shared across all triangles, and then
21+
// each sliding window of two vertices plus that first vertex defines a
22+
// triangle.
23+
static std::vector<uint16_t> fromFanIndices(size_t vertex_count,
24+
size_t index_count,
25+
const uint16_t* indices) {
26+
std::vector<uint16_t> unrolled_indices;
27+
28+
// Un-fan index buffer if provided.
29+
if (index_count > 0u) {
30+
if (index_count < 3u) {
31+
return {};
32+
}
33+
34+
auto center_point = indices[0];
35+
for (auto i = 1u; i < index_count - 1; i++) {
36+
unrolled_indices.push_back(center_point);
37+
unrolled_indices.push_back(indices[i]);
38+
unrolled_indices.push_back(indices[i + 1]);
39+
}
40+
} else {
41+
if (vertex_count < 3u) {
42+
return {};
43+
}
44+
45+
// If indices were not provided, create an index buffer that unfans
46+
// triangles instead of re-writing points, colors, et cetera.
47+
for (auto i = 1u; i < vertex_count - 1; i++) {
48+
unrolled_indices.push_back(0);
49+
unrolled_indices.push_back(i);
50+
unrolled_indices.push_back(i + 1);
51+
}
52+
}
53+
return unrolled_indices;
1854
}
1955

20-
static VerticesGeometry::VertexMode ToVertexMode(flutter::DlVertexMode mode) {
21-
switch (mode) {
22-
case flutter::DlVertexMode::kTriangles:
23-
return VerticesGeometry::VertexMode::kTriangles;
24-
case flutter::DlVertexMode::kTriangleStrip:
25-
return VerticesGeometry::VertexMode::kTriangleStrip;
56+
} // namespace
57+
58+
/////// Vertices Geometry ///////
59+
60+
DlVerticesGeometry::DlVerticesGeometry(
61+
const std::shared_ptr<const flutter::DlVertices>& vertices,
62+
const ContentContext& renderer)
63+
: vertices_(vertices) {
64+
performed_normalization_ = MaybePerformIndexNormalization(renderer);
65+
bounds_ = skia_conversions::ToRect(vertices_->bounds());
66+
}
67+
68+
PrimitiveType DlVerticesGeometry::GetPrimitiveType() const {
69+
switch (vertices_->mode()) {
2670
case flutter::DlVertexMode::kTriangleFan:
27-
return VerticesGeometry::VertexMode::kTriangleFan;
28-
};
71+
// Unrolled into triangle mode.
72+
if (performed_normalization_) {
73+
return PrimitiveType::kTriangle;
74+
}
75+
return PrimitiveType::kTriangleFan;
76+
case flutter::DlVertexMode::kTriangleStrip:
77+
return PrimitiveType::kTriangleStrip;
78+
case flutter::DlVertexMode::kTriangles:
79+
return PrimitiveType::kTriangle;
80+
}
81+
}
82+
83+
bool DlVerticesGeometry::HasVertexColors() const {
84+
return vertices_->colors() != nullptr;
2985
}
3086

31-
std::shared_ptr<impeller::VerticesGeometry> MakeVertices(
32-
const std::shared_ptr<const flutter::DlVertices>& vertices) {
33-
auto bounds = ToRect(vertices->bounds());
34-
auto mode = ToVertexMode(vertices->mode());
35-
std::vector<Point> positions(vertices->vertex_count());
36-
for (auto i = 0; i < vertices->vertex_count(); i++) {
37-
positions[i] = skia_conversions::ToPoint(vertices->vertices()[i]);
87+
bool DlVerticesGeometry::HasTextureCoordinates() const {
88+
return vertices_->texture_coordinates() != nullptr;
89+
}
90+
91+
std::optional<Rect> DlVerticesGeometry::GetTextureCoordinateCoverge() const {
92+
if (!HasTextureCoordinates()) {
93+
return std::nullopt;
94+
}
95+
auto vertex_count = vertices_->vertex_count();
96+
if (vertex_count == 0) {
97+
return std::nullopt;
3898
}
3999

40-
std::vector<uint16_t> indices(vertices->index_count());
41-
for (auto i = 0; i < vertices->index_count(); i++) {
42-
indices[i] = vertices->indices()[i];
100+
auto first = vertices_->texture_coordinates();
101+
auto left = first->x();
102+
auto top = first->y();
103+
auto right = first->x();
104+
auto bottom = first->y();
105+
int i = 1;
106+
for (auto it = first + 1; i < vertex_count; ++it, i++) {
107+
left = std::min(left, it->x());
108+
top = std::min(top, it->y());
109+
right = std::max(right, it->x());
110+
bottom = std::max(bottom, it->y());
43111
}
112+
return Rect::MakeLTRB(left, top, right, bottom);
113+
}
44114

45-
std::vector<Color> colors;
46-
if (vertices->colors()) {
47-
colors.reserve(vertices->vertex_count());
48-
for (auto i = 0; i < vertices->vertex_count(); i++) {
49-
colors.push_back(
50-
skia_conversions::ToColor(vertices->colors()[i]).Premultiply());
51-
}
115+
GeometryResult DlVerticesGeometry::GetPositionBuffer(
116+
const ContentContext& renderer,
117+
const Entity& entity,
118+
RenderPass& pass) const {
119+
int vertex_count = vertices_->vertex_count();
120+
BufferView vertex_buffer = renderer.GetTransientsBuffer().Emplace(
121+
vertices_->vertices(), vertex_count * sizeof(SkPoint), alignof(SkPoint));
122+
123+
BufferView index_buffer = {};
124+
auto index_count =
125+
performed_normalization_ ? indices_.size() : vertices_->index_count();
126+
const uint16_t* indices_data =
127+
performed_normalization_ ? indices_.data() : vertices_->indices();
128+
if (index_count) {
129+
index_buffer = renderer.GetTransientsBuffer().Emplace(
130+
indices_data, index_count * sizeof(uint16_t), alignof(uint16_t));
52131
}
53-
std::vector<Point> texture_coordinates;
54-
if (vertices->texture_coordinates()) {
55-
texture_coordinates.reserve(vertices->vertex_count());
56-
for (auto i = 0; i < vertices->vertex_count(); i++) {
57-
texture_coordinates.push_back(
58-
skia_conversions::ToPoint(vertices->texture_coordinates()[i]));
59-
}
132+
133+
return GeometryResult{
134+
.type = GetPrimitiveType(),
135+
.vertex_buffer =
136+
{
137+
.vertex_buffer = vertex_buffer,
138+
.index_buffer = index_buffer,
139+
.vertex_count = index_count > 0 ? index_count : vertex_count,
140+
.index_type =
141+
index_count > 0 ? IndexType::k16bit : IndexType::kNone,
142+
},
143+
.transform = entity.GetShaderTransform(pass),
144+
};
145+
}
146+
147+
GeometryResult DlVerticesGeometry::GetPositionUVColorBuffer(
148+
Rect texture_coverage,
149+
Matrix effect_transform,
150+
const ContentContext& renderer,
151+
const Entity& entity,
152+
RenderPass& pass) const {
153+
using VS = PorterDuffBlendPipeline::VertexShader;
154+
155+
int vertex_count = vertices_->vertex_count();
156+
Matrix uv_transform =
157+
texture_coverage.GetNormalizingTransform() * effect_transform;
158+
bool has_texture_coordinates = HasTextureCoordinates();
159+
bool has_colors = HasVertexColors();
160+
161+
const SkPoint* coordinates = has_texture_coordinates
162+
? vertices_->texture_coordinates()
163+
: vertices_->vertices();
164+
BufferView vertex_buffer = renderer.GetTransientsBuffer().Emplace(
165+
vertex_count * sizeof(VS::PerVertexData), alignof(VS::PerVertexData),
166+
[&](uint8_t* data) {
167+
VS::PerVertexData* vtx_contents =
168+
reinterpret_cast<VS::PerVertexData*>(data);
169+
for (auto i = 0; i < vertex_count; i++) {
170+
Point texture_coord = skia_conversions::ToPoint(coordinates[i]);
171+
Point uv = uv_transform * texture_coord;
172+
Color color = has_colors
173+
? skia_conversions::ToColor(vertices_->colors()[i])
174+
.Premultiply()
175+
: Color::BlackTransparent();
176+
VS::PerVertexData vertex_data = {
177+
.vertices = skia_conversions::ToPoint(vertices_->vertices()[i]),
178+
.texture_coords = uv,
179+
.color = color};
180+
vtx_contents[i] = vertex_data;
181+
}
182+
});
183+
184+
BufferView index_buffer = {};
185+
auto index_count =
186+
performed_normalization_ ? indices_.size() : vertices_->index_count();
187+
const uint16_t* indices_data =
188+
performed_normalization_ ? indices_.data() : vertices_->indices();
189+
if (index_count) {
190+
index_buffer = renderer.GetTransientsBuffer().Emplace(
191+
indices_data, index_count * sizeof(uint16_t), alignof(uint16_t));
192+
}
193+
194+
return GeometryResult{
195+
.type = GetPrimitiveType(),
196+
.vertex_buffer =
197+
{
198+
.vertex_buffer = vertex_buffer,
199+
.index_buffer = index_buffer,
200+
.vertex_count = index_count > 0 ? index_count : vertex_count,
201+
.index_type =
202+
index_count > 0 ? IndexType::k16bit : IndexType::kNone,
203+
},
204+
.transform = entity.GetShaderTransform(pass),
205+
};
206+
}
207+
208+
std::optional<Rect> DlVerticesGeometry::GetCoverage(
209+
const Matrix& transform) const {
210+
return bounds_.TransformBounds(transform);
211+
}
212+
213+
bool DlVerticesGeometry::MaybePerformIndexNormalization(
214+
const ContentContext& renderer) {
215+
if (vertices_->mode() == flutter::DlVertexMode::kTriangleFan &&
216+
!renderer.GetDeviceCapabilities().SupportsTriangleFan()) {
217+
indices_ = fromFanIndices(vertices_->vertex_count(),
218+
vertices_->index_count(), vertices_->indices());
219+
return true;
60220
}
61-
return std::make_shared<VerticesGeometry>(
62-
positions, indices, texture_coordinates, colors, bounds, mode);
221+
return false;
63222
}
64223

65224
} // namespace impeller

0 commit comments

Comments
 (0)