Skip to content

Commit

Permalink
Filters: Replace Snapshot position with a full transform (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdero authored and dnfield committed Apr 27, 2022
1 parent 999978f commit 9c4018f
Show file tree
Hide file tree
Showing 17 changed files with 241 additions and 196 deletions.
5 changes: 3 additions & 2 deletions impeller/entity/contents/contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ std::optional<Rect> Contents::GetCoverage(const Entity& entity) const {
return entity.GetPathCoverage();
}

std::optional<Snapshot> Contents::RenderToTexture(
std::optional<Snapshot> Contents::RenderToSnapshot(
const ContentContext& renderer,
const Entity& entity) const {
auto bounds = GetCoverage(entity);
Expand All @@ -58,7 +58,8 @@ std::optional<Snapshot> Contents::RenderToTexture(
return std::nullopt;
}

return Snapshot{.texture = texture, .position = bounds->origin};
return Snapshot{.texture = texture,
.transform = Matrix::MakeTranslation(bounds->origin)};
}

} // namespace impeller
4 changes: 2 additions & 2 deletions impeller/entity/contents/contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ class Contents {
/// @brief Get the screen space bounding rectangle that this contents affects.
virtual std::optional<Rect> GetCoverage(const Entity& entity) const;

/// @brief Render this contents to a texture, respecting the entity's
/// @brief Render this contents to a snapshot, respecting the entity's
/// transform, path, stencil depth, blend mode, etc.
/// The result texture size is always the size of
/// `GetCoverage(entity)`.
virtual std::optional<Snapshot> RenderToTexture(
virtual std::optional<Snapshot> RenderToSnapshot(
const ContentContext& renderer,
const Entity& entity) const;

Expand Down
142 changes: 77 additions & 65 deletions impeller/entity/contents/filters/blend_filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,43 @@ static bool AdvancedBlend(const FilterInput::Vector& inputs,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const Rect& bounds,
const Rect& coverage,
PipelineProc pipeline_proc) {
if (inputs.size() < 2) {
return false;
}

auto dst_snapshot = inputs[1]->GetSnapshot(renderer, entity);
if (!dst_snapshot.has_value()) {
return true;
}
auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(coverage);
if (!maybe_dst_uvs.has_value()) {
return true;
}
auto dst_uvs = maybe_dst_uvs.value();

auto src_snapshot = inputs[0]->GetSnapshot(renderer, entity);
if (!src_snapshot.has_value()) {
return true;
}
auto maybe_src_uvs = src_snapshot->GetCoverageUVs(coverage);
if (!maybe_src_uvs.has_value()) {
return true;
}
auto src_uvs = maybe_src_uvs.value();

auto& host_buffer = pass.GetTransientsBuffer();

auto size = pass.GetRenderTargetSize();
VertexBufferBuilder<typename VS::PerVertexData> vtx_builder;
vtx_builder.AddVertices({
{Point(0, 0), Point(0, 0)},
{Point(size.width, 0), Point(1, 0)},
{Point(size.width, size.height), Point(1, 1)},
{Point(0, 0), Point(0, 0)},
{Point(size.width, size.height), Point(1, 1)},
{Point(0, size.height), Point(0, 1)},
{Point(0, 0), dst_uvs[0], src_uvs[0]},
{Point(size.width, 0), dst_uvs[1], src_uvs[1]},
{Point(size.width, size.height), dst_uvs[3], src_uvs[3]},
{Point(0, 0), dst_uvs[0], src_uvs[0]},
{Point(size.width, size.height), dst_uvs[3], src_uvs[3]},
{Point(0, size.height), dst_uvs[2], src_uvs[2]},
});
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);

Expand All @@ -56,25 +76,12 @@ static bool AdvancedBlend(const FilterInput::Vector& inputs,
cmd.pipeline = std::move(pipeline);

auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, sampler);
FS::BindTextureSamplerSrc(cmd, src_snapshot->texture, sampler);

typename VS::FrameInfo frame_info;
frame_info.mvp = Matrix::MakeOrthographic(size);

auto dst_snapshot = inputs[1]->GetSnapshot(renderer, entity);
FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, sampler);
frame_info.dst_uv_transform =
Matrix::MakeTranslation(-(dst_snapshot->position - bounds.origin) /
size) *
Matrix::MakeScale(
Vector3(Size(size) / Size(dst_snapshot->texture->GetSize())));

auto src_snapshot = inputs[0]->GetSnapshot(renderer, entity);
FS::BindTextureSamplerDst(cmd, src_snapshot->texture, sampler);
frame_info.src_uv_transform =
Matrix::MakeTranslation(-(src_snapshot->position - bounds.origin) /
size) *
Matrix::MakeScale(
Vector3(Size(size) / Size(src_snapshot->texture->GetSize())));

auto uniform_view = host_buffer.EmplaceUniform(frame_info);
VS::BindFrameInfo(cmd, uniform_view);
pass.AddCommand(cmd);
Expand All @@ -99,11 +106,11 @@ void BlendFilterContents::SetBlendMode(Entity::BlendMode blend_mode) {
advanced_blend_proc_ = [](const FilterInput::Vector& inputs,
const ContentContext& renderer,
const Entity& entity, RenderPass& pass,
const Rect& bounds) {
const Rect& coverage) {
PipelineProc p = &ContentContext::GetTextureBlendScreenPipeline;
return AdvancedBlend<TextureBlendScreenPipeline::VertexShader,
TextureBlendScreenPipeline::FragmentShader>(
inputs, renderer, entity, pass, bounds, p);
inputs, renderer, entity, pass, coverage, p);
};
break;
default:
Expand All @@ -116,49 +123,62 @@ static bool BasicBlend(const FilterInput::Vector& inputs,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const Rect& bounds,
const Rect& coverage,
Entity::BlendMode basic_blend) {
using VS = TextureBlendPipeline::VertexShader;
using FS = TextureBlendPipeline::FragmentShader;

auto& host_buffer = pass.GetTransientsBuffer();

auto size = pass.GetRenderTargetSize();
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
vtx_builder.AddVertices({
{Point(0, 0), Point(0, 0)},
{Point(size.width, 0), Point(1, 0)},
{Point(size.width, size.height), Point(1, 1)},
{Point(0, 0), Point(0, 0)},
{Point(size.width, size.height), Point(1, 1)},
{Point(0, size.height), Point(0, 1)},
});
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);

auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});

// Draw the first texture using kSource.

Command cmd;
cmd.label = "Basic Blend Filter";
cmd.BindVertices(vtx_buffer);
auto options = OptionsFromPass(pass);
options.blend_mode = Entity::BlendMode::kSource;
cmd.pipeline = renderer.GetTextureBlendPipeline(options);
{
auto input = inputs[0]->GetSnapshot(renderer, entity);

auto add_blend_command = [&](std::optional<Snapshot> input) {
if (!input.has_value()) {
return false;
}
auto input_coverage = input->GetCoverage();
if (!input_coverage.has_value()) {
return false;
}

FS::BindTextureSamplerSrc(cmd, input->texture, sampler);

auto size = input->texture->GetSize();
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
vtx_builder.AddVertices({
{Point(0, 0), Point(0, 0)},
{Point(size.width, 0), Point(1, 0)},
{Point(size.width, size.height), Point(1, 1)},
{Point(0, 0), Point(0, 0)},
{Point(size.width, size.height), Point(1, 1)},
{Point(0, size.height), Point(0, 1)},
});
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
cmd.BindVertices(vtx_buffer);

VS::FrameInfo frame_info;
frame_info.mvp =
Matrix::MakeOrthographic(size) *
Matrix::MakeTranslation(input->position - bounds.origin) *
Matrix::MakeScale(Size(input->texture->GetSize()) / Size(size));
frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
Matrix::MakeTranslation(-coverage.origin) *
input->transform;

auto uniform_view = host_buffer.EmplaceUniform(frame_info);
VS::BindFrameInfo(cmd, uniform_view);

pass.AddCommand(cmd);
return true;
};

// Draw the first texture using kSource.

options.blend_mode = Entity::BlendMode::kSource;
cmd.pipeline = renderer.GetTextureBlendPipeline(options);
if (!add_blend_command(inputs[0]->GetSnapshot(renderer, entity))) {
return true;
}
pass.AddCommand(cmd);

if (inputs.size() < 2) {
return true;
Expand All @@ -172,17 +192,9 @@ static bool BasicBlend(const FilterInput::Vector& inputs,
for (auto texture_i = inputs.begin() + 1; texture_i < inputs.end();
texture_i++) {
auto input = texture_i->get()->GetSnapshot(renderer, entity);
FS::BindTextureSamplerSrc(cmd, input->texture, sampler);

VS::FrameInfo frame_info;
frame_info.mvp = frame_info.mvp =
Matrix::MakeOrthographic(size) *
Matrix::MakeTranslation(input->position - bounds.origin) *
Matrix::MakeScale(Size(input->texture->GetSize()) / Size(size));

auto uniform_view = host_buffer.EmplaceUniform(frame_info);
VS::BindFrameInfo(cmd, uniform_view);
pass.AddCommand(cmd);
if (!add_blend_command(input)) {
return true;
}
}

return true;
Expand All @@ -192,23 +204,23 @@ bool BlendFilterContents::RenderFilter(const FilterInput::Vector& inputs,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const Rect& bounds) const {
const Rect& coverage) const {
if (inputs.empty()) {
return true;
}

if (inputs.size() == 1) {
// Nothing to blend.
return BasicBlend(inputs, renderer, entity, pass, bounds,
return BasicBlend(inputs, renderer, entity, pass, coverage,
Entity::BlendMode::kSource);
}

if (blend_mode_ <= Entity::BlendMode::kLastPipelineBlendMode) {
return BasicBlend(inputs, renderer, entity, pass, bounds, blend_mode_);
return BasicBlend(inputs, renderer, entity, pass, coverage, blend_mode_);
}

if (blend_mode_ <= Entity::BlendMode::kLastAdvancedBlendMode) {
return advanced_blend_proc_(inputs, renderer, entity, pass, bounds);
return advanced_blend_proc_(inputs, renderer, entity, pass, coverage);
}

FML_UNREACHABLE();
Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/filters/blend_filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class BlendFilterContents : public FilterContents {
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const Rect& bounds)>;
const Rect& coverage)>;

BlendFilterContents();

Expand All @@ -30,7 +30,7 @@ class BlendFilterContents : public FilterContents {
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const Rect& bounds) const override;
const Rect& coverage) const override;

Entity::BlendMode blend_mode_;
AdvancedBlendProc advanced_blend_proc_;
Expand Down
11 changes: 7 additions & 4 deletions impeller/entity/contents/filters/filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ std::shared_ptr<FilterContents> FilterContents::MakeBlend(
new_blend = std::make_shared<BlendFilterContents>();
new_blend->SetInputs({blend_input, *in_i});
new_blend->SetBlendMode(blend_mode);
blend_input = FilterInput::Make(new_blend);
if (in_i < inputs.end() - 1) {
blend_input = FilterInput::Make(new_blend);
}
}
// new_blend will always be assigned because inputs.size() >= 2.
return new_blend;
Expand Down Expand Up @@ -104,7 +106,7 @@ bool FilterContents::Render(const ContentContext& renderer,

// Run the filter.

auto maybe_snapshot = RenderToTexture(renderer, entity);
auto maybe_snapshot = RenderToSnapshot(renderer, entity);
if (!maybe_snapshot.has_value()) {
return false;
}
Expand Down Expand Up @@ -147,7 +149,7 @@ std::optional<Rect> FilterContents::GetCoverage(const Entity& entity) const {
return result;
}

std::optional<Snapshot> FilterContents::RenderToTexture(
std::optional<Snapshot> FilterContents::RenderToSnapshot(
const ContentContext& renderer,
const Entity& entity) const {
auto bounds = GetCoverage(entity);
Expand All @@ -166,7 +168,8 @@ std::optional<Snapshot> FilterContents::RenderToTexture(
return std::nullopt;
}

return Snapshot{.texture = texture, .position = bounds->origin};
return Snapshot{.texture = texture,
.transform = Matrix::MakeTranslation(bounds->origin)};
}

} // namespace impeller
2 changes: 1 addition & 1 deletion impeller/entity/contents/filters/filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class FilterContents : public Contents {
std::optional<Rect> GetCoverage(const Entity& entity) const override;

// |Contents|
virtual std::optional<Snapshot> RenderToTexture(
virtual std::optional<Snapshot> RenderToSnapshot(
const ContentContext& renderer,
const Entity& entity) const override;

Expand Down
22 changes: 17 additions & 5 deletions impeller/entity/contents/filters/filter_input.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <cstdarg>
#include <initializer_list>
#include <memory>
#include <optional>

#include "impeller/entity/contents/snapshot.h"
#include "impeller/entity/entity.h"
Expand All @@ -32,7 +33,7 @@ FilterInput::Variant FilterInput::GetInput() const {

std::optional<Rect> FilterInput::GetCoverage(const Entity& entity) const {
if (snapshot_) {
return Rect(snapshot_->position, Size(snapshot_->texture->GetSize()));
return snapshot_->GetCoverage();
}

if (auto contents = std::get_if<std::shared_ptr<Contents>>(&input_)) {
Expand All @@ -51,7 +52,7 @@ std::optional<Snapshot> FilterInput::GetSnapshot(const ContentContext& renderer,
if (snapshot_) {
return snapshot_;
}
snapshot_ = RenderToTexture(renderer, entity);
snapshot_ = MakeSnapshot(renderer, entity);

return snapshot_;
}
Expand All @@ -60,15 +61,26 @@ FilterInput::FilterInput(Variant input) : input_(input) {}

FilterInput::~FilterInput() = default;

std::optional<Snapshot> FilterInput::RenderToTexture(
std::optional<Snapshot> FilterInput::MakeSnapshot(
const ContentContext& renderer,
const Entity& entity) const {
if (auto contents = std::get_if<std::shared_ptr<Contents>>(&input_)) {
return contents->get()->RenderToTexture(renderer, entity);
return contents->get()->RenderToSnapshot(renderer, entity);
}

if (auto texture = std::get_if<std::shared_ptr<Texture>>(&input_)) {
return Snapshot::FromTransformedTexture(renderer, entity, *texture);
// Rendered textures stretch to fit the entity path coverage, so we
// incorporate this behavior by translating and scaling the snapshot
// transform.
auto path_bounds = entity.GetPath().GetBoundingBox();
if (!path_bounds.has_value()) {
return std::nullopt;
}
auto transform = entity.GetTransformation() *
Matrix::MakeTranslation(path_bounds->origin) *
Matrix::MakeScale(Vector2(path_bounds->size) /
texture->get()->GetSize());
return Snapshot{.texture = *texture, .transform = transform};
}

FML_UNREACHABLE();
Expand Down
6 changes: 4 additions & 2 deletions impeller/entity/contents/filters/filter_input.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ class FilterInput final {
private:
FilterInput(Variant input);

std::optional<Snapshot> RenderToTexture(const ContentContext& renderer,
const Entity& entity) const;
std::optional<Snapshot> MakeSnapshot(const ContentContext& renderer,
const Entity& entity) const;

std::optional<Snapshot> MakeSnapshotForTexture(const Entity& entity) const;

Variant input_;
mutable std::optional<Snapshot> snapshot_;
Expand Down
Loading

0 comments on commit 9c4018f

Please sign in to comment.