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 
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_) {
73  // Unrolled into triangle mode.
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 
91  return colors_.size() > 0;
92 }
93 
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 
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 
159  const ContentContext& renderer,
160  const Entity& entity,
161  RenderPass& pass) {
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 
217  Rect texture_coverage,
218  Matrix effect_transform,
219  const ContentContext& renderer,
220  const Entity& entity,
221  RenderPass& pass) const {
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 
287  if (HasVertexColors()) {
289  }
290  if (HasTextureCoordinates()) {
292  }
293 
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