| Flutter Impeller |

vertices_geometry.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/entity/geometry/vertices_geometry.h"
6
7 #include <utility>
8
9 #include <utility>
10 #include "impeller/core/formats.h"
11
12 namespace impeller {
13
14 // Fan mode isn't natively supported. Unroll into triangle mode by
15 // manipulating the index array.
16 //
17 // In Triangle fan, the first vertex is shared across all triangles, and then
18 // each sliding window of two vertices plus that first vertex defines a
19 // triangle.
20 static std::vector<uint16_t> fromFanIndices(
21 const std::vector<Point>& vertices,
22 const std::vector<uint16_t>& indices) {
23 std::vector<uint16_t> unrolled_indices;
24
25 // Un-fan index buffer if provided.
26 if (indices.size() > 0u) {
27 if (indices.size() < 3u) {
28 return {};
29 }
30
31 auto center_point = indices[0];
32 for (auto i = 1u; i < indices.size() - 1; i++) {
33 unrolled_indices.push_back(center_point);
34 unrolled_indices.push_back(indices[i]);
35 unrolled_indices.push_back(indices[i + 1]);
36 }
37 } else {
38 if (vertices.size() < 3u) {
39 return {};
40 }
41
42 // If indices were not provided, create an index buffer that unfans
43 // triangles instead of re-writing points, colors, et cetera.
44 for (auto i = 1u; i < vertices.size() - 1; i++) {
45 unrolled_indices.push_back(0);
46 unrolled_indices.push_back(i);
47 unrolled_indices.push_back(i + 1);
48 }
49 }
50 return unrolled_indices;
51 }
52
53 /////// Vertices Geometry ///////
54
55 VerticesGeometry::VerticesGeometry(std::vector<Point> vertices,
56 std::vector<uint16_t> indices,
57 std::vector<Point> texture_coordinates,
58 std::vector<Color> colors,
59 Rect bounds,
60 VertexMode vertex_mode)
61 : vertices_(std::move(vertices)),
62 colors_(std::move(colors)),
63 texture_coordinates_(std::move(texture_coordinates)),
64 indices_(std::move(indices)),
65 bounds_(bounds),
66 vertex_mode_(vertex_mode) {
67 NormalizeIndices();
68 }
69
70 PrimitiveType VerticesGeometry::GetPrimitiveType() const {
71 switch (vertex_mode_) {
72 case VerticesGeometry::VertexMode::kTriangleFan:
73 // Unrolled into triangle mode.
74 return PrimitiveType::kTriangle;
75 case VerticesGeometry::VertexMode::kTriangleStrip:
76 return PrimitiveType::kTriangleStrip;
77 case VerticesGeometry::VertexMode::kTriangles:
78 return PrimitiveType::kTriangle;
79 }
80 }
81
82 void VerticesGeometry::NormalizeIndices() {
83 // Convert triangle fan if present.
84 if (vertex_mode_ == VerticesGeometry::VertexMode::kTriangleFan) {
85 indices_ = fromFanIndices(vertices_, indices_);
86 return;
87 }
88 }
89
90 bool VerticesGeometry::HasVertexColors() const {
91 return colors_.size() > 0;
92 }
93
94 bool VerticesGeometry::HasTextureCoordinates() const {
95 return texture_coordinates_.size() > 0;
96 }
97
98 std::optional<Rect> VerticesGeometry::GetTextureCoordinateCoverge() const {
99 if (!HasTextureCoordinates()) {
100 return std::nullopt;
101 }
102 auto vertex_count = vertices_.size();
103 if (vertex_count == 0) {
104 return std::nullopt;
105 }
106
107 return Rect::MakePointBounds(texture_coordinates_.begin(),
108 texture_coordinates_.end());
109 }
110
111 GeometryResult VerticesGeometry::GetPositionBuffer(
112 const ContentContext& renderer,
113 const Entity& entity,
114 RenderPass& pass) const {
115 auto index_count = indices_.size();
116 auto vertex_count = vertices_.size();
117
118 size_t total_vtx_bytes = vertex_count * sizeof(float) * 2;
119 size_t total_idx_bytes = index_count * sizeof(uint16_t);
120
121 DeviceBufferDescriptor buffer_desc;
122 buffer_desc.size = total_vtx_bytes + total_idx_bytes;
123 buffer_desc.storage_mode = StorageMode::kHostVisible;
124
125 auto buffer =
126 renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
127
128 if (!buffer->CopyHostBuffer(
129 reinterpret_cast<const uint8_t*>(vertices_.data()),
130 Range{0, total_vtx_bytes}, 0)) {
131 return {};
132 }
133 if (index_count > 0 &&
134 !buffer->CopyHostBuffer(
135 reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(indices_.data())),
136 Range{0, total_idx_bytes}, total_vtx_bytes)) {
137 return {};
138 }
139
140 return GeometryResult{
141 .type = GetPrimitiveType(),
142 .vertex_buffer =
143 {
144 .vertex_buffer = {.buffer = buffer,
145 .range = Range{0, total_vtx_bytes}},
146 .index_buffer = {.buffer = buffer,
147 .range =
148 Range{total_vtx_bytes, total_idx_bytes}},
149 .vertex_count = index_count > 0 ? index_count : vertex_count,
150 .index_type =
151 index_count > 0 ? IndexType::k16bit : IndexType::kNone,
152 },
153 .transform = pass.GetOrthographicTransform() * entity.GetTransform(),
154 .prevent_overdraw = false,
155 };
156 }
157
158 GeometryResult VerticesGeometry::GetPositionColorBuffer(
159 const ContentContext& renderer,
160 const Entity& entity,
161 RenderPass& pass) {
162 using VS = GeometryColorPipeline::VertexShader;
163
164 auto index_count = indices_.size();
165 auto vertex_count = vertices_.size();
166
167 std::vector<VS::PerVertexData> vertex_data(vertex_count);
168 {
169 for (auto i = 0u; i < vertex_count; i++) {
170 vertex_data[i] = {
171 .position = vertices_[i],
172 .color = colors_[i],
173 };
174 }
175 }
176
177 size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
178 size_t total_idx_bytes = index_count * sizeof(uint16_t);
179
180 DeviceBufferDescriptor buffer_desc;
181 buffer_desc.size = total_vtx_bytes + total_idx_bytes;
182 buffer_desc.storage_mode = StorageMode::kHostVisible;
183
184 auto buffer =
185 renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
186
187 if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
188 Range{0, total_vtx_bytes}, 0)) {
189 return {};
190 }
191 if (index_count > 0 &&
192 !buffer->CopyHostBuffer(
193 reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(indices_.data())),
194 Range{0, total_idx_bytes}, total_vtx_bytes)) {
195 return {};
196 }
197
198 return GeometryResult{
199 .type = GetPrimitiveType(),
200 .vertex_buffer =
201 {
202 .vertex_buffer = {.buffer = buffer,
203 .range = Range{0, total_vtx_bytes}},
204 .index_buffer = {.buffer = buffer,
205 .range =
206 Range{total_vtx_bytes, total_idx_bytes}},
207 .vertex_count = index_count > 0 ? index_count : vertex_count,
208 .index_type =
209 index_count > 0 ? IndexType::k16bit : IndexType::kNone,
210 },
211 .transform = pass.GetOrthographicTransform() * entity.GetTransform(),
212 .prevent_overdraw = false,
213 };
214 }
215
216 GeometryResult VerticesGeometry::GetPositionUVBuffer(
217 Rect texture_coverage,
218 Matrix effect_transform,
219 const ContentContext& renderer,
220 const Entity& entity,
221 RenderPass& pass) const {
222 using VS = TexturePipeline::VertexShader;
223
224 auto index_count = indices_.size();
225 auto vertex_count = vertices_.size();
226 auto uv_transform =
227 texture_coverage.GetNormalizingTransform() * effect_transform;
228 auto has_texture_coordinates = HasTextureCoordinates();
229 std::vector<VS::PerVertexData> vertex_data(vertex_count);
230 {
231 for (auto i = 0u; i < vertex_count; i++) {
232 auto vertex = vertices_[i];
233 auto texture_coord =
234 has_texture_coordinates ? texture_coordinates_[i] : vertices_[i];
235 auto uv = uv_transform * texture_coord;
236 // From experimentation we need to clamp these values to < 1.0 or else
237 // there can be flickering.
238 vertex_data[i] = {
239 .position = vertex,
240 .texture_coords =
241 Point(std::clamp(uv.x, 0.0f, 1.0f - kEhCloseEnough),
242 std::clamp(uv.y, 0.0f, 1.0f - kEhCloseEnough)),
243 };
244 }
245 }
246
247 size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
248 size_t total_idx_bytes = index_count * sizeof(uint16_t);
249
250 DeviceBufferDescriptor buffer_desc;
251 buffer_desc.size = total_vtx_bytes + total_idx_bytes;
252 buffer_desc.storage_mode = StorageMode::kHostVisible;
253
254 auto buffer =
255 renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
256
257 if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
258 Range{0, total_vtx_bytes}, 0)) {
259 return {};
260 }
261 if (index_count > 0u &&
262 !buffer->CopyHostBuffer(
263 reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(indices_.data())),
264 Range{0, total_idx_bytes}, total_vtx_bytes)) {
265 return {};
266 }
267
268 return GeometryResult{
269 .type = GetPrimitiveType(),
270 .vertex_buffer =
271 {
272 .vertex_buffer = {.buffer = buffer,
273 .range = Range{0, total_vtx_bytes}},
274 .index_buffer = {.buffer = buffer,
275 .range =
276 Range{total_vtx_bytes, total_idx_bytes}},
277 .vertex_count = index_count > 0 ? index_count : vertex_count,
278 .index_type =
279 index_count > 0 ? IndexType::k16bit : IndexType::kNone,
280 },
281 .transform = pass.GetOrthographicTransform() * entity.GetTransform(),
282 .prevent_overdraw = false,
283 };
284 }
285
286 GeometryVertexType VerticesGeometry::GetVertexType() const {
287 if (HasVertexColors()) {
288 return GeometryVertexType::kColor;
289 }
290 if (HasTextureCoordinates()) {
291 return GeometryVertexType::kUV;
292 }
293
294 return GeometryVertexType::kPosition;
295 }
296
297 std::optional<Rect> VerticesGeometry::GetCoverage(
298 const Matrix& transform) const {
299 return bounds_.TransformBounds(transform);
300 }
301
302 } // namespace impeller
impeller::IndexType::k16bit
@ k16bit
impeller::Entity::GetTransform
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:49
impeller::DeviceBufferDescriptor
Definition: device_buffer_descriptor.h:14
impeller::VerticesGeometry::VerticesGeometry
VerticesGeometry(std::vector< Point > vertices, std::vector< uint16_t > indices, std::vector< Point > texture_coordinates, std::vector< Color > colors, Rect bounds, VerticesGeometry::VertexMode vertex_mode)
Definition: vertices_geometry.cc:55
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:56
impeller::TRect::TransformBounds
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:264
formats.h
impeller::TRect::GetNormalizingTransform
constexpr Matrix GetNormalizingTransform() const
Constructs a Matrix that will map all points in the coordinate space of the rectangle into a new norm...
Definition: rect.h:280
impeller::VerticesGeometry::GetPositionUVBuffer
GeometryResult GetPositionUVBuffer(Rect texture_coverage, Matrix effect_transform, const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Definition: vertices_geometry.cc:216
impeller::DeviceBufferDescriptor::size
size_t size
Definition: device_buffer_descriptor.h:16
impeller::StorageMode::kHostVisible
@ kHostVisible
impeller::RenderPass::GetOrthographicTransform
const Matrix & GetOrthographicTransform() const
Definition: render_pass.cc:51
impeller::GeometryVertexType
GeometryVertexType
Definition: geometry.h:34
impeller::TRect< Scalar >::MakePointBounds
constexpr static std::optional< TRect > MakePointBounds(const U &value)
Definition: rect.h:49
impeller::kColor
@ kColor
Definition: geometry.h:36
impeller::PrimitiveType::kTriangle
@ kTriangle
impeller::Entity
Definition: entity.h:21
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::PrimitiveType
PrimitiveType
Decides how backend draws pixels based on input vertices.
Definition: formats.h:350
impeller::Point
TPoint< Scalar > Point
Definition: point.h:308
impeller::VerticesGeometry::VertexMode
VertexMode
Definition: vertices_geometry.h:15
impeller::GeometryResult::type
PrimitiveType type
Definition: geometry.h:21
impeller::ContentContext::GetContext
std::shared_ptr< Context > GetContext() const
Definition: content_context.cc:479
impeller::VerticesGeometry::HasVertexColors
bool HasVertexColors() const
Definition: vertices_geometry.cc:90
impeller::VerticesGeometry::VertexMode::kTriangleStrip
@ kTriangleStrip
impeller::VerticesGeometry::GetPositionColorBuffer
GeometryResult GetPositionColorBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass)
Definition: vertices_geometry.cc:158
impeller::GeometryResult
Definition: geometry.h:20
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::VerticesGeometry::GetVertexType
GeometryVertexType GetVertexType() const override
Definition: vertices_geometry.cc:286
vertices_geometry.h
impeller::kUV
@ kUV
Definition: geometry.h:37
impeller::VerticesGeometry::GetCoverage
std::optional< Rect > GetCoverage(const Matrix &transform) const override
Definition: vertices_geometry.cc:297
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:29
impeller::Range
Definition: range.h:14
std
Definition: comparable.h:95
impeller::VerticesGeometry::GetPositionBuffer
GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Definition: vertices_geometry.cc:111
impeller::VerticesGeometry::VertexMode::kTriangles
@ kTriangles
impeller::VerticesGeometry::HasTextureCoordinates
bool HasTextureCoordinates() const
Definition: vertices_geometry.cc:94
impeller::RenderPipelineT::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:92
impeller
Definition: aiks_context.cc:10
impeller::VerticesGeometry::VertexMode::kTriangleFan
@ kTriangleFan
impeller::kPosition
@ kPosition
Definition: geometry.h:35
impeller::ContentContext
Definition: content_context.h:332
impeller::TRect< Scalar >
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::VerticesGeometry::GetTextureCoordinateCoverge
std::optional< Rect > GetTextureCoordinateCoverge() const
Definition: vertices_geometry.cc:98
impeller::fromFanIndices
static std::vector< uint16_t > fromFanIndices(const std::vector< Point > &vertices, const std::vector< uint16_t > &indices)
Definition: vertices_geometry.cc:20