| 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 VerticesGeometry::~VerticesGeometry() = default;
71
72 PrimitiveType VerticesGeometry::GetPrimitiveType() const {
73 switch (vertex_mode_) {
74 case VerticesGeometry::VertexMode::kTriangleFan:
75 // Unrolled into triangle mode.
76 return PrimitiveType::kTriangle;
77 case VerticesGeometry::VertexMode::kTriangleStrip:
78 return PrimitiveType::kTriangleStrip;
79 case VerticesGeometry::VertexMode::kTriangles:
80 return PrimitiveType::kTriangle;
81 }
82 }
83
84 void VerticesGeometry::NormalizeIndices() {
85 // Convert triangle fan if present.
86 if (vertex_mode_ == VerticesGeometry::VertexMode::kTriangleFan) {
87 indices_ = fromFanIndices(vertices_, indices_);
88 return;
89 }
90 }
91
92 bool VerticesGeometry::HasVertexColors() const {
93 return colors_.size() > 0;
94 }
95
96 bool VerticesGeometry::HasTextureCoordinates() const {
97 return texture_coordinates_.size() > 0;
98 }
99
100 std::optional<Rect> VerticesGeometry::GetTextureCoordinateCoverge() const {
101 if (!HasTextureCoordinates()) {
102 return std::nullopt;
103 }
104 auto vertex_count = vertices_.size();
105 if (vertex_count == 0) {
106 return std::nullopt;
107 }
108
109 return Rect::MakePointBounds(texture_coordinates_.begin(),
110 texture_coordinates_.end());
111 }
112
113 GeometryResult VerticesGeometry::GetPositionBuffer(
114 const ContentContext& renderer,
115 const Entity& entity,
116 RenderPass& pass) {
117 auto index_count = indices_.size();
118 auto vertex_count = vertices_.size();
119
120 size_t total_vtx_bytes = vertex_count * sizeof(float) * 2;
121 size_t total_idx_bytes = index_count * sizeof(uint16_t);
122
123 DeviceBufferDescriptor buffer_desc;
124 buffer_desc.size = total_vtx_bytes + total_idx_bytes;
125 buffer_desc.storage_mode = StorageMode::kHostVisible;
126
127 auto buffer =
128 renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
129
130 if (!buffer->CopyHostBuffer(
131 reinterpret_cast<const uint8_t*>(vertices_.data()),
132 Range{0, total_vtx_bytes}, 0)) {
133 return {};
134 }
135 if (index_count > 0 &&
136 !buffer->CopyHostBuffer(
137 reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(indices_.data())),
138 Range{0, total_idx_bytes}, total_vtx_bytes)) {
139 return {};
140 }
141
142 return GeometryResult{
143 .type = GetPrimitiveType(),
144 .vertex_buffer =
145 {
146 .vertex_buffer = {.buffer = buffer,
147 .range = Range{0, total_vtx_bytes}},
148 .index_buffer = {.buffer = buffer,
149 .range =
150 Range{total_vtx_bytes, total_idx_bytes}},
151 .vertex_count = index_count > 0 ? index_count : vertex_count,
152 .index_type =
153 index_count > 0 ? IndexType::k16bit : IndexType::kNone,
154 },
155 .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
156 entity.GetTransformation(),
157 .prevent_overdraw = false,
158 };
159 }
160
161 GeometryResult VerticesGeometry::GetPositionColorBuffer(
162 const ContentContext& renderer,
163 const Entity& entity,
164 RenderPass& pass) {
165 using VS = GeometryColorPipeline::VertexShader;
166
167 auto index_count = indices_.size();
168 auto vertex_count = vertices_.size();
169
170 std::vector<VS::PerVertexData> vertex_data(vertex_count);
171 {
172 for (auto i = 0u; i < vertex_count; i++) {
173 vertex_data[i] = {
174 .position = vertices_[i],
175 .color = colors_[i],
176 };
177 }
178 }
179
180 size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
181 size_t total_idx_bytes = index_count * sizeof(uint16_t);
182
183 DeviceBufferDescriptor buffer_desc;
184 buffer_desc.size = total_vtx_bytes + total_idx_bytes;
185 buffer_desc.storage_mode = StorageMode::kHostVisible;
186
187 auto buffer =
188 renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
189
190 if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
191 Range{0, total_vtx_bytes}, 0)) {
192 return {};
193 }
194 if (index_count > 0 &&
195 !buffer->CopyHostBuffer(
196 reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(indices_.data())),
197 Range{0, total_idx_bytes}, total_vtx_bytes)) {
198 return {};
199 }
200
201 return GeometryResult{
202 .type = GetPrimitiveType(),
203 .vertex_buffer =
204 {
205 .vertex_buffer = {.buffer = buffer,
206 .range = Range{0, total_vtx_bytes}},
207 .index_buffer = {.buffer = buffer,
208 .range =
209 Range{total_vtx_bytes, total_idx_bytes}},
210 .vertex_count = index_count > 0 ? index_count : vertex_count,
211 .index_type =
212 index_count > 0 ? IndexType::k16bit : IndexType::kNone,
213 },
214 .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
215 entity.GetTransformation(),
216 .prevent_overdraw = false,
217 };
218 }
219
220 GeometryResult VerticesGeometry::GetPositionUVBuffer(
221 Rect texture_coverage,
222 Matrix effect_transform,
223 const ContentContext& renderer,
224 const Entity& entity,
225 RenderPass& pass) {
226 using VS = TexturePipeline::VertexShader;
227
228 auto index_count = indices_.size();
229 auto vertex_count = vertices_.size();
230 auto size = texture_coverage.size;
231 auto origin = texture_coverage.origin;
232 auto has_texture_coordinates = HasTextureCoordinates();
233 std::vector<VS::PerVertexData> vertex_data(vertex_count);
234 {
235 for (auto i = 0u; i < vertex_count; i++) {
236 auto vertex = vertices_[i];
237 auto texture_coord =
238 has_texture_coordinates ? texture_coordinates_[i] : vertices_[i];
239 auto uv =
240 effect_transform * Point((texture_coord.x - origin.x) / size.width,
241 (texture_coord.y - origin.y) / size.height);
242 // From experimentation we need to clamp these values to < 1.0 or else
243 // there can be flickering.
244 vertex_data[i] = {
245 .position = vertex,
246 .texture_coords =
247 Point(std::clamp(uv.x, 0.0f, 1.0f - kEhCloseEnough),
248 std::clamp(uv.y, 0.0f, 1.0f - kEhCloseEnough)),
249 };
250 }
251 }
252
253 size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
254 size_t total_idx_bytes = index_count * sizeof(uint16_t);
255
256 DeviceBufferDescriptor buffer_desc;
257 buffer_desc.size = total_vtx_bytes + total_idx_bytes;
258 buffer_desc.storage_mode = StorageMode::kHostVisible;
259
260 auto buffer =
261 renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
262
263 if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
264 Range{0, total_vtx_bytes}, 0)) {
265 return {};
266 }
267 if (index_count > 0u &&
268 !buffer->CopyHostBuffer(
269 reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(indices_.data())),
270 Range{0, total_idx_bytes}, total_vtx_bytes)) {
271 return {};
272 }
273
274 return GeometryResult{
275 .type = GetPrimitiveType(),
276 .vertex_buffer =
277 {
278 .vertex_buffer = {.buffer = buffer,
279 .range = Range{0, total_vtx_bytes}},
280 .index_buffer = {.buffer = buffer,
281 .range =
282 Range{total_vtx_bytes, total_idx_bytes}},
283 .vertex_count = index_count > 0 ? index_count : vertex_count,
284 .index_type =
285 index_count > 0 ? IndexType::k16bit : IndexType::kNone,
286 },
287 .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
288 entity.GetTransformation(),
289 .prevent_overdraw = false,
290 };
291 }
292
293 GeometryVertexType VerticesGeometry::GetVertexType() const {
294 if (HasVertexColors()) {
295 return GeometryVertexType::kColor;
296 }
297 if (HasTextureCoordinates()) {
298 return GeometryVertexType::kUV;
299 }
300
301 return GeometryVertexType::kPosition;
302 }
303
304 std::optional<Rect> VerticesGeometry::GetCoverage(
305 const Matrix& transform) const {
306 return bounds_.TransformBounds(transform);
307 }
308
309 } // namespace impeller
impeller::PrimitiveType
PrimitiveType
Definition: formats.h:328
impeller::TRect::size
TSize< Type > size
Definition: rect.h:24
impeller::IndexType::k16bit
@ k16bit
impeller::DeviceBufferDescriptor
Definition: device_buffer_descriptor.h:13
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:55
impeller::TRect::TransformBounds
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:204
formats.h
impeller::DeviceBufferDescriptor::size
size_t size
Definition: device_buffer_descriptor.h:15
impeller::StorageMode::kHostVisible
@ kHostVisible
impeller::GeometryVertexType
GeometryVertexType
Definition: geometry.h:25
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Entity::GetTransformation
const Matrix & GetTransformation() const
Definition: entity.cc:49
impeller::kColor
@ kColor
Definition: geometry.h:27
impeller::Entity
Definition: entity.h:21
impeller::RenderPass::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_pass.cc:30
impeller::Point
TPoint< Scalar > Point
Definition: point.h:306
impeller::VerticesGeometry::VertexMode
VertexMode
Definition: vertices_geometry.h:14
impeller::GeometryResult::type
PrimitiveType type
Definition: geometry.h:19
impeller::ContentContext::GetContext
std::shared_ptr< Context > GetContext() const
Definition: content_context.cc:440
impeller::VerticesGeometry::HasVertexColors
bool HasVertexColors() const
Definition: vertices_geometry.cc:92
impeller::VerticesGeometry::VertexMode::kTriangleStrip
@ kTriangleStrip
impeller::VerticesGeometry::GetPositionColorBuffer
GeometryResult GetPositionColorBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass)
Definition: vertices_geometry.cc:161
impeller::GeometryResult
Definition: geometry.h:18
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::VerticesGeometry::GetVertexType
GeometryVertexType GetVertexType() const override
Definition: vertices_geometry.cc:293
impeller::TRect::origin
TPoint< Type > origin
Definition: rect.h:23
impeller::TRect< Scalar >::MakePointBounds
constexpr static std::optional< TRect > MakePointBounds(const PointIter first, const PointIter last)
Definition: rect.h:57
vertices_geometry.h
impeller::kUV
@ kUV
Definition: geometry.h:28
impeller::VerticesGeometry::GetCoverage
std::optional< Rect > GetCoverage(const Matrix &transform) const override
Definition: vertices_geometry.cc:304
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:27
impeller::VerticesGeometry::GetPositionBuffer
GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) override
Definition: vertices_geometry.cc:113
impeller::Range
Definition: range.h:13
std
Definition: comparable.h:98
impeller::Matrix::MakeOrthographic
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:448
impeller::VerticesGeometry::GetPositionUVBuffer
GeometryResult GetPositionUVBuffer(Rect texture_coverage, Matrix effect_transform, const ContentContext &renderer, const Entity &entity, RenderPass &pass) override
Definition: vertices_geometry.cc:220
impeller::VerticesGeometry::VertexMode::kTriangles
@ kTriangles
impeller::PrimitiveType::kTriangle
@ kTriangle
impeller::VerticesGeometry::HasTextureCoordinates
bool HasTextureCoordinates() const
Definition: vertices_geometry.cc:96
impeller::VerticesGeometry::~VerticesGeometry
~VerticesGeometry()
impeller::RenderPipelineT::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:90
impeller
Definition: aiks_context.cc:10
impeller::VerticesGeometry::VertexMode::kTriangleFan
@ kTriangleFan
impeller::kPosition
@ kPosition
Definition: geometry.h:26
impeller::ContentContext
Definition: content_context.h:344
impeller::TRect< Scalar >
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:36
impeller::VerticesGeometry::GetTextureCoordinateCoverge
std::optional< Rect > GetTextureCoordinateCoverge() const
Definition: vertices_geometry.cc:100
impeller::fromFanIndices
static std::vector< uint16_t > fromFanIndices(const std::vector< Point > &vertices, const std::vector< uint16_t > &indices)
Definition: vertices_geometry.cc:20