Skip to content

Commit

Permalink
Rework canvas passes in prep for subpasses.
Browse files Browse the repository at this point in the history
  • Loading branch information
chinmaygarde authored and dnfield committed Apr 27, 2022
1 parent 60c3b21 commit 65ffd04
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 39 deletions.
24 changes: 24 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}

Expand Down
70 changes: 49 additions & 21 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,30 @@
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() {
FML_DCHECK(xformation_stack_.size() > 0);
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) {
Expand Down Expand Up @@ -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));
}

Expand All @@ -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));
}
}

Expand Down Expand Up @@ -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
14 changes: 6 additions & 8 deletions impeller/aiks/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

#pragma once

#include <deque>
#include <memory>
#include <optional>
#include <stack>
#include <vector>

#include "flutter/fml/macros.h"
Expand All @@ -23,11 +23,6 @@ namespace impeller {

class Entity;

struct CanvasStackEntry {
Matrix xformation;
size_t stencil_depth = 0u;
};

class Canvas {
public:
Canvas();
Expand Down Expand Up @@ -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,
Expand All @@ -72,15 +69,16 @@ class Canvas {
Picture EndRecordingAsPicture();

private:
std::stack<CanvasStackEntry> xformation_stack_;
std::vector<CanvasPass> passes_;
std::deque<CanvasStackEntry> xformation_stack_;

CanvasPass& GetCurrentPass();

void IncrementStencilDepth();

size_t GetStencilDepth() const;

void Save(bool create_subpass);

FML_DISALLOW_COPY_AND_ASSIGN(Canvas);
};

Expand Down
23 changes: 23 additions & 0 deletions impeller/aiks/canvas_pass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions impeller/aiks/canvas_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#pragma once

#include <memory>
#include <optional>

#include "flutter/fml/macros.h"
#include "impeller/entity/contents.h"
Expand All @@ -20,6 +21,8 @@ class CanvasPass {

void PushEntity(Entity entity);

Rect GetCoverageRect() const;

const std::vector<Entity>& GetPassEntities() const;

void SetPostProcessingEntity(Entity entity);
Expand All @@ -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 changes: 2 additions & 2 deletions impeller/aiks/picture.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

#pragma once

#include <deque>
#include <memory>
#include <vector>

#include "flutter/fml/macros.h"
#include "impeller/aiks/canvas_pass.h"
Expand All @@ -14,7 +14,7 @@
namespace impeller {

struct Picture {
std::vector<CanvasPass> passes;
std::deque<CanvasStackEntry> entries;
};

} // namespace impeller
10 changes: 6 additions & 4 deletions impeller/aiks/picture_renderer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions impeller/entity/entity.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,8 @@ uint32_t Entity::GetStencilDepth() const {
return stencil_depth_;
}

void Entity::IncrementStencilDepth(uint32_t increment) {
stencil_depth_ += increment;
}

} // namespace impeller
2 changes: 2 additions & 0 deletions impeller/entity/entity.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class Entity {

void SetStencilDepth(uint32_t stencil_depth);

void IncrementStencilDepth(uint32_t increment);

uint32_t GetStencilDepth() const;

private:
Expand Down
4 changes: 4 additions & 0 deletions impeller/geometry/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -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};
}
Expand Down
17 changes: 13 additions & 4 deletions impeller/geometry/path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
3 changes: 3 additions & 0 deletions impeller/geometry/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#pragma once

#include <functional>
#include <optional>
#include <vector>

#include "impeller/geometry/path_component.h"
Expand Down Expand Up @@ -68,6 +69,8 @@ class Path {

Rect GetBoundingBox() const;

std::optional<std::pair<Point, Point>> GetMinMaxCoveragePoints() const;

private:
struct ComponentIndexPair {
ComponentType type = ComponentType::kLinear;
Expand Down
Loading

0 comments on commit 65ffd04

Please sign in to comment.