[Impeller] Implement drawVertices (flutter/engine#33492)

This commit is contained in:
Jonah Williams
2022-05-26 14:45:05 -07:00
committed by GitHub
parent 5d5c396ec0
commit 39760a89fe
18 changed files with 388 additions and 4 deletions

View File

@@ -524,6 +524,8 @@ FILE: ../../../flutter/impeller/entity/contents/text_contents.cc
FILE: ../../../flutter/impeller/entity/contents/text_contents.h
FILE: ../../../flutter/impeller/entity/contents/texture_contents.cc
FILE: ../../../flutter/impeller/entity/contents/texture_contents.h
FILE: ../../../flutter/impeller/entity/contents/vertices_contents.cc
FILE: ../../../flutter/impeller/entity/contents/vertices_contents.h
FILE: ../../../flutter/impeller/entity/entity.cc
FILE: ../../../flutter/impeller/entity/entity.h
FILE: ../../../flutter/impeller/entity/entity_pass.cc
@@ -553,6 +555,8 @@ FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.frag
FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.vert
FILE: ../../../flutter/impeller/entity/shaders/texture_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert
FILE: ../../../flutter/impeller/entity/shaders/vertices.frag
FILE: ../../../flutter/impeller/entity/shaders/vertices.vert
FILE: ../../../flutter/impeller/geometry/color.cc
FILE: ../../../flutter/impeller/geometry/color.h
FILE: ../../../flutter/impeller/geometry/constants.cc
@@ -584,6 +588,8 @@ FILE: ../../../flutter/impeller/geometry/type_traits.cc
FILE: ../../../flutter/impeller/geometry/type_traits.h
FILE: ../../../flutter/impeller/geometry/vector.cc
FILE: ../../../flutter/impeller/geometry/vector.h
FILE: ../../../flutter/impeller/geometry/vertices.cc
FILE: ../../../flutter/impeller/geometry/vertices.h
FILE: ../../../flutter/impeller/image/backends/skia/compressed_image_skia.cc
FILE: ../../../flutter/impeller/image/backends/skia/compressed_image_skia.h
FILE: ../../../flutter/impeller/image/compressed_image.cc

View File

@@ -11,7 +11,9 @@
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/contents/text_contents.h"
#include "impeller/entity/contents/texture_contents.h"
#include "impeller/entity/contents/vertices_contents.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/geometry/vertices.h"
namespace impeller {
@@ -300,4 +302,19 @@ void Canvas::DrawTextFrame(TextFrame text_frame, Point position, Paint paint) {
GetCurrentPass().AddEntity(std::move(entity));
}
void Canvas::DrawVertices(Vertices vertices,
Entity::BlendMode mode,
Paint paint) {
std::shared_ptr<VerticesContents> contents =
std::make_shared<VerticesContents>(std::move(vertices));
contents->SetColor(paint.color);
Entity entity;
entity.SetTransformation(GetCurrentTransformation());
entity.SetStencilDepth(GetStencilDepth());
entity.SetBlendMode(paint.blend_mode);
entity.SetContents(paint.WithFilters(std::move(contents), true));
GetCurrentPass().AddEntity(std::move(entity));
}
} // namespace impeller

View File

@@ -18,6 +18,7 @@
#include "impeller/geometry/path.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/vector.h"
#include "impeller/geometry/vertices.h"
#include "impeller/renderer/sampler_descriptor.h"
#include "impeller/typographer/glyph_atlas.h"
#include "impeller/typographer/text_frame.h"
@@ -89,6 +90,8 @@ class Canvas {
void DrawTextFrame(TextFrame text_frame, Point position, Paint paint);
void DrawVertices(Vertices vertices, Entity::BlendMode mode, Paint paint);
Picture EndRecordingAsPicture();
private:

View File

@@ -14,6 +14,7 @@
#include "impeller/entity/entity.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/geometry/scalar.h"
#include "impeller/geometry/vertices.h"
#include "impeller/typographer/backends/skia/text_frame_skia.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -490,6 +491,53 @@ static Path ToPath(const SkRRect& rrect) {
.TakePath();
}
static Vertices ToVertices(const flutter::DlVertices* vertices) {
std::vector<Point> points;
std::vector<uint16_t> indices;
std::vector<Color> colors;
for (int i = 0; i < vertices->vertex_count(); i++) {
auto point = vertices->vertices()[i];
points.push_back(Point(point.x(), point.y()));
}
for (int i = 0; i < vertices->index_count(); i++) {
auto index = vertices->indices()[i];
indices.push_back(index);
}
auto* dl_colors = vertices->colors();
if (dl_colors != nullptr) {
auto color_length = vertices->index_count() > 0 ? vertices->index_count()
: vertices->vertex_count();
for (int i = 0; i < color_length; i++) {
auto dl_color = dl_colors[i];
colors.push_back({
dl_color.getRedF(),
dl_color.getGreenF(),
dl_color.getBlueF(),
dl_color.getAlphaF(),
});
}
}
VertexMode mode;
switch (vertices->mode()) {
case flutter::DlVertexMode::kTriangles:
mode = VertexMode::kTriangle;
break;
case flutter::DlVertexMode::kTriangleStrip:
mode = VertexMode::kTriangleStrip;
break;
case flutter::DlVertexMode::kTriangleFan:
FML_DLOG(ERROR) << "Unimplemented vertex mode TriangleFan in "
<< __FUNCTION__;
mode = VertexMode::kTriangle;
break;
}
auto bounds = vertices->bounds();
return Vertices(std::move(points), std::move(indices), std::move(colors),
mode, ToRect(bounds));
}
// |flutter::Dispatcher|
void DisplayListDispatcher::clipRRect(const SkRRect& rrect,
SkClipOp clip_op,
@@ -592,9 +640,12 @@ void DisplayListDispatcher::drawSkVertices(const sk_sp<SkVertices> vertices,
// |flutter::Dispatcher|
void DisplayListDispatcher::drawVertices(const flutter::DlVertices* vertices,
flutter::DlBlendMode mode) {
// Needs https://github.com/flutter/flutter/issues/95434
UNIMPLEMENTED;
flutter::DlBlendMode dl_mode) {
if (auto mode = ToBlendMode(dl_mode); mode.has_value()) {
canvas_.DrawVertices(ToVertices(vertices), mode.value(), paint_);
} else {
FML_DLOG(ERROR) << "Unimplemented blend mode in " << __FUNCTION__;
}
}
// |flutter::Dispatcher|

View File

@@ -174,7 +174,7 @@ class DisplayListDispatcher final : public flutter::Dispatcher {
// |flutter::Dispatcher|
void drawVertices(const flutter::DlVertices* vertices,
flutter::DlBlendMode mode) override;
flutter::DlBlendMode dl_mode) override;
// |flutter::Dispatcher|
void drawImage(const sk_sp<flutter::DlImage> image,

View File

@@ -27,6 +27,8 @@ impeller_shaders("entity_shaders") {
"shaders/solid_stroke.vert",
"shaders/texture_fill.frag",
"shaders/texture_fill.vert",
"shaders/vertices.vert",
"shaders/vertices.frag",
]
}
@@ -66,6 +68,8 @@ impeller_component("entity") {
"contents/text_contents.h",
"contents/texture_contents.cc",
"contents/texture_contents.h",
"contents/vertices_contents.cc",
"contents/vertices_contents.h",
"entity.cc",
"entity.h",
"entity_pass.cc",

View File

@@ -168,6 +168,7 @@ ContentContext::ContentContext(std::shared_ptr<Context> context)
CreateDefaultPipeline<SolidStrokePipeline>(*context_);
glyph_atlas_pipelines_[{}] =
CreateDefaultPipeline<GlyphAtlasPipeline>(*context_);
vertices_pipelines_[{}] = CreateDefaultPipeline<VerticesPipeline>(*context_);
// Pipelines that are variants of the base pipelines with custom descriptors.
// TODO(98684): Rework this API to allow fetching the descriptor without

View File

@@ -31,6 +31,8 @@
#include "impeller/entity/solid_stroke.vert.h"
#include "impeller/entity/texture_fill.frag.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/entity/vertices.frag.h"
#include "impeller/entity/vertices.vert.h"
#include "impeller/renderer/formats.h"
namespace impeller {
@@ -54,6 +56,8 @@ using SolidStrokePipeline =
PipelineT<SolidStrokeVertexShader, SolidStrokeFragmentShader>;
using GlyphAtlasPipeline =
PipelineT<GlyphAtlasVertexShader, GlyphAtlasFragmentShader>;
using VerticesPipeline =
PipelineT<VerticesVertexShader, VerticesFragmentShader>;
// Instead of requiring new shaders for clips, the solid fill stages are used
// to redirect writing to the stencil instead of color attachments.
using ClipPipeline = PipelineT<SolidFillVertexShader, SolidFillFragmentShader>;
@@ -145,6 +149,11 @@ class ContentContext {
return GetPipeline(glyph_atlas_pipelines_, opts);
}
std::shared_ptr<Pipeline> GetVerticesPipeline(
ContentContextOptions opts) const {
return GetPipeline(vertices_pipelines_, opts);
}
std::shared_ptr<Context> GetContext() const;
using SubpassCallback =
@@ -178,6 +187,7 @@ class ContentContext {
mutable Variants<SolidStrokePipeline> solid_stroke_pipelines_;
mutable Variants<ClipPipeline> clip_pipelines_;
mutable Variants<GlyphAtlasPipeline> glyph_atlas_pipelines_;
mutable Variants<VerticesPipeline> vertices_pipelines_;
template <class TypedPipeline>
std::shared_ptr<Pipeline> GetPipeline(Variants<TypedPipeline>& container,

View File

@@ -0,0 +1,102 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "vertices_contents.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/vertices.frag.h"
#include "impeller/entity/vertices.vert.h"
#include "impeller/geometry/color.h"
#include "impeller/renderer/formats.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
namespace impeller {
VerticesContents::VerticesContents(Vertices vertices)
: vertices_(std::move(vertices)){};
VerticesContents::~VerticesContents() = default;
std::optional<Rect> VerticesContents::GetCoverage(const Entity& entity) const {
return vertices_.GetTransformedBoundingBox(entity.GetTransformation());
};
void VerticesContents::SetColor(Color color) {
color_ = color.Premultiply();
}
bool VerticesContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
using VS = VerticesVertexShader;
const auto coverage_rect = vertices_.GetBoundingBox();
if (!coverage_rect.has_value()) {
return true;
}
if (coverage_rect->size.IsEmpty()) {
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 (uint i = 0; i < points.size(); i += 1) {
VS::PerVertexData data;
data.point = points[i];
data.vertex_color = color_;
vertex_builder.AppendVertex(data);
}
} else {
for (uint i = 0; i < indices.size(); i += 1) {
VS::PerVertexData data;
data.point = points[indices[i]];
data.vertex_color = color_;
vertex_builder.AppendVertex(data);
}
}
PrimitiveType primitiveType;
switch (mode) {
case VertexMode::kTriangle:
primitiveType = PrimitiveType::kTriangle;
break;
case VertexMode::kTriangleStrip:
primitiveType = PrimitiveType::kTriangleStrip;
break;
}
if (!vertex_builder.HasVertices()) {
return true;
}
auto& host_buffer = pass.GetTransientsBuffer();
VS::FrameInfo frame_info;
frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation();
Command cmd;
cmd.label = "Vertices";
cmd.pipeline =
renderer.GetVerticesPipeline(OptionsFromPassAndEntity(pass, entity));
cmd.stencil_reference = entity.GetStencilDepth();
cmd.primitive_type = primitiveType;
cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer));
VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
pass.AddCommand(std::move(cmd));
return true;
}
} // namespace impeller

View File

@@ -0,0 +1,44 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <functional>
#include <memory>
#include <vector>
#include "flutter/fml/macros.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/geometry/color.h"
#include "impeller/geometry/path.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/vertices.h"
#include "impeller/renderer/sampler_descriptor.h"
namespace impeller {
class VerticesContents final : public Contents {
public:
explicit VerticesContents(Vertices vertices);
~VerticesContents() override;
void SetColor(Color color);
// |Contents|
std::optional<Rect> GetCoverage(const Entity& entity) const override;
// |Contents|
bool Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
public:
Vertices vertices_;
Color color_;
FML_DISALLOW_COPY_AND_ASSIGN(VerticesContents);
};
} // namespace impeller

View File

@@ -10,6 +10,7 @@
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/contents/solid_color_contents.h"
#include "impeller/entity/contents/solid_stroke_contents.h"
#include "impeller/entity/contents/vertices_contents.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/entity_pass.h"
#include "impeller/entity/entity_pass_delegate.h"
@@ -951,5 +952,22 @@ TEST_P(EntityTest, BorderMaskBlurCoverageIsCorrect) {
}
}
TEST_P(EntityTest, DrawVerticesSolidColorTrianglesWithoutIndex) {
std::vector<Point> points = {Point(0, 0), Point(0, 1), Point(1, 0)};
std::vector<uint16_t> indexes;
std::vector<Color> colors = {Color::White(), Color::White(), Color::White()};
Vertices vertices = Vertices(points, indexes, colors, VertexMode::kTriangle,
Rect(0, 0, 4, 4));
std::shared_ptr<VerticesContents> contents =
std::make_shared<VerticesContents>(vertices);
contents->SetColor(Color::White());
Entity e;
e.SetContents(contents);
ASSERT_TRUE(OpenPlaygroundHere(e));
}
} // namespace testing
} // namespace impeller

View File

@@ -0,0 +1,11 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
in vec4 color;
out vec4 frag_color;
void main() {
frag_color = color;
}

View File

@@ -0,0 +1,17 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
uniform FrameInfo {
mat4 mvp;
} frame_info;
in vec2 point;
in vec4 vertex_color;
out vec4 color;
void main() {
gl_Position = frame_info.mvp * vec4(point, 0.0, 1.0);
color = vertex_color;
}

View File

@@ -35,6 +35,8 @@ impeller_component("geometry") {
"type_traits.h",
"vector.cc",
"vector.h",
"vertices.cc",
"vertices.h",
]
}

View File

@@ -1086,5 +1086,20 @@ TEST(GeometryTest, PathPolylineDuplicatesAreRemovedForSameContour) {
ASSERT_EQ(polyline.points[6], Point(0, 100));
}
TEST(GeometryTest, VerticesConstructorAndGetters) {
std::vector<Point> points = {Point(1, 2), Point(2, 3), Point(3, 4)};
std::vector<uint16_t> indices = {0, 1, 2};
std::vector<Color> colors = {Color::White(), Color::White(), Color::White()};
Vertices vertices = Vertices(points, indices, colors, VertexMode::kTriangle,
Rect(0, 0, 4, 4));
ASSERT_EQ(vertices.GetBoundingBox().value(), Rect(0, 0, 4, 4));
ASSERT_EQ(vertices.GetPoints(), points);
ASSERT_EQ(vertices.GetIndices(), indices);
ASSERT_EQ(vertices.GetColors(), colors);
ASSERT_EQ(vertices.GetMode(), VertexMode::kTriangle);
}
} // namespace testing
} // namespace impeller

View File

@@ -10,6 +10,7 @@
#include "impeller/geometry/rect.h"
#include "impeller/geometry/size.h"
#include "impeller/geometry/vector.h"
#include "impeller/geometry/vertices.h"
inline bool NumberNear(double a, double b) {
static const double epsilon = 1e-3;

View File

@@ -0,0 +1,31 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "vertices.h"
namespace impeller {
Vertices::Vertices(std::vector<Point> points,
std::vector<uint16_t> indices,
std::vector<Color> colors,
VertexMode vertex_mode,
Rect bounds)
: points_(std::move(points)),
indices_(std::move(indices)),
colors_(std::move(colors)),
vertex_mode_(vertex_mode),
bounds_(bounds){};
Vertices::~Vertices() = default;
std::optional<Rect> Vertices::GetTransformedBoundingBox(
const Matrix& transform) const {
auto bounds = GetBoundingBox();
if (!bounds.has_value()) {
return std::nullopt;
}
return bounds->TransformBounds(transform);
};
} // namespace impeller

View File

@@ -0,0 +1,51 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <optional>
#include <vector>
#include "impeller/geometry/color.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/rect.h"
namespace impeller {
enum class VertexMode {
kTriangle,
kTriangleStrip,
};
class Vertices {
public:
Vertices(std::vector<Point> points,
std::vector<uint16_t> indices,
std::vector<Color> colors,
VertexMode vertex_mode,
Rect bounds);
~Vertices();
std::optional<Rect> GetBoundingBox() const { return bounds_; };
std::optional<Rect> GetTransformedBoundingBox(const Matrix& transform) const;
const std::vector<Point>& GetPoints() const { return points_; }
const std::vector<uint16_t>& GetIndices() const { return indices_; }
const std::vector<Color>& GetColors() const { return colors_; }
VertexMode GetMode() const { return vertex_mode_; }
private:
std::vector<Point> points_;
std::vector<uint16_t> indices_;
std::vector<Color> colors_;
VertexMode vertex_mode_;
Rect bounds_;
};
} // namespace impeller