From ff37fcdf5a71ca4c659696a9049f42fd4210bd82 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 31 Aug 2023 16:58:04 -0700 Subject: [PATCH] [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. --- .../impeller/display_list/dl_dispatcher.cc | 3 +- .../display_list/dl_vertices_geometry.cc | 353 ++---------------- .../display_list/dl_vertices_geometry.h | 58 +-- .../entity/geometry/vertices_geometry.cc | 296 +++++++++++++++ .../entity/geometry/vertices_geometry.h | 58 ++- 5 files changed, 384 insertions(+), 384 deletions(-) diff --git a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc index 44d93adb4be..5e420546585 100644 --- a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc +++ b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc @@ -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| diff --git a/engine/src/flutter/impeller/display_list/dl_vertices_geometry.cc b/engine/src/flutter/impeller/display_list/dl_vertices_geometry.cc index 52c70c74757..66ad5aac91d 100644 --- a/engine/src/flutter/impeller/display_list/dl_vertices_geometry.cc +++ b/engine/src/flutter/impeller/display_list/dl_vertices_geometry.cc @@ -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 fromFanIndices( - const flutter::DlVertices* vertices) { - FML_DCHECK(vertices->vertex_count() >= 3); - FML_DCHECK(vertices->mode() == flutter::DlVertexMode::kTriangleFan); - - std::vector 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 DlVerticesGeometry::MakeVertices( - const flutter::DlVertices* vertices) { - return std::make_shared(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 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(dl_vertices), - Range{0, total_vtx_bytes}, 0)) { - return {}; - } - if (!buffer->CopyHostBuffer( - reinterpret_cast(const_cast(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 MakeVertices( + const flutter::DlVertices* vertices) { + auto bounds = ToRect(vertices->bounds()); + auto mode = ToVertexMode(vertices->mode()); + std::vector 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 indices(vertices->index_count()); + for (auto i = 0; i < vertices->index_count(); i++) { + indices[i] = vertices->indices()[i]; + } - std::vector 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 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(vertex_data.data()), - Range{0, total_vtx_bytes}, 0)) { - return {}; - } - if (!buffer->CopyHostBuffer( - reinterpret_cast(const_cast(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 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 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(vertex_data.data()), - Range{0, total_vtx_bytes}, 0)) { - return {}; - } - if (!buffer->CopyHostBuffer( - reinterpret_cast(const_cast(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 DlVerticesGeometry::GetCoverage( - const Matrix& transform) const { - return ToRect(vertices_->bounds()).TransformBounds(transform); + return std::make_shared( + positions, indices, texture_coordinates, colors, bounds, mode); } } // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/dl_vertices_geometry.h b/engine/src/flutter/impeller/display_list/dl_vertices_geometry.h index 538b65a6d50..466ed932a7c 100644 --- a/engine/src/flutter/impeller/display_list/dl_vertices_geometry.h +++ b/engine/src/flutter/impeller/display_list/dl_vertices_geometry.h @@ -4,67 +4,13 @@ #pragma once -#include -#include - #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 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 GetCoverage(const Matrix& transform) const override; - - // |Geometry| - GeometryVertexType GetVertexType() const override; - - // |VerticesGeometry| - bool HasVertexColors() const override; - - // |VerticesGeometry| - bool HasTextureCoordinates() const override; - - // |VerticesGeometry| - std::optional GetTextureCoordinateCoverge() const override; - - private: - void NormalizeIndices(); - - const flutter::DlVertices* vertices_; - std::vector normalized_indices_; - - FML_DISALLOW_COPY_AND_ASSIGN(DlVerticesGeometry); -}; +std::shared_ptr MakeVertices( + const flutter::DlVertices* vertices); } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry/vertices_geometry.cc b/engine/src/flutter/impeller/entity/geometry/vertices_geometry.cc index 2d275928535..8c1a0c0d542 100644 --- a/engine/src/flutter/impeller/entity/geometry/vertices_geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry/vertices_geometry.cc @@ -4,8 +4,304 @@ #include "impeller/entity/geometry/vertices_geometry.h" +#include + +#include +#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 fromFanIndices( + const std::vector& vertices, + const std::vector& indices) { + std::vector 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 vertices, + std::vector indices, + std::vector texture_coordinates, + std::vector 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 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(vertices_.data()), + Range{0, total_vtx_bytes}, 0)) { + return {}; + } + if (index_count > 0 && + !buffer->CopyHostBuffer( + reinterpret_cast(const_cast(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 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(vertex_data.data()), + Range{0, total_vtx_bytes}, 0)) { + return {}; + } + if (index_count > 0 && + !buffer->CopyHostBuffer( + reinterpret_cast(const_cast(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 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(vertex_data.data()), + Range{0, total_vtx_bytes}, 0)) { + return {}; + } + if (index_count > 0u && + !buffer->CopyHostBuffer( + reinterpret_cast(const_cast(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 VerticesGeometry::GetCoverage( + const Matrix& transform) const { + return bounds_.TransformBounds(transform); +} } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry/vertices_geometry.h b/engine/src/flutter/impeller/entity/geometry/vertices_geometry.h index 09a6b377659..93ab83679b1 100644 --- a/engine/src/flutter/impeller/entity/geometry/vertices_geometry.h +++ b/engine/src/flutter/impeller/entity/geometry/vertices_geometry.h @@ -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 vertices, + std::vector indices, + std::vector texture_coordinates, + std::vector colors, + Rect bounds, + VerticesGeometry::VertexMode vertex_mode); - virtual bool HasTextureCoordinates() const = 0; + ~VerticesGeometry(); - virtual std::optional 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 GetCoverage(const Matrix& transform) const override; + + // |Geometry| + GeometryVertexType GetVertexType() const override; + + bool HasVertexColors() const; + + bool HasTextureCoordinates() const; + + std::optional GetTextureCoordinateCoverge() const; + + private: + void NormalizeIndices(); + + PrimitiveType GetPrimitiveType() const; + + std::vector vertices_; + std::vector colors_; + std::vector texture_coordinates_; + std::vector indices_; + Rect bounds_; + VerticesGeometry::VertexMode vertex_mode_ = + VerticesGeometry::VertexMode::kTriangles; }; } // namespace impeller