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 
71 
72 PrimitiveType VerticesGeometry::GetPrimitiveType() const {
73  switch (vertex_mode_) {
75  // Unrolled into triangle mode.
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 
93  return colors_.size() > 0;
94 }
95 
97  return texture_coordinates_.size() > 0;
98 }
99 
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 
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 
162  const ContentContext& renderer,
163  const Entity& entity,
164  RenderPass& pass) {
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 
221  Rect texture_coverage,
222  Matrix effect_transform,
223  const ContentContext& renderer,
224  const Entity& entity,
225  RenderPass& pass) {
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 
294  if (HasVertexColors()) {
296  }
297  if (HasTextureCoordinates()) {
299  }
300 
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