[Impeller] Copy user indices directly into buffer for DrawVertices (flutter/engine#34792)

This commit is contained in:
Brandon DeRosier 2022-07-20 14:04:04 -07:00 committed by GitHub
parent 24e07cd37e
commit b14c460a7a
11 changed files with 149 additions and 61 deletions

View File

@ -108,7 +108,7 @@ class DlVertices {
///
/// Vertices are always required. Optional texture coordinates
/// and optional colors are reserved depending on the |Flags|.
/// Optional indices will be reserved iff the index_count is
/// Optional indices will be reserved if the index_count is
/// positive (>0).
///
/// The caller must provide all data that is promised by the

View File

@ -306,11 +306,12 @@ void Canvas::DrawTextFrame(TextFrame text_frame, Point position, Paint paint) {
}
void Canvas::DrawVertices(Vertices vertices,
Entity::BlendMode mode,
Entity::BlendMode blend_mode,
Paint paint) {
std::shared_ptr<VerticesContents> contents =
std::make_shared<VerticesContents>(std::move(vertices));
contents->SetColor(paint.color);
contents->SetBlendMode(blend_mode);
Entity entity;
entity.SetTransformation(GetCurrentTransformation());
entity.SetStencilDepth(GetStencilDepth());

View File

@ -93,7 +93,9 @@ class Canvas {
void DrawTextFrame(TextFrame text_frame, Point position, Paint paint);
void DrawVertices(Vertices vertices, Entity::BlendMode mode, Paint paint);
void DrawVertices(Vertices vertices,
Entity::BlendMode blend_mode,
Paint paint);
Picture EndRecordingAsPicture();

View File

@ -12,6 +12,7 @@
#include "impeller/renderer/formats.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer.h"
namespace impeller {
@ -28,10 +29,27 @@ void VerticesContents::SetColor(Color color) {
color_ = color.Premultiply();
}
void VerticesContents::SetBlendMode(Entity::BlendMode blend_mode) {
blend_mode_ = blend_mode;
}
static PrimitiveType GetPrimitiveType(const Vertices& vertices) {
switch (vertices.GetMode()) {
case VertexMode::kTriangle:
return PrimitiveType::kTriangle;
case VertexMode::kTriangleStrip:
return PrimitiveType::kTriangleStrip;
}
}
bool VerticesContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
using VS = VerticesVertexShader;
if (!vertices_.IsValid()) {
return true;
}
using VS = VerticesPipeline::VertexShader;
const auto coverage_rect = vertices_.GetBoundingBox();
@ -43,42 +61,36 @@ bool VerticesContents::Render(const ContentContext& renderer,
return true;
}
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
std::vector<Point> points = vertices_.GetPoints();
std::vector<uint16_t> indices = vertices_.GetIndices();
// TODO: colors are currently unused, must be blended with
// paint color based on provided blend mode.
std::vector<Color> colors = vertices_.GetColors();
VertexMode mode = vertices_.GetMode();
if (indices.size() == 0) {
for (size_t i = 0; i < points.size(); i += 1) {
VS::PerVertexData data;
data.point = points[i];
data.vertex_color = color_;
vertex_builder.AppendVertex(data);
}
} else {
for (size_t i = 0; i < indices.size(); i += 1) {
VS::PerVertexData data;
data.point = points[indices[i]];
data.vertex_color = color_;
vertex_builder.AppendVertex(data);
std::vector<VS::PerVertexData> vertex_data;
{
const auto& positions = vertices_.GetPositions();
const auto& colors = vertices_.GetColors();
for (size_t i = 0; i < positions.size(); i++) {
vertex_data.push_back(VS::PerVertexData{
.position = positions[i],
// TODO(108047): Blend these colors together when available. Use
// colors[i] as the destination and color_ as the
// source. Always use color_ when vertex colors are not
// supplied.
.color = i < colors.size() ? colors[i] : color_,
});
}
}
PrimitiveType primitiveType;
switch (mode) {
case VertexMode::kTriangle:
primitiveType = PrimitiveType::kTriangle;
break;
case VertexMode::kTriangleStrip:
primitiveType = PrimitiveType::kTriangleStrip;
break;
}
size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
size_t total_idx_bytes = vertices_.GetIndices().size() * sizeof(uint16_t);
if (!vertex_builder.HasVertices()) {
return true;
auto buffer = renderer.GetContext()->GetTransientsAllocator()->CreateBuffer(
StorageMode::kHostVisible, total_vtx_bytes + total_idx_bytes);
if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
Range{0, total_vtx_bytes}, 0)) {
return false;
}
if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(
vertices_.GetIndices().data())),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
return false;
}
auto& host_buffer = pass.GetTransientsBuffer();
@ -91,8 +103,14 @@ bool VerticesContents::Render(const ContentContext& renderer,
cmd.pipeline =
renderer.GetVerticesPipeline(OptionsFromPassAndEntity(pass, entity));
cmd.stencil_reference = entity.GetStencilDepth();
cmd.primitive_type = primitiveType;
cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer));
cmd.primitive_type = GetPrimitiveType(vertices_);
cmd.BindVertices({
.vertex_buffer = {.buffer = buffer, .range = Range{0, total_vtx_bytes}},
.index_buffer = {.buffer = buffer,
.range = Range{total_vtx_bytes, total_idx_bytes}},
.index_count = vertices_.GetIndices().size(),
.index_type = IndexType::k16bit,
});
VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
pass.AddCommand(std::move(cmd));

View File

@ -10,6 +10,7 @@
#include "flutter/fml/macros.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/entity/entity.h"
#include "impeller/geometry/color.h"
#include "impeller/geometry/path.h"
#include "impeller/geometry/point.h"
@ -26,6 +27,8 @@ class VerticesContents final : public Contents {
void SetColor(Color color);
void SetBlendMode(Entity::BlendMode blend_mode);
// |Contents|
std::optional<Rect> GetCoverage(const Entity& entity) const override;
@ -37,6 +40,7 @@ class VerticesContents final : public Contents {
public:
Vertices vertices_;
Color color_;
Entity::BlendMode blend_mode_ = Entity::BlendMode::kSource;
FML_DISALLOW_COPY_AND_ASSIGN(VerticesContents);
};

View File

@ -1055,14 +1055,31 @@ TEST_P(EntityTest, BorderMaskBlurCoverageIsCorrect) {
}
}
TEST_P(EntityTest, DrawVerticesSolidColorTrianglesWithoutIndex) {
std::vector<Point> points = {Point(100, 300), Point(200, 100),
Point(300, 300)};
std::vector<uint16_t> indexes;
TEST_P(EntityTest, DrawVerticesSolidColorTrianglesWithoutIndices) {
std::vector<Point> positions = {Point(100, 300), Point(200, 100),
Point(300, 300)};
std::vector<Color> colors = {Color::White(), Color::White(), Color::White()};
Vertices vertices = Vertices(points, indexes, colors, VertexMode::kTriangle,
Rect(100, 100, 300, 300));
Vertices vertices = Vertices(positions, {} /* indices */, colors,
VertexMode::kTriangle, Rect(100, 100, 300, 300));
std::shared_ptr<VerticesContents> contents =
std::make_shared<VerticesContents>(vertices);
contents->SetColor(Color::White());
Entity e;
e.SetTransformation(Matrix::MakeScale(GetContentScale()));
e.SetContents(contents);
ASSERT_TRUE(OpenPlaygroundHere(e));
}
TEST_P(EntityTest, DrawVerticesSolidColorTrianglesWithIndices) {
std::vector<Point> positions = {Point(100, 300), Point(200, 100),
Point(300, 300), Point(200, 500)};
std::vector<uint16_t> indices = {0, 1, 2, 0, 2, 3};
Vertices vertices = Vertices(positions, indices, {} /* colors */,
VertexMode::kTriangle, Rect(100, 100, 300, 300));
std::shared_ptr<VerticesContents> contents =
std::make_shared<VerticesContents>(vertices);

View File

@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
in vec4 color;
in vec4 v_color;
out vec4 frag_color;
void main() {
frag_color = color;
frag_color = v_color;
}

View File

@ -6,12 +6,12 @@ uniform FrameInfo {
mat4 mvp;
} frame_info;
in vec2 point;
in vec4 vertex_color;
in vec2 position;
in vec4 color;
out vec4 color;
out vec4 v_color;
void main() {
gl_Position = frame_info.mvp * vec4(point, 0.0, 1.0);
color = vertex_color;
gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0);
v_color = color;
}

View File

@ -1233,7 +1233,7 @@ TEST(GeometryTest, VerticesConstructorAndGetters) {
Rect(0, 0, 4, 4));
ASSERT_EQ(vertices.GetBoundingBox().value(), Rect(0, 0, 4, 4));
ASSERT_EQ(vertices.GetPoints(), points);
ASSERT_EQ(vertices.GetPositions(), points);
ASSERT_EQ(vertices.GetIndices(), indices);
ASSERT_EQ(vertices.GetColors(), colors);
ASSERT_EQ(vertices.GetMode(), VertexMode::kTriangle);

View File

@ -11,14 +11,31 @@ Vertices::Vertices(std::vector<Point> points,
std::vector<Color> colors,
VertexMode vertex_mode,
Rect bounds)
: points_(std::move(points)),
: positions_(std::move(points)),
indices_(std::move(indices)),
colors_(std::move(colors)),
vertex_mode_(vertex_mode),
bounds_(bounds){};
bounds_(bounds) {
NormalizeIndices();
}
Vertices::~Vertices() = default;
bool Vertices::IsValid() const {
size_t points_size = positions_.size();
size_t colors_size = colors_.size();
if (colors_size > 0 && colors_size != points_size) {
return false;
}
return true;
}
std::optional<Rect> Vertices::GetBoundingBox() const {
return bounds_;
};
std::optional<Rect> Vertices::GetTransformedBoundingBox(
const Matrix& transform) const {
auto bounds = GetBoundingBox();
@ -28,4 +45,29 @@ std::optional<Rect> Vertices::GetTransformedBoundingBox(
return bounds->TransformBounds(transform);
};
const std::vector<Point>& Vertices::GetPositions() const {
return positions_;
}
const std::vector<uint16_t>& Vertices::GetIndices() const {
return indices_;
}
const std::vector<Color>& Vertices::GetColors() const {
return colors_;
}
VertexMode Vertices::GetMode() const {
return vertex_mode_;
}
void Vertices::NormalizeIndices() {
if (indices_.size() != 0 || positions_.size() == 0) {
return;
}
for (size_t i = 0; i < positions_.size(); i++) {
indices_.push_back(i);
}
}
} // namespace impeller

View File

@ -20,7 +20,7 @@ enum class VertexMode {
class Vertices {
public:
Vertices(std::vector<Point> points,
Vertices(std::vector<Point> positions,
std::vector<uint16_t> indices,
std::vector<Color> colors,
VertexMode vertex_mode,
@ -28,24 +28,28 @@ class Vertices {
~Vertices();
std::optional<Rect> GetBoundingBox() const { return bounds_; };
bool IsValid() const;
std::optional<Rect> GetBoundingBox() const;
std::optional<Rect> GetTransformedBoundingBox(const Matrix& transform) const;
const std::vector<Point>& GetPoints() const { return points_; }
const std::vector<Point>& GetPositions() const;
const std::vector<uint16_t>& GetIndices() const { return indices_; }
const std::vector<uint16_t>& GetIndices() const;
const std::vector<Color>& GetColors() const { return colors_; }
const std::vector<Color>& GetColors() const;
VertexMode GetMode() const { return vertex_mode_; }
VertexMode GetMode() const;
private:
std::vector<Point> points_;
std::vector<Point> positions_;
std::vector<uint16_t> indices_;
std::vector<Color> colors_;
VertexMode vertex_mode_;
Rect bounds_;
void NormalizeIndices();
};
} // namespace impeller