[Impeller] copy data out of DlVertices. (flutter/engine#45355)

The implementation of DLVerticesGeometry is holding onto a raw ptr that it doesn't own nor does it know that the lifecycle is deterministic. My bad!

This mostly worked (ehhh) until the stopwatch visualizer change. I've confirmed that going back to copying the data fixes the issue with the stopwatch visualizer.
This commit is contained in:
Jonah Williams 2023-08-31 16:58:04 -07:00 committed by GitHub
parent 8d106930d6
commit ff37fcdf5a
5 changed files with 384 additions and 384 deletions

View File

@ -967,8 +967,7 @@ void DlDispatcher::drawPoints(PointMode mode,
// |flutter::DlOpReceiver|
void DlDispatcher::drawVertices(const flutter::DlVertices* vertices,
flutter::DlBlendMode dl_mode) {
canvas_.DrawVertices(DlVerticesGeometry::MakeVertices(vertices),
ToBlendMode(dl_mode), paint_);
canvas_.DrawVertices(MakeVertices(vertices), ToBlendMode(dl_mode), paint_);
}
// |flutter::DlOpReceiver|

View File

@ -4,15 +4,10 @@
#include "impeller/display_list/dl_vertices_geometry.h"
#include "impeller/core/device_buffer.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/position_color.vert.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/path_builder.h"
#include "display_list/dl_vertices.h"
#include "impeller/display_list/skia_conversions.h"
#include "impeller/entity/geometry/vertices_geometry.h"
#include "impeller/geometry/point.h"
#include "impeller/renderer/render_pass.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "third_party/skia/include/core/SkRect.h"
@ -22,330 +17,48 @@ static Rect ToRect(const SkRect& rect) {
return Rect::MakeLTRB(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
}
// Fan mode isn't natively supported. Unroll into triangle mode by
// manipulating the index array.
//
// In Triangle fan, the first vertex is shared across all triangles, and then
// each sliding window of two vertices plus that first vertex defines a
// triangle.
static std::vector<uint16_t> fromFanIndices(
const flutter::DlVertices* vertices) {
FML_DCHECK(vertices->vertex_count() >= 3);
FML_DCHECK(vertices->mode() == flutter::DlVertexMode::kTriangleFan);
std::vector<uint16_t> indices;
// Un-fan index buffer if provided.
if (vertices->index_count() > 0) {
auto* dl_indices = vertices->indices();
auto center_point = dl_indices[0];
for (int i = 1; i < vertices->index_count() - 1; i++) {
indices.push_back(center_point);
indices.push_back(dl_indices[i]);
indices.push_back(dl_indices[i + 1]);
}
} else {
// If indices were not provided, create an index buffer that unfans
// triangles instead of re-writing points, colors, et cetera.
for (int i = 1; i < vertices->vertex_count() - 1; i++) {
indices.push_back(0);
indices.push_back(i);
indices.push_back(i + 1);
}
}
return indices;
}
/////// Vertices Geometry ///////
// static
std::shared_ptr<VerticesGeometry> DlVerticesGeometry::MakeVertices(
const flutter::DlVertices* vertices) {
return std::make_shared<DlVerticesGeometry>(vertices);
}
DlVerticesGeometry::DlVerticesGeometry(const flutter::DlVertices* vertices)
: vertices_(vertices) {
NormalizeIndices();
}
DlVerticesGeometry::~DlVerticesGeometry() = default;
void DlVerticesGeometry::NormalizeIndices() {
// Convert triangle fan if present.
if (vertices_->mode() == flutter::DlVertexMode::kTriangleFan) {
normalized_indices_ = fromFanIndices(vertices_);
return;
}
auto index_count = vertices_->index_count();
auto vertex_count = vertices_->vertex_count();
if (index_count != 0 || vertex_count == 0) {
return;
}
normalized_indices_.reserve(vertex_count);
for (auto i = 0; i < vertex_count; i++) {
normalized_indices_.push_back(i);
}
}
static PrimitiveType GetPrimitiveType(const flutter::DlVertices* vertices) {
switch (vertices->mode()) {
static VerticesGeometry::VertexMode ToVertexMode(flutter::DlVertexMode mode) {
switch (mode) {
case flutter::DlVertexMode::kTriangles:
return PrimitiveType::kTriangle;
return VerticesGeometry::VertexMode::kTriangles;
case flutter::DlVertexMode::kTriangleStrip:
return PrimitiveType::kTriangleStrip;
return VerticesGeometry::VertexMode::kTriangleStrip;
case flutter::DlVertexMode::kTriangleFan:
// Unrolled into triangle mode.
return PrimitiveType::kTriangle;
}
}
std::optional<Rect> DlVerticesGeometry::GetTextureCoordinateCoverge() const {
if (!HasTextureCoordinates()) {
return std::nullopt;
}
auto vertex_count = vertices_->vertex_count();
auto* dl_texture_coordinates = vertices_->texture_coordinates();
if (vertex_count == 0) {
return std::nullopt;
}
auto left = dl_texture_coordinates[0].x();
auto top = dl_texture_coordinates[0].y();
auto right = dl_texture_coordinates[0].x();
auto bottom = dl_texture_coordinates[0].y();
for (auto i = 0; i < vertex_count; i++) {
left = std::min(left, dl_texture_coordinates[i].x());
top = std::min(top, dl_texture_coordinates[i].y());
right = std::max(right, dl_texture_coordinates[i].x());
bottom = std::max(bottom, dl_texture_coordinates[i].y());
}
return Rect::MakeLTRB(left, top, right, bottom);
}
bool DlVerticesGeometry::HasVertexColors() const {
return vertices_->colors() != nullptr;
}
bool DlVerticesGeometry::HasTextureCoordinates() const {
return vertices_->texture_coordinates() != nullptr;
}
GeometryResult DlVerticesGeometry::GetPositionBuffer(
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) {
auto index_count = normalized_indices_.size() == 0
? vertices_->index_count()
: normalized_indices_.size();
auto vertex_count = vertices_->vertex_count();
auto* dl_indices = normalized_indices_.size() == 0
? vertices_->indices()
: normalized_indices_.data();
auto* dl_vertices = vertices_->vertices();
size_t total_vtx_bytes = vertex_count * sizeof(float) * 2;
size_t total_idx_bytes = index_count * sizeof(uint16_t);
DeviceBufferDescriptor buffer_desc;
buffer_desc.size = total_vtx_bytes + total_idx_bytes;
buffer_desc.storage_mode = StorageMode::kHostVisible;
auto buffer =
renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
if (!buffer->CopyHostBuffer(reinterpret_cast<const uint8_t*>(dl_vertices),
Range{0, total_vtx_bytes}, 0)) {
return {};
}
if (!buffer->CopyHostBuffer(
reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(dl_indices)),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
return {};
}
return GeometryResult{
.type = GetPrimitiveType(vertices_),
.vertex_buffer =
{
.vertex_buffer = {.buffer = buffer,
.range = Range{0, total_vtx_bytes}},
.index_buffer = {.buffer = buffer,
.range =
Range{total_vtx_bytes, total_idx_bytes}},
.vertex_count = index_count,
.index_type = IndexType::k16bit,
},
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation(),
.prevent_overdraw = false,
return VerticesGeometry::VertexMode::kTriangleFan;
};
}
GeometryResult DlVerticesGeometry::GetPositionColorBuffer(
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) {
using VS = GeometryColorPipeline::VertexShader;
std::shared_ptr<impeller::VerticesGeometry> MakeVertices(
const flutter::DlVertices* vertices) {
auto bounds = ToRect(vertices->bounds());
auto mode = ToVertexMode(vertices->mode());
std::vector<Point> positions(vertices->vertex_count());
for (auto i = 0; i < vertices->vertex_count(); i++) {
positions[i] = skia_conversions::ToPoint(vertices->vertices()[i]);
}
auto index_count = normalized_indices_.size() == 0
? vertices_->index_count()
: normalized_indices_.size();
auto vertex_count = vertices_->vertex_count();
auto* dl_indices = normalized_indices_.size() == 0
? vertices_->indices()
: normalized_indices_.data();
auto* dl_vertices = vertices_->vertices();
auto* dl_colors = vertices_->colors();
std::vector<uint16_t> indices(vertices->index_count());
for (auto i = 0; i < vertices->index_count(); i++) {
indices[i] = vertices->indices()[i];
}
std::vector<VS::PerVertexData> vertex_data(vertex_count);
{
for (auto i = 0; i < vertex_count; i++) {
auto dl_color = dl_colors[i];
auto color = Color(dl_color.getRedF(), dl_color.getGreenF(),
dl_color.getBlueF(), dl_color.getAlphaF())
.Premultiply();
auto sk_point = dl_vertices[i];
vertex_data[i] = {
.position = Point(sk_point.x(), sk_point.y()),
.color = color,
};
std::vector<Color> colors;
if (vertices->colors()) {
colors.reserve(vertices->vertex_count());
for (auto i = 0; i < vertices->vertex_count(); i++) {
colors.push_back(skia_conversions::ToColor(vertices->colors()[i]));
}
}
size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
size_t total_idx_bytes = index_count * sizeof(uint16_t);
DeviceBufferDescriptor buffer_desc;
buffer_desc.size = total_vtx_bytes + total_idx_bytes;
buffer_desc.storage_mode = StorageMode::kHostVisible;
auto buffer =
renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
Range{0, total_vtx_bytes}, 0)) {
return {};
}
if (!buffer->CopyHostBuffer(
reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(dl_indices)),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
return {};
}
return GeometryResult{
.type = GetPrimitiveType(vertices_),
.vertex_buffer =
{
.vertex_buffer = {.buffer = buffer,
.range = Range{0, total_vtx_bytes}},
.index_buffer = {.buffer = buffer,
.range =
Range{total_vtx_bytes, total_idx_bytes}},
.vertex_count = index_count,
.index_type = IndexType::k16bit,
},
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation(),
.prevent_overdraw = false,
};
}
GeometryResult DlVerticesGeometry::GetPositionUVBuffer(
Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) {
using VS = TexturePipeline::VertexShader;
auto index_count = normalized_indices_.size() == 0
? vertices_->index_count()
: normalized_indices_.size();
auto vertex_count = vertices_->vertex_count();
auto* dl_indices = normalized_indices_.size() == 0
? vertices_->indices()
: normalized_indices_.data();
auto* dl_vertices = vertices_->vertices();
auto* dl_texture_coordinates = vertices_->texture_coordinates();
auto size = texture_coverage.size;
auto origin = texture_coverage.origin;
std::vector<VS::PerVertexData> vertex_data(vertex_count);
{
for (auto i = 0; i < vertex_count; i++) {
auto sk_point = dl_vertices[i];
auto texture_coord = dl_texture_coordinates[i];
auto uv = effect_transform *
Point((texture_coord.x() - origin.x) / size.width,
(texture_coord.y() - origin.y) / size.height);
// From experimentation we need to clamp these values to < 1.0 or else
// there can be flickering.
vertex_data[i] = {
.position = Point(sk_point.x(), sk_point.y()),
.texture_coords =
Point(std::clamp(uv.x, 0.0f, 1.0f - kEhCloseEnough),
std::clamp(uv.y, 0.0f, 1.0f - kEhCloseEnough)),
};
std::vector<Point> texture_coordinates;
if (vertices->texture_coordinates()) {
texture_coordinates.reserve(vertices->vertex_count());
for (auto i = 0; i < vertices->vertex_count(); i++) {
texture_coordinates.push_back(
skia_conversions::ToPoint(vertices->texture_coordinates()[i]));
}
}
size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
size_t total_idx_bytes = index_count * sizeof(uint16_t);
DeviceBufferDescriptor buffer_desc;
buffer_desc.size = total_vtx_bytes + total_idx_bytes;
buffer_desc.storage_mode = StorageMode::kHostVisible;
auto buffer =
renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
Range{0, total_vtx_bytes}, 0)) {
return {};
}
if (!buffer->CopyHostBuffer(
reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(dl_indices)),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
return {};
}
return GeometryResult{
.type = GetPrimitiveType(vertices_),
.vertex_buffer =
{
.vertex_buffer = {.buffer = buffer,
.range = Range{0, total_vtx_bytes}},
.index_buffer = {.buffer = buffer,
.range =
Range{total_vtx_bytes, total_idx_bytes}},
.vertex_count = index_count,
.index_type = IndexType::k16bit,
},
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation(),
.prevent_overdraw = false,
};
}
GeometryVertexType DlVerticesGeometry::GetVertexType() const {
auto* dl_colors = vertices_->colors();
if (dl_colors != nullptr) {
return GeometryVertexType::kColor;
}
auto* dl_texture_coordinates = vertices_->texture_coordinates();
if (dl_texture_coordinates != nullptr) {
return GeometryVertexType::kUV;
}
return GeometryVertexType::kPosition;
}
std::optional<Rect> DlVerticesGeometry::GetCoverage(
const Matrix& transform) const {
return ToRect(vertices_->bounds()).TransformBounds(transform);
return std::make_shared<VerticesGeometry>(
positions, indices, texture_coordinates, colors, bounds, mode);
}
} // namespace impeller

View File

@ -4,67 +4,13 @@
#pragma once
#include <optional>
#include <vector>
#include "flutter/display_list/dl_vertices.h"
#include "impeller/entity/geometry/vertices_geometry.h"
#include "impeller/geometry/color.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/rect.h"
namespace impeller {
/// @brief A geometry that is created from a vertices object.
class DlVerticesGeometry : public VerticesGeometry {
public:
explicit DlVerticesGeometry(const flutter::DlVertices* vertices);
~DlVerticesGeometry();
static std::shared_ptr<VerticesGeometry> MakeVertices(
const flutter::DlVertices* vertices);
// |VerticesGeometry|
GeometryResult GetPositionColorBuffer(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) override;
// |VerticesGeometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) override;
// |Geometry|
GeometryResult GetPositionBuffer(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) override;
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
// |Geometry|
GeometryVertexType GetVertexType() const override;
// |VerticesGeometry|
bool HasVertexColors() const override;
// |VerticesGeometry|
bool HasTextureCoordinates() const override;
// |VerticesGeometry|
std::optional<Rect> GetTextureCoordinateCoverge() const override;
private:
void NormalizeIndices();
const flutter::DlVertices* vertices_;
std::vector<uint16_t> normalized_indices_;
FML_DISALLOW_COPY_AND_ASSIGN(DlVerticesGeometry);
};
std::shared_ptr<VerticesGeometry> MakeVertices(
const flutter::DlVertices* vertices);
} // namespace impeller

View File

@ -4,8 +4,304 @@
#include "impeller/entity/geometry/vertices_geometry.h"
#include <utility>
#include <utility>
#include "impeller/core/formats.h"
namespace impeller {
// Fan mode isn't natively supported. Unroll into triangle mode by
// manipulating the index array.
//
// In Triangle fan, the first vertex is shared across all triangles, and then
// each sliding window of two vertices plus that first vertex defines a
// triangle.
static std::vector<uint16_t> fromFanIndices(
const std::vector<Point>& vertices,
const std::vector<uint16_t>& indices) {
std::vector<uint16_t> unrolled_indices;
// Un-fan index buffer if provided.
if (indices.size() > 0u) {
if (indices.size() < 3u) {
return {};
}
auto center_point = indices[0];
for (auto i = 1u; i < indices.size() - 1; i++) {
unrolled_indices.push_back(center_point);
unrolled_indices.push_back(indices[i]);
unrolled_indices.push_back(indices[i + 1]);
}
} else {
if (vertices.size() < 3u) {
return {};
}
// If indices were not provided, create an index buffer that unfans
// triangles instead of re-writing points, colors, et cetera.
for (auto i = 1u; i < vertices.size() - 1; i++) {
unrolled_indices.push_back(0);
unrolled_indices.push_back(i);
unrolled_indices.push_back(i + 1);
}
}
return unrolled_indices;
}
/////// Vertices Geometry ///////
VerticesGeometry::VerticesGeometry(std::vector<Point> vertices,
std::vector<uint16_t> indices,
std::vector<Point> texture_coordinates,
std::vector<Color> colors,
Rect bounds,
VertexMode vertex_mode)
: vertices_(std::move(vertices)),
colors_(std::move(colors)),
texture_coordinates_(std::move(texture_coordinates)),
indices_(std::move(indices)),
bounds_(bounds),
vertex_mode_(vertex_mode) {
NormalizeIndices();
}
VerticesGeometry::~VerticesGeometry() = default;
PrimitiveType VerticesGeometry::GetPrimitiveType() const {
switch (vertex_mode_) {
case VerticesGeometry::VertexMode::kTriangleFan:
// Unrolled into triangle mode.
return PrimitiveType::kTriangle;
case VerticesGeometry::VertexMode::kTriangleStrip:
return PrimitiveType::kTriangleStrip;
case VerticesGeometry::VertexMode::kTriangles:
return PrimitiveType::kTriangle;
}
}
void VerticesGeometry::NormalizeIndices() {
// Convert triangle fan if present.
if (vertex_mode_ == VerticesGeometry::VertexMode::kTriangleFan) {
indices_ = fromFanIndices(vertices_, indices_);
return;
}
}
bool VerticesGeometry::HasVertexColors() const {
return colors_.size() > 0;
}
bool VerticesGeometry::HasTextureCoordinates() const {
return texture_coordinates_.size() > 0;
}
std::optional<Rect> VerticesGeometry::GetTextureCoordinateCoverge() const {
if (!HasTextureCoordinates()) {
return std::nullopt;
}
auto vertex_count = vertices_.size();
if (vertex_count == 0) {
return std::nullopt;
}
return Rect::MakePointBounds(texture_coordinates_.begin(),
texture_coordinates_.end());
}
GeometryResult VerticesGeometry::GetPositionBuffer(
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) {
auto index_count = indices_.size();
auto vertex_count = vertices_.size();
size_t total_vtx_bytes = vertex_count * sizeof(float) * 2;
size_t total_idx_bytes = index_count * sizeof(uint16_t);
DeviceBufferDescriptor buffer_desc;
buffer_desc.size = total_vtx_bytes + total_idx_bytes;
buffer_desc.storage_mode = StorageMode::kHostVisible;
auto buffer =
renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
if (!buffer->CopyHostBuffer(
reinterpret_cast<const uint8_t*>(vertices_.data()),
Range{0, total_vtx_bytes}, 0)) {
return {};
}
if (index_count > 0 &&
!buffer->CopyHostBuffer(
reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(indices_.data())),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
return {};
}
return GeometryResult{
.type = GetPrimitiveType(),
.vertex_buffer =
{
.vertex_buffer = {.buffer = buffer,
.range = Range{0, total_vtx_bytes}},
.index_buffer = {.buffer = buffer,
.range =
Range{total_vtx_bytes, total_idx_bytes}},
.vertex_count = index_count > 0 ? index_count : vertex_count,
.index_type =
index_count > 0 ? IndexType::k16bit : IndexType::kNone,
},
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation(),
.prevent_overdraw = false,
};
}
GeometryResult VerticesGeometry::GetPositionColorBuffer(
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) {
using VS = GeometryColorPipeline::VertexShader;
auto index_count = indices_.size();
auto vertex_count = vertices_.size();
std::vector<VS::PerVertexData> vertex_data(vertex_count);
{
for (auto i = 0u; i < vertex_count; i++) {
vertex_data[i] = {
.position = vertices_[i],
.color = colors_[i],
};
}
}
size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
size_t total_idx_bytes = index_count * sizeof(uint16_t);
DeviceBufferDescriptor buffer_desc;
buffer_desc.size = total_vtx_bytes + total_idx_bytes;
buffer_desc.storage_mode = StorageMode::kHostVisible;
auto buffer =
renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
Range{0, total_vtx_bytes}, 0)) {
return {};
}
if (index_count > 0 &&
!buffer->CopyHostBuffer(
reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(indices_.data())),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
return {};
}
return GeometryResult{
.type = GetPrimitiveType(),
.vertex_buffer =
{
.vertex_buffer = {.buffer = buffer,
.range = Range{0, total_vtx_bytes}},
.index_buffer = {.buffer = buffer,
.range =
Range{total_vtx_bytes, total_idx_bytes}},
.vertex_count = index_count > 0 ? index_count : vertex_count,
.index_type =
index_count > 0 ? IndexType::k16bit : IndexType::kNone,
},
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation(),
.prevent_overdraw = false,
};
}
GeometryResult VerticesGeometry::GetPositionUVBuffer(
Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) {
using VS = TexturePipeline::VertexShader;
auto index_count = indices_.size();
auto vertex_count = vertices_.size();
auto size = texture_coverage.size;
auto origin = texture_coverage.origin;
std::vector<VS::PerVertexData> vertex_data(vertex_count);
{
for (auto i = 0u; i < vertex_count; i++) {
auto vertex = vertices_[i];
auto texture_coord = texture_coordinates_[i];
auto uv =
effect_transform * Point((texture_coord.x - origin.x) / size.width,
(texture_coord.y - origin.y) / size.height);
// From experimentation we need to clamp these values to < 1.0 or else
// there can be flickering.
vertex_data[i] = {
.position = vertex,
.texture_coords =
Point(std::clamp(uv.x, 0.0f, 1.0f - kEhCloseEnough),
std::clamp(uv.y, 0.0f, 1.0f - kEhCloseEnough)),
};
}
}
size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
size_t total_idx_bytes = index_count * sizeof(uint16_t);
DeviceBufferDescriptor buffer_desc;
buffer_desc.size = total_vtx_bytes + total_idx_bytes;
buffer_desc.storage_mode = StorageMode::kHostVisible;
auto buffer =
renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);
if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
Range{0, total_vtx_bytes}, 0)) {
return {};
}
if (index_count > 0u &&
!buffer->CopyHostBuffer(
reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(indices_.data())),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
return {};
}
return GeometryResult{
.type = GetPrimitiveType(),
.vertex_buffer =
{
.vertex_buffer = {.buffer = buffer,
.range = Range{0, total_vtx_bytes}},
.index_buffer = {.buffer = buffer,
.range =
Range{total_vtx_bytes, total_idx_bytes}},
.vertex_count = index_count > 0 ? index_count : vertex_count,
.index_type =
index_count > 0 ? IndexType::k16bit : IndexType::kNone,
},
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation(),
.prevent_overdraw = false,
};
}
GeometryVertexType VerticesGeometry::GetVertexType() const {
if (HasVertexColors()) {
return GeometryVertexType::kColor;
}
if (HasTextureCoordinates()) {
return GeometryVertexType::kUV;
}
return GeometryVertexType::kPosition;
}
std::optional<Rect> VerticesGeometry::GetCoverage(
const Matrix& transform) const {
return bounds_.TransformBounds(transform);
}
} // namespace impeller

View File

@ -11,15 +11,61 @@ namespace impeller {
/// @brief A geometry that is created from a vertices object.
class VerticesGeometry : public Geometry {
public:
virtual GeometryResult GetPositionColorBuffer(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) = 0;
enum class VertexMode {
kTriangles,
kTriangleStrip,
kTriangleFan,
};
virtual bool HasVertexColors() const = 0;
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);
virtual bool HasTextureCoordinates() const = 0;
~VerticesGeometry();
virtual std::optional<Rect> GetTextureCoordinateCoverge() const = 0;
GeometryResult GetPositionColorBuffer(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass);
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) override;
// |Geometry|
GeometryResult GetPositionBuffer(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) override;
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
// |Geometry|
GeometryVertexType GetVertexType() const override;
bool HasVertexColors() const;
bool HasTextureCoordinates() const;
std::optional<Rect> GetTextureCoordinateCoverge() const;
private:
void NormalizeIndices();
PrimitiveType GetPrimitiveType() const;
std::vector<Point> vertices_;
std::vector<Color> colors_;
std::vector<Point> texture_coordinates_;
std::vector<uint16_t> indices_;
Rect bounds_;
VerticesGeometry::VertexMode vertex_mode_ =
VerticesGeometry::VertexMode::kTriangles;
};
} // namespace impeller