From ce8a7dfd7be9741fea0b2bd1862561665425139d Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Fri, 20 Aug 2021 04:05:59 -0700 Subject: [PATCH] Add more path builder ops. --- engine/src/flutter/impeller/aiks/canvas.cc | 13 ++- .../src/flutter/impeller/compositor/BUILD.gn | 3 +- .../impeller/compositor/render_pass.mm | 3 +- .../impeller/entity/entity_renderer.mm | 22 ++++- .../impeller/entity/entity_renderer_impl.h | 12 ++- .../impeller/entity/entity_renderer_impl.mm | 46 ++++++++-- engine/src/flutter/impeller/entity/path.vert | 4 + .../flutter/impeller/entity/solid_fill.frag | 4 +- engine/src/flutter/impeller/geometry/path.h | 2 +- .../flutter/impeller/geometry/path_builder.cc | 92 ++++++++++--------- .../flutter/impeller/geometry/path_builder.h | 4 + .../primitives/primitives_unittests.mm | 2 +- 12 files changed, 144 insertions(+), 63 deletions(-) diff --git a/engine/src/flutter/impeller/aiks/canvas.cc b/engine/src/flutter/impeller/aiks/canvas.cc index 8da1754be21..eef923e1a61 100644 --- a/engine/src/flutter/impeller/aiks/canvas.cc +++ b/engine/src/flutter/impeller/aiks/canvas.cc @@ -54,7 +54,12 @@ size_t Canvas::GetSaveCount() const { return xformation_stack_.size(); } +void AssertionBreak() {} + void Canvas::DrawPath(Path path, Paint paint) { + if (path.GetBoundingBox().IsZero()) { + AssertionBreak(); + } Entity entity; entity.SetTransformation(GetCurrentTransformation()); entity.SetPath(std::move(path)); @@ -75,8 +80,12 @@ void Canvas::ClipPath(Path path) { void Canvas::DrawShadow(Path path, Color color, Scalar elevation) {} void Canvas::DrawPicture(const Picture& picture) { - std::copy(std::begin(picture.entities), std::end(picture.entities), - std::back_inserter(ops_)); + for (const auto& entity : picture.entities) { + auto new_entity = entity; + new_entity.SetTransformation(GetCurrentTransformation() * + new_entity.GetTransformation()); + ops_.emplace_back(std::move(new_entity)); + } } Picture Canvas::EndRecordingAsPicture() { diff --git a/engine/src/flutter/impeller/compositor/BUILD.gn b/engine/src/flutter/impeller/compositor/BUILD.gn index 62ee7c9040d..c29c5b976c3 100644 --- a/engine/src/flutter/impeller/compositor/BUILD.gn +++ b/engine/src/flutter/impeller/compositor/BUILD.gn @@ -78,6 +78,8 @@ impeller_component("compositor") { "../image", ] + deps = [ "//third_party/libtess2" ] + frameworks = [ "Metal.framework" ] } @@ -93,6 +95,5 @@ source_set("compositor_unittests") { ":compositor", "../playground", "//flutter/testing:testing_lib", - "//third_party/libtess2", ] } diff --git a/engine/src/flutter/impeller/compositor/render_pass.mm b/engine/src/flutter/impeller/compositor/render_pass.mm index 458f5277688..bcbbb36fbc0 100644 --- a/engine/src/flutter/impeller/compositor/render_pass.mm +++ b/engine/src/flutter/impeller/compositor/render_pass.mm @@ -344,6 +344,7 @@ bool RenderPass::EncodeCommands(Allocator& allocator, fml::closure pop_debug_marker = [pass]() { [pass popDebugGroup]; }; for (const auto& command : commands_) { if (command.index_count == 0u) { + FML_DLOG(ERROR) << "Zero index count in render pass command."; continue; } @@ -360,7 +361,7 @@ bool RenderPass::EncodeCommands(Allocator& allocator, [pass setFrontFacingWinding:command.winding == WindingOrder::kClockwise ? MTLWindingClockwise : MTLWindingCounterClockwise]; - [pass setCullMode:MTLCullModeBack]; + [pass setCullMode:MTLCullModeNone]; if (!bind_stage_resources(command.vertex_bindings, ShaderStage::kVertex)) { return false; } diff --git a/engine/src/flutter/impeller/entity/entity_renderer.mm b/engine/src/flutter/impeller/entity/entity_renderer.mm index 87df107395a..06b0a439caf 100644 --- a/engine/src/flutter/impeller/entity/entity_renderer.mm +++ b/engine/src/flutter/impeller/entity/entity_renderer.mm @@ -30,13 +30,29 @@ bool EntityRenderer::RenderEntities(const Surface& surface, return false; } + size_t success = 0u; + size_t failure = 0u; + size_t skipped = 0u; + for (const auto& entity : entities) { - if (!renderer_->RenderEntity(surface, onscreen_pass, entity)) { - return false; + auto result = renderer_->RenderEntity(surface, onscreen_pass, entity); + switch (result) { + case EntityRendererImpl::RenderResult::kSuccess: + success++; + break; + case EntityRendererImpl::RenderResult::kFailure: + failure++; + break; + case EntityRendererImpl::RenderResult::kSkipped: + skipped++; + break; } } - return true; + FML_LOG(ERROR) << "Success " << success << " failure " << failure + << " skipped " << skipped << " total " << entities.size(); + + return failure == 0; } } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/entity_renderer_impl.h b/engine/src/flutter/impeller/entity/entity_renderer_impl.h index c63d063e021..1bf525227d7 100644 --- a/engine/src/flutter/impeller/entity/entity_renderer_impl.h +++ b/engine/src/flutter/impeller/entity/entity_renderer_impl.h @@ -29,9 +29,15 @@ class EntityRendererImpl { bool IsValid() const; - [[nodiscard]] bool RenderEntity(const Surface& surface, - RenderPass& onscreen_pass, - const Entity& entities); + enum class RenderResult { + kSkipped, + kSuccess, + kFailure, + }; + + [[nodiscard]] RenderResult RenderEntity(const Surface& surface, + RenderPass& onscreen_pass, + const Entity& entities); private: using SolidFillPipeline = diff --git a/engine/src/flutter/impeller/entity/entity_renderer_impl.mm b/engine/src/flutter/impeller/entity/entity_renderer_impl.mm index 4d763a7d122..531fbfc15fc 100644 --- a/engine/src/flutter/impeller/entity/entity_renderer_impl.mm +++ b/engine/src/flutter/impeller/entity/entity_renderer_impl.mm @@ -3,6 +3,9 @@ // found in the LICENSE file. #include "impeller/entity/entity_renderer_impl.h" + +#include "flutter/fml/trace_event.h" +#include "impeller/compositor/tessellator.h" #include "impeller/compositor/vertex_buffer_builder.h" namespace impeller { @@ -24,32 +27,59 @@ bool EntityRendererImpl::IsValid() const { return is_valid_; } -bool EntityRendererImpl::RenderEntity(const Surface& surface, - RenderPass& pass, - const Entity& entity) { +EntityRendererImpl::RenderResult EntityRendererImpl::RenderEntity( + const Surface& surface, + RenderPass& pass, + const Entity& entity) { if (!entity.HasRenderableContents()) { - return true; + if (entity.GetPath().GetBoundingBox().IsZero()) { + FML_LOG(ERROR) << "Skipped because bounds box zero."; + } + return RenderResult::kSkipped; } - if (entity.HasContents()) { + if (entity.HasContents() && !entity.IsClip()) { using VS = SolidFillPipeline::VertexShader; Command cmd; + cmd.label = "SolidFill"; cmd.pipeline = solid_fill_pipeline_->WaitAndGet(); if (cmd.pipeline == nullptr) { - return false; + return RenderResult::kFailure; } - VertexBufferBuilder builder; + VertexBufferBuilder vtx_builder; + { + TRACE_EVENT0("flutter", "Tesselate"); + auto tesselation_result = Tessellator{}.Tessellate( + entity.GetPath().SubdivideAdaptively(), [&vtx_builder](auto point) { + VS::PerVertexData vtx; + vtx.vertices = point; + vtx_builder.AppendVertex(vtx); + }); + if (!tesselation_result) { + return RenderResult::kFailure; + } + } + + cmd.BindVertices( + vtx_builder.CreateVertexBuffer(*context_->GetPermanentsAllocator())); VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(surface.GetSize()) * entity.GetTransformation(); + frame_info.color = entity.GetBackgroundColor(); VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + cmd.primitive_type = PrimitiveType::kTriangle; + + if (!pass.RecordCommand(std::move(cmd))) { + return RenderResult::kFailure; + } } - return true; + return RenderResult::kSuccess; } } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/path.vert b/engine/src/flutter/impeller/entity/path.vert index ba38d88acd1..9d29d7eeee6 100644 --- a/engine/src/flutter/impeller/entity/path.vert +++ b/engine/src/flutter/impeller/entity/path.vert @@ -4,10 +4,14 @@ uniform FrameInfo { mat4 mvp; + vec4 color; } frame_info; in vec2 vertices; +out vec4 color; + void main() { gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0); + color = frame_info.color; } diff --git a/engine/src/flutter/impeller/entity/solid_fill.frag b/engine/src/flutter/impeller/entity/solid_fill.frag index ba7a8555c21..0263c965f29 100644 --- a/engine/src/flutter/impeller/entity/solid_fill.frag +++ b/engine/src/flutter/impeller/entity/solid_fill.frag @@ -2,8 +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; + out vec4 frag_color; void main() { - frag_color = vec4(1.0, 1.0, 1.0, 1.0); + frag_color = color; } diff --git a/engine/src/flutter/impeller/geometry/path.h b/engine/src/flutter/impeller/geometry/path.h index 18c7b4a602d..4952ecab16d 100644 --- a/engine/src/flutter/impeller/geometry/path.h +++ b/engine/src/flutter/impeller/geometry/path.h @@ -54,7 +54,7 @@ class Path { bool UpdateCubicComponentAtIndex(size_t index, CubicPathComponent& cubic); std::vector SubdivideAdaptively( - const SmoothingApproximation& approximation) const; + const SmoothingApproximation& approximation = {}) const; Rect GetBoundingBox() const; diff --git a/engine/src/flutter/impeller/geometry/path_builder.cc b/engine/src/flutter/impeller/geometry/path_builder.cc index c24c4b83de0..835e15ad349 100644 --- a/engine/src/flutter/impeller/geometry/path_builder.cc +++ b/engine/src/flutter/impeller/geometry/path_builder.cc @@ -159,48 +159,7 @@ PathBuilder& PathBuilder::AddRect(Rect rect) { } PathBuilder& PathBuilder::AddCircle(const Point& c, Scalar r) { - current_ = c + Point{0.0, r}; - - // m for magic - const auto m = kArcApproximationMagic * r; - - //---------------------------------------------------------------------------- - /// Top right arc. - /// - prototype_.AddCubicComponent({c.x, c.y - r}, // p1 - {c.x + m, c.y - r}, // cp1 - {c.x + r, c.y - m}, // cp2 - {c.x + r, c.y} // p2 - ); - - //---------------------------------------------------------------------------- - /// Bottom right arc. - /// - prototype_.AddCubicComponent({c.x + r, c.y}, // p1 - {c.x + r, c.y + m}, // cp1 - {c.x + m, c.y + r}, // cp2 - {c.x, c.y + r} // p2 - ); - - //---------------------------------------------------------------------------- - /// Bottom left arc. - /// - prototype_.AddCubicComponent({c.x, c.y + r}, // p1 - {c.x - m, c.y + r}, // cp1 - {c.x - r, c.y + m}, // cp2 - {c.x - r, c.y} // p2 - ); - - //---------------------------------------------------------------------------- - /// Top left arc. - /// - prototype_.AddCubicComponent({c.x - r, c.y}, // p1 - {c.x - r, c.y - m}, // cp1 - {c.x - m, c.y - r}, // cp2 - {c.x, c.y - r} // p2 - ); - - return *this; + return AddOval(Rect{c.x - r, c.y - r, 2.0f * r, 2.0f * r}); } PathBuilder& PathBuilder::AddRoundedRect(Rect rect, Scalar radius) { @@ -294,4 +253,53 @@ PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) { return *this; } +PathBuilder& PathBuilder::AddOval(const Rect& container) { + const Point r = {container.size.width * 0.5f, container.size.height * 0.5f}; + const Point c = {container.origin.x + (container.size.width * 0.5f), + container.origin.y + (container.size.height * 0.5f)}; + const Point m = {kArcApproximationMagic * r.x, kArcApproximationMagic * r.y}; + + //---------------------------------------------------------------------------- + /// Top right arc. + /// + prototype_.AddCubicComponent({c.x, c.y - r.y}, // p1 + {c.x + m.x, c.y - r.y}, // cp1 + {c.x + r.x, c.y - m.y}, // cp2 + {c.x + r.x, c.y} // p2 + ); + + //---------------------------------------------------------------------------- + /// Bottom right arc. + /// + prototype_.AddCubicComponent({c.x + r.x, c.y}, // p1 + {c.x + r.x, c.y + m.y}, // cp1 + {c.x + m.x, c.y + r.y}, // cp2 + {c.x, c.y + r.y} // p2 + ); + + //---------------------------------------------------------------------------- + /// Bottom left arc. + /// + prototype_.AddCubicComponent({c.x, c.y + r.y}, // p1 + {c.x - m.x, c.y + r.y}, // cp1 + {c.x - r.x, c.y + m.y}, // cp2 + {c.x - r.x, c.y} // p2 + ); + + //---------------------------------------------------------------------------- + /// Top left arc. + /// + prototype_.AddCubicComponent({c.x - r.x, c.y}, // p1 + {c.x - r.x, c.y - m.y}, // cp1 + {c.x - m.x, c.y - r.y}, // cp2 + {c.x, c.y - r.y} // p2 + ); + + return *this; +} + +const Path& PathBuilder::GetCurrentPath() const { + return prototype_; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/geometry/path_builder.h b/engine/src/flutter/impeller/geometry/path_builder.h index a058e9250d0..36e391fa81f 100644 --- a/engine/src/flutter/impeller/geometry/path_builder.h +++ b/engine/src/flutter/impeller/geometry/path_builder.h @@ -19,6 +19,8 @@ class PathBuilder { Path CreatePath() const; + const Path& GetCurrentPath() const; + PathBuilder& MoveTo(Point point, bool relative = false); PathBuilder& Close(); @@ -50,6 +52,8 @@ class PathBuilder { PathBuilder& AddCircle(const Point& center, Scalar radius); + PathBuilder& AddOval(const Rect& rect); + struct RoundingRadii { Scalar topLeft = 0.0; Scalar bottomLeft = 0.0; diff --git a/engine/src/flutter/impeller/primitives/primitives_unittests.mm b/engine/src/flutter/impeller/primitives/primitives_unittests.mm index 2e4b359296d..d8dfee10c2c 100644 --- a/engine/src/flutter/impeller/primitives/primitives_unittests.mm +++ b/engine/src/flutter/impeller/primitives/primitives_unittests.mm @@ -252,7 +252,7 @@ TEST_F(PrimitivesTest, CanRenderToTexture) { } TEST_F(PrimitivesTest, CanRenderPath) { - auto path = PathBuilder{}.AddRoundedRect({10, 10, 200, 200}, 50).CreatePath(); + auto path = PathBuilder{}.AddCircle({550, 550}, 500).CreatePath(); ASSERT_FALSE(path.GetBoundingBox().IsZero()); using BoxPipeline = PipelineT;