mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Rework canvas passes in prep for subpasses.
This commit is contained in:
parent
2eb6372d9d
commit
0a855c21f7
@ -103,6 +103,30 @@ TEST_F(AiksTest, CanRenderClips) {
|
||||
canvas.ClipPath(
|
||||
PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 500, 500)).CreatePath());
|
||||
canvas.DrawPath(PathBuilder{}.AddCircle({500, 500}, 250).CreatePath(), paint);
|
||||
// ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_F(AiksTest, CanRenderGroupOpacity) {
|
||||
Canvas canvas;
|
||||
|
||||
Paint red;
|
||||
red.color = Color::Red(); //.WithAlpha(0.5);
|
||||
Paint green;
|
||||
green.color = Color::Green(); //.WithAlpha(0.5);
|
||||
Paint blue;
|
||||
blue.color = Color::Blue(); //.WithAlpha(0.5);
|
||||
|
||||
Paint alpha;
|
||||
alpha.color = Color::Red().WithAlpha(0.5);
|
||||
|
||||
canvas.SaveLayer(alpha);
|
||||
|
||||
canvas.DrawRect({100, 100, 100, 100}, red);
|
||||
canvas.DrawRect({120, 120, 100, 100}, green);
|
||||
canvas.DrawRect({140, 140, 100, 100}, blue);
|
||||
|
||||
canvas.Restore();
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
|
||||
@ -12,15 +12,13 @@
|
||||
namespace impeller {
|
||||
|
||||
Canvas::Canvas() {
|
||||
xformation_stack_.push({});
|
||||
passes_.emplace_back(CanvasPass{});
|
||||
Save(true);
|
||||
}
|
||||
|
||||
Canvas::~Canvas() = default;
|
||||
|
||||
void Canvas::Save() {
|
||||
FML_DCHECK(xformation_stack_.size() > 0);
|
||||
xformation_stack_.push(xformation_stack_.top());
|
||||
Save(false);
|
||||
}
|
||||
|
||||
bool Canvas::Restore() {
|
||||
@ -28,17 +26,16 @@ bool Canvas::Restore() {
|
||||
if (xformation_stack_.size() == 1) {
|
||||
return false;
|
||||
}
|
||||
xformation_stack_.pop();
|
||||
xformation_stack_.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Canvas::Concat(const Matrix& xformation) {
|
||||
const auto current_xformation = xformation_stack_.top().xformation;
|
||||
xformation_stack_.top().xformation = xformation * current_xformation;
|
||||
xformation_stack_.back().xformation = xformation * GetCurrentTransformation();
|
||||
}
|
||||
|
||||
const Matrix& Canvas::GetCurrentTransformation() const {
|
||||
return xformation_stack_.top().xformation;
|
||||
return xformation_stack_.back().xformation;
|
||||
}
|
||||
|
||||
void Canvas::Translate(const Vector3& offset) {
|
||||
@ -71,6 +68,7 @@ void Canvas::DrawPath(Path path, Paint paint) {
|
||||
entity.SetPath(std::move(path));
|
||||
entity.SetStencilDepth(GetStencilDepth());
|
||||
entity.SetContents(paint.CreateContentsForEntity());
|
||||
|
||||
GetCurrentPass().PushEntity(std::move(entity));
|
||||
}
|
||||
|
||||
@ -86,21 +84,23 @@ void Canvas::ClipPath(Path path) {
|
||||
entity.SetPath(std::move(path));
|
||||
entity.SetContents(std::make_shared<ClipContents>());
|
||||
entity.SetStencilDepth(GetStencilDepth());
|
||||
|
||||
GetCurrentPass().PushEntity(std::move(entity));
|
||||
}
|
||||
|
||||
void Canvas::DrawShadow(Path path, Color color, Scalar elevation) {}
|
||||
|
||||
void Canvas::DrawPicture(const Picture& picture) {
|
||||
for (const auto& pass : picture.passes) {
|
||||
CanvasPass new_pass;
|
||||
for (const auto& entity : pass.GetPassEntities()) {
|
||||
auto new_entity = entity;
|
||||
new_entity.SetTransformation(GetCurrentTransformation() *
|
||||
entity.GetTransformation());
|
||||
new_pass.PushEntity(std::move(new_entity));
|
||||
for (const auto& stack_entry : picture.entries) {
|
||||
auto new_stack_entry = stack_entry;
|
||||
if (auto pass = new_stack_entry.pass) {
|
||||
for (auto entity : pass->GetPassEntities()) {
|
||||
entity.IncrementStencilDepth(GetStencilDepth());
|
||||
entity.SetTransformation(GetCurrentTransformation() *
|
||||
entity.GetTransformation());
|
||||
}
|
||||
}
|
||||
passes_.emplace_back(std::move(new_pass));
|
||||
xformation_stack_.emplace_back(std::move(new_stack_entry));
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,21 +145,49 @@ void Canvas::DrawImageRect(std::shared_ptr<Image> image,
|
||||
|
||||
Picture Canvas::EndRecordingAsPicture() {
|
||||
Picture picture;
|
||||
picture.passes = std::move(passes_);
|
||||
picture.entries = std::move(xformation_stack_);
|
||||
return picture;
|
||||
}
|
||||
|
||||
CanvasPass& Canvas::GetCurrentPass() {
|
||||
FML_DCHECK(!passes_.empty());
|
||||
return passes_.back();
|
||||
for (auto i = xformation_stack_.rbegin(), end = xformation_stack_.rend();
|
||||
i < end; i++) {
|
||||
if (i->pass.has_value()) {
|
||||
return i->pass.value();
|
||||
}
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
void Canvas::IncrementStencilDepth() {
|
||||
++xformation_stack_.top().stencil_depth;
|
||||
++xformation_stack_.back().stencil_depth;
|
||||
}
|
||||
|
||||
size_t Canvas::GetStencilDepth() const {
|
||||
return xformation_stack_.top().stencil_depth;
|
||||
return xformation_stack_.back().stencil_depth;
|
||||
}
|
||||
|
||||
void Canvas::DrawRect(Rect rect, Paint paint) {
|
||||
DrawPath(PathBuilder{}.AddRect(rect).CreatePath(), std::move(paint));
|
||||
}
|
||||
|
||||
void Canvas::Save(bool create_subpass) {
|
||||
// Check if called from the ctor.
|
||||
if (xformation_stack_.empty()) {
|
||||
FML_DCHECK(create_subpass) << "Base entries must have a pass.";
|
||||
CanvasStackEntry entry;
|
||||
entry.pass = CanvasPass{};
|
||||
xformation_stack_.emplace_back(std::move(entry));
|
||||
}
|
||||
|
||||
auto entry = CanvasStackEntry{};
|
||||
|
||||
entry.xformation = xformation_stack_.back().xformation;
|
||||
entry.stencil_depth = xformation_stack_.back().stencil_depth;
|
||||
if (create_subpass) {
|
||||
entry.pass = CanvasPass{};
|
||||
}
|
||||
xformation_stack_.emplace_back(std::move(entry));
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -4,9 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
@ -23,11 +23,6 @@ namespace impeller {
|
||||
|
||||
class Entity;
|
||||
|
||||
struct CanvasStackEntry {
|
||||
Matrix xformation;
|
||||
size_t stencil_depth = 0u;
|
||||
};
|
||||
|
||||
class Canvas {
|
||||
public:
|
||||
Canvas();
|
||||
@ -56,6 +51,8 @@ class Canvas {
|
||||
|
||||
void DrawPath(Path path, Paint paint);
|
||||
|
||||
void DrawRect(Rect rect, Paint paint);
|
||||
|
||||
void DrawImage(std::shared_ptr<Image> image, Point offset, Paint paint);
|
||||
|
||||
void DrawImageRect(std::shared_ptr<Image> image,
|
||||
@ -72,8 +69,7 @@ class Canvas {
|
||||
Picture EndRecordingAsPicture();
|
||||
|
||||
private:
|
||||
std::stack<CanvasStackEntry> xformation_stack_;
|
||||
std::vector<CanvasPass> passes_;
|
||||
std::deque<CanvasStackEntry> xformation_stack_;
|
||||
|
||||
CanvasPass& GetCurrentPass();
|
||||
|
||||
@ -81,6 +77,8 @@ class Canvas {
|
||||
|
||||
size_t GetStencilDepth() const;
|
||||
|
||||
void Save(bool create_subpass);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(Canvas);
|
||||
};
|
||||
|
||||
|
||||
@ -26,4 +26,27 @@ const Entity& CanvasPass::GetPostProcessingEntity() const {
|
||||
return post_processing_entity_;
|
||||
}
|
||||
|
||||
Rect CanvasPass::GetCoverageRect() const {
|
||||
std::optional<Point> min, max;
|
||||
for (const auto& entity : ops_) {
|
||||
auto coverage = entity.GetPath().GetMinMaxCoveragePoints();
|
||||
if (!coverage.has_value()) {
|
||||
continue;
|
||||
}
|
||||
if (!min.has_value()) {
|
||||
min = coverage->first;
|
||||
}
|
||||
if (!max.has_value()) {
|
||||
max = coverage->second;
|
||||
}
|
||||
min = min->Min(coverage->first);
|
||||
max = max->Max(coverage->second);
|
||||
}
|
||||
if (!min.has_value() || !max.has_value()) {
|
||||
return {};
|
||||
}
|
||||
const auto diff = *max - *min;
|
||||
return {min->x, min->y, diff.x, diff.y};
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/entity/contents.h"
|
||||
@ -20,6 +21,8 @@ class CanvasPass {
|
||||
|
||||
void PushEntity(Entity entity);
|
||||
|
||||
Rect GetCoverageRect() const;
|
||||
|
||||
const std::vector<Entity>& GetPassEntities() const;
|
||||
|
||||
void SetPostProcessingEntity(Entity entity);
|
||||
@ -31,4 +34,10 @@ class CanvasPass {
|
||||
Entity post_processing_entity_;
|
||||
};
|
||||
|
||||
struct CanvasStackEntry {
|
||||
Matrix xformation;
|
||||
size_t stencil_depth = 0u;
|
||||
std::optional<CanvasPass> pass;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/aiks/canvas_pass.h"
|
||||
@ -14,7 +14,7 @@
|
||||
namespace impeller {
|
||||
|
||||
struct Picture {
|
||||
std::vector<CanvasPass> passes;
|
||||
std::deque<CanvasStackEntry> entries;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -29,10 +29,12 @@ bool PictureRenderer::Render(const Surface& surface,
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& pass : picture.passes) {
|
||||
if (!entity_renderer_.RenderEntities(surface, parent_pass,
|
||||
pass.GetPassEntities())) {
|
||||
return false;
|
||||
for (const auto& entry : picture.entries) {
|
||||
if (auto pass = entry.pass) {
|
||||
if (!entity_renderer_.RenderEntities(surface, parent_pass,
|
||||
pass->GetPassEntities())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -42,4 +42,8 @@ uint32_t Entity::GetStencilDepth() const {
|
||||
return stencil_depth_;
|
||||
}
|
||||
|
||||
void Entity::IncrementStencilDepth(uint32_t increment) {
|
||||
stencil_depth_ += increment;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -33,6 +33,8 @@ class Entity {
|
||||
|
||||
void SetStencilDepth(uint32_t stencil_depth);
|
||||
|
||||
void IncrementStencilDepth(uint32_t increment);
|
||||
|
||||
uint32_t GetStencilDepth() const;
|
||||
|
||||
private:
|
||||
|
||||
@ -62,6 +62,10 @@ struct Color {
|
||||
|
||||
static constexpr Color Blue() { return {0.0, 0.0, 1.0, 1.0}; }
|
||||
|
||||
constexpr Color WithAlpha(Scalar new_alpha) const {
|
||||
return {red, green, blue, new_alpha};
|
||||
}
|
||||
|
||||
static constexpr Color AliceBlue() {
|
||||
return {240.0 / 255.0, 248.0 / 255.0, 255.0 / 255.0, 1.0};
|
||||
}
|
||||
|
||||
@ -174,9 +174,20 @@ std::vector<Point> Path::CreatePolyline(
|
||||
}
|
||||
|
||||
Rect Path::GetBoundingBox() const {
|
||||
if (linears_.empty() && quads_.empty() && cubics_.empty()) {
|
||||
auto min_max = GetMinMaxCoveragePoints();
|
||||
if (!min_max.has_value()) {
|
||||
return {};
|
||||
}
|
||||
auto min = min_max->first;
|
||||
auto max = min_max->second;
|
||||
const auto difference = max - min;
|
||||
return {min.x, min.y, difference.x, difference.y};
|
||||
}
|
||||
|
||||
std::optional<std::pair<Point, Point>> Path::GetMinMaxCoveragePoints() const {
|
||||
if (linears_.empty() && quads_.empty() && cubics_.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<Point> min, max;
|
||||
|
||||
@ -209,9 +220,7 @@ Rect Path::GetBoundingBox() const {
|
||||
clamp(cubic.Extrema());
|
||||
}
|
||||
|
||||
const auto difference = *max - *min;
|
||||
|
||||
return {min->x, min->y, difference.x, difference.y};
|
||||
return std::make_pair(min.value(), max.value());
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "impeller/geometry/path_component.h"
|
||||
@ -68,6 +69,8 @@ class Path {
|
||||
|
||||
Rect GetBoundingBox() const;
|
||||
|
||||
std::optional<std::pair<Point, Point>> GetMinMaxCoveragePoints() const;
|
||||
|
||||
private:
|
||||
struct ComponentIndexPair {
|
||||
ComponentType type = ComponentType::kLinear;
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
@ -83,6 +84,14 @@ struct TPoint {
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
constexpr TPoint Min(const TPoint& p) const {
|
||||
return {std::min<Type>(x, p.x), std::min<Type>(y, p.y)};
|
||||
}
|
||||
|
||||
constexpr TPoint Max(const TPoint& p) const {
|
||||
return {std::max<Type>(x, p.x), std::max<Type>(y, p.y)};
|
||||
}
|
||||
|
||||
constexpr Type GetDistance(const TPoint& p) const {
|
||||
return sqrt(GetDistanceSquared(p));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user