Add more path builder ops.

This commit is contained in:
Chinmay Garde 2021-08-20 04:05:59 -07:00 committed by Dan Field
parent 7f23e748ab
commit ce8a7dfd7b
12 changed files with 144 additions and 63 deletions

View File

@ -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() {

View File

@ -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",
]
}

View File

@ -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;
}

View File

@ -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

View File

@ -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 =

View File

@ -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<VS::PerVertexData> builder;
VertexBufferBuilder<VS::PerVertexData> 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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -54,7 +54,7 @@ class Path {
bool UpdateCubicComponentAtIndex(size_t index, CubicPathComponent& cubic);
std::vector<Point> SubdivideAdaptively(
const SmoothingApproximation& approximation) const;
const SmoothingApproximation& approximation = {}) const;
Rect GetBoundingBox() const;

View File

@ -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

View File

@ -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;

View File

@ -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<BoxFadeVertexShader, BoxFadeFragmentShader>;