Skip to content

Commit

Permalink
[Impeller] Change Renderer utility to pass RenderTarget to callback; …
Browse files Browse the repository at this point in the history
…render non-pipeline blend modes (flutter#32982)
  • Loading branch information
bdero authored May 10, 2022
1 parent fcf0e80 commit 3f51133
Show file tree
Hide file tree
Showing 23 changed files with 405 additions and 128 deletions.
4 changes: 2 additions & 2 deletions impeller/aiks/aiks_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ bool AiksContext::IsValid() const {
return is_valid_;
}

bool AiksContext::Render(const Picture& picture, RenderPass& parent_pass) {
bool AiksContext::Render(const Picture& picture, RenderTarget& render_target) {
if (!IsValid()) {
return false;
}

if (picture.pass) {
return picture.pass->Render(*content_context_, parent_pass);
return picture.pass->Render(*content_context_, render_target);
}

return true;
Expand Down
3 changes: 2 additions & 1 deletion impeller/aiks/aiks_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "flutter/fml/macros.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/renderer/context.h"
#include "impeller/renderer/render_target.h"

namespace impeller {

Expand All @@ -23,7 +24,7 @@ class AiksContext {

bool IsValid() const;

bool Render(const Picture& picture, RenderPass& parent_pass);
bool Render(const Picture& picture, RenderTarget& render_target);

private:
std::shared_ptr<Context> context_;
Expand Down
8 changes: 4 additions & 4 deletions impeller/aiks/aiks_playground.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ AiksPlayground::~AiksPlayground() = default;

bool AiksPlayground::OpenPlaygroundHere(const Picture& picture) {
return OpenPlaygroundHere(
[&picture](AiksContext& renderer, RenderPass& pass) -> bool {
return renderer.Render(picture, pass);
[&picture](AiksContext& renderer, RenderTarget& render_target) -> bool {
return renderer.Render(picture, render_target);
});
}

Expand All @@ -31,8 +31,8 @@ bool AiksPlayground::OpenPlaygroundHere(AiksPlaygroundCallback callback) {
}

return Playground::OpenPlaygroundHere(
[&renderer, &callback](RenderPass& pass) -> bool {
return callback(renderer, pass);
[&renderer, &callback](RenderTarget& render_target) -> bool {
return callback(renderer, render_target);
});
}

Expand Down
2 changes: 1 addition & 1 deletion impeller/aiks/aiks_playground.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace impeller {
class AiksPlayground : public Playground {
public:
using AiksPlaygroundCallback =
std::function<bool(AiksContext& renderer, RenderPass& pass)>;
std::function<bool(AiksContext& renderer, RenderTarget& render_target)>;

AiksPlayground();

Expand Down
125 changes: 121 additions & 4 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// found in the LICENSE file.

#include <array>
#include <cmath>
#include <tuple>

#include "flutter/testing/testing.h"
#include "impeller/aiks/aiks_playground.h"
Expand Down Expand Up @@ -467,6 +469,121 @@ TEST_P(AiksTest, PaintBlendModeIsRespected) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CanDrawWithAdvancedBlend) {
// Compare with https://fiddle.skia.org/c/@BlendModes

std::vector<const char*> blend_mode_names;
std::vector<Entity::BlendMode> blend_mode_values;
{
const std::vector<std::tuple<const char*, Entity::BlendMode>> blends = {
// Pipeline blends (Porter-Duff/alpha blends)
{"Clear", Entity::BlendMode::kClear},
{"Source", Entity::BlendMode::kSource},
{"Destination", Entity::BlendMode::kDestination},
{"SourceOver", Entity::BlendMode::kSourceOver},
{"DestinationOver", Entity::BlendMode::kDestinationOver},
{"SourceIn", Entity::BlendMode::kSourceIn},
{"DestinationIn", Entity::BlendMode::kDestinationIn},
{"SourceOut", Entity::BlendMode::kSourceOut},
{"DestinationOut", Entity::BlendMode::kDestinationOut},
{"SourceATop", Entity::BlendMode::kSourceATop},
{"DestinationATop", Entity::BlendMode::kDestinationATop},
{"Xor", Entity::BlendMode::kXor},
{"Plus", Entity::BlendMode::kPlus},
{"Modulate", Entity::BlendMode::kModulate},
// Advanced blends (non Porter-Duff/color blends)
{"Screen", Entity::BlendMode::kScreen},
};
assert(blends.size() ==
static_cast<size_t>(Entity::BlendMode::kLastAdvancedBlendMode) + 1);
for (const auto& [name, mode] : blends) {
blend_mode_names.push_back(name);
blend_mode_values.push_back(mode);
}
}

auto draw_color_wheel = [](Canvas& canvas) {
/// color_wheel_sampler: r=0 -> fuchsia, r=2pi/3 -> yellow, r=4pi/3 ->
/// cyan domain: r >= 0 (because modulo used is non euclidean)
auto color_wheel_sampler = [](Radians r) {
Scalar x = r.radians / k2Pi + 1;

// https://www.desmos.com/calculator/6nhjelyoaj
auto color_cycle = [](Scalar x) {
Scalar cycle = std::fmod(x, 6.0f);
return std::max(0.0f, std::min(1.0f, 2 - std::abs(2 - cycle)));
};
return Color(color_cycle(6 * x + 1), //
color_cycle(6 * x - 1), //
color_cycle(6 * x - 3), //
1);
};

Paint paint;

// Draw a fancy color wheel for the backdrop.
// https://www.desmos.com/calculator/xw7kafthwd
const int max_dist = 900;
for (int i = 0; i <= 900; i++) {
Radians r(kPhi / k2Pi * i);
Scalar distance = r.radians / std::powf(4.12, 0.0026 * r.radians);
Scalar normalized_distance = static_cast<Scalar>(i) / max_dist;

paint.color =
color_wheel_sampler(r).WithAlpha(1.0f - normalized_distance);
Point position(distance * std::sin(r.radians),
-distance * std::cos(r.radians));

canvas.DrawCircle(position, 9 + normalized_distance * 3, paint);
}
};

bool first_frame = true;
auto callback = [&](AiksContext& renderer, RenderTarget& render_target) {
if (first_frame) {
first_frame = false;
ImGui::SetNextWindowSize({350, 200});
ImGui::SetNextWindowPos({325, 550});
}

ImGui::Begin("Controls");
static int current_blend_index = 3;
ImGui::ListBox("Blending mode", &current_blend_index,
blend_mode_names.data(), blend_mode_names.size());
ImGui::End();

Canvas canvas;
Paint paint;
// Default blend is kSourceOver.
paint.color = Color::White();
canvas.DrawPaint(paint);

canvas.Translate(Vector2(500, 400));
canvas.Scale(Vector2(3, 3));

draw_color_wheel(canvas);

// Draw 3 circles to a subpass and blend it in.
canvas.SaveLayer({.blend_mode = blend_mode_values[current_blend_index]});
{
paint.blend_mode = Entity::BlendMode::kPlus;
const Scalar x = std::sin(k2Pi / 3);
const Scalar y = -std::cos(k2Pi / 3);
paint.color = Color::Red();
canvas.DrawCircle(Point(-x, y) * 45, 65, paint);
paint.color = Color::Green();
canvas.DrawCircle(Point(0, -1) * 45, 65, paint);
paint.color = Color::Blue();
canvas.DrawCircle(Point(x, y) * 45, 65, paint);
}
canvas.Restore();

return renderer.Render(canvas.EndRecordingAsPicture(), render_target);
};

ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_P(AiksTest, TransformMultipliesCorrectly) {
Canvas canvas;
ASSERT_MATRIX_NEAR(canvas.GetCurrentTransformation(), Matrix());
Expand Down Expand Up @@ -509,7 +626,7 @@ TEST_P(AiksTest, TransformMultipliesCorrectly) {
TEST_P(AiksTest, SolidStrokesRenderCorrectly) {
// Compare with https://fiddle.skia.org/c/027392122bec8ac2b5d5de00a4b9bbe2
bool first_frame = true;
auto callback = [&](AiksContext& renderer, RenderPass& pass) {
auto callback = [&](AiksContext& renderer, RenderTarget& render_target) {
if (first_frame) {
first_frame = false;
ImGui::SetNextWindowSize({480, 100});
Expand Down Expand Up @@ -573,14 +690,14 @@ TEST_P(AiksTest, SolidStrokesRenderCorrectly) {
canvas.Translate({-240, 60});
}

return renderer.Render(canvas.EndRecordingAsPicture(), pass);
return renderer.Render(canvas.EndRecordingAsPicture(), render_target);
};

ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_P(AiksTest, CoverageOriginShouldBeAccountedForInSubpasses) {
auto callback = [](AiksContext& renderer, RenderPass& pass) {
auto callback = [](AiksContext& renderer, RenderTarget& render_target) {
Canvas canvas;
Paint alpha;
alpha.color = Color::Red().WithAlpha(0.5);
Expand All @@ -605,7 +722,7 @@ TEST_P(AiksTest, CoverageOriginShouldBeAccountedForInSubpasses) {

canvas.Restore();

return renderer.Render(canvas.EndRecordingAsPicture(), pass);
return renderer.Render(canvas.EndRecordingAsPicture(), render_target);
};

ASSERT_TRUE(OpenPlaygroundHere(callback));
Expand Down
4 changes: 2 additions & 2 deletions impeller/display_list/display_list_playground.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ bool DisplayListPlayground::OpenPlaygroundHere(
return false;
}
return Playground::OpenPlaygroundHere(
[&context, &callback](RenderPass& pass) -> bool {
[&context, &callback](RenderTarget& render_target) -> bool {
auto list = callback();

DisplayListDispatcher dispatcher;
list->Dispatch(dispatcher);
auto picture = dispatcher.EndRecordingAsPicture();

return context.Render(picture, pass);
return context.Render(picture, render_target);
});
}

Expand Down
1 change: 1 addition & 0 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <sstream>

#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/formats.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/render_target.h"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,4 @@ std::optional<Rect> TextureFilterInput::GetCoverage(
.TransformBounds(GetTransform(entity));
}

Matrix TextureFilterInput::GetLocalTransform(const Entity& entity) const {
// Compute the local transform such that the texture is centered.
return Matrix::MakeTranslation(-Point(texture_->GetSize()) / 2);
}

} // namespace impeller
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ class TextureFilterInput final : public FilterInput {
// |FilterInput|
std::optional<Rect> GetCoverage(const Entity& entity) const override;

// |FilterInput|
Matrix GetLocalTransform(const Entity& entity) const override;

private:
TextureFilterInput(std::shared_ptr<Texture> texture);

Expand Down
5 changes: 1 addition & 4 deletions impeller/entity/entity.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "impeller/base/validation.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/contents/filters/filter_contents.h"
#include "impeller/renderer/render_pass.h"

namespace impeller {
Expand Down Expand Up @@ -61,10 +62,6 @@ void Entity::IncrementStencilDepth(uint32_t increment) {
}

void Entity::SetBlendMode(BlendMode blend_mode) {
if (blend_mode_ > BlendMode::kLastPipelineBlendMode) {
VALIDATION_LOG << "Non-pipeline blend modes are not supported by the "
"entity blend mode setting.";
}
blend_mode_ = blend_mode;
}

Expand Down
Loading

0 comments on commit 3f51133

Please sign in to comment.