mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add more path builder ops.
This commit is contained in:
parent
7f23e748ab
commit
ce8a7dfd7b
@ -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() {
|
||||
|
||||
@ -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",
|
||||
]
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user