Skip to content

Commit 9c4018f

Browse files
bderodnfield
authored andcommitted
Filters: Replace Snapshot position with a full transform (#130)
1 parent 999978f commit 9c4018f

17 files changed

+241
-196
lines changed

impeller/entity/contents/contents.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ std::optional<Rect> Contents::GetCoverage(const Entity& entity) const {
3333
return entity.GetPathCoverage();
3434
}
3535

36-
std::optional<Snapshot> Contents::RenderToTexture(
36+
std::optional<Snapshot> Contents::RenderToSnapshot(
3737
const ContentContext& renderer,
3838
const Entity& entity) const {
3939
auto bounds = GetCoverage(entity);
@@ -58,7 +58,8 @@ std::optional<Snapshot> Contents::RenderToTexture(
5858
return std::nullopt;
5959
}
6060

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

6465
} // namespace impeller

impeller/entity/contents/contents.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ class Contents {
3939
/// @brief Get the screen space bounding rectangle that this contents affects.
4040
virtual std::optional<Rect> GetCoverage(const Entity& entity) const;
4141

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

impeller/entity/contents/filters/blend_filter_contents.cc

+77-65
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,43 @@ static bool AdvancedBlend(const FilterInput::Vector& inputs,
2525
const ContentContext& renderer,
2626
const Entity& entity,
2727
RenderPass& pass,
28-
const Rect& bounds,
28+
const Rect& coverage,
2929
PipelineProc pipeline_proc) {
3030
if (inputs.size() < 2) {
3131
return false;
3232
}
3333

34+
auto dst_snapshot = inputs[1]->GetSnapshot(renderer, entity);
35+
if (!dst_snapshot.has_value()) {
36+
return true;
37+
}
38+
auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(coverage);
39+
if (!maybe_dst_uvs.has_value()) {
40+
return true;
41+
}
42+
auto dst_uvs = maybe_dst_uvs.value();
43+
44+
auto src_snapshot = inputs[0]->GetSnapshot(renderer, entity);
45+
if (!src_snapshot.has_value()) {
46+
return true;
47+
}
48+
auto maybe_src_uvs = src_snapshot->GetCoverageUVs(coverage);
49+
if (!maybe_src_uvs.has_value()) {
50+
return true;
51+
}
52+
auto src_uvs = maybe_src_uvs.value();
53+
3454
auto& host_buffer = pass.GetTransientsBuffer();
3555

3656
auto size = pass.GetRenderTargetSize();
3757
VertexBufferBuilder<typename VS::PerVertexData> vtx_builder;
3858
vtx_builder.AddVertices({
39-
{Point(0, 0), Point(0, 0)},
40-
{Point(size.width, 0), Point(1, 0)},
41-
{Point(size.width, size.height), Point(1, 1)},
42-
{Point(0, 0), Point(0, 0)},
43-
{Point(size.width, size.height), Point(1, 1)},
44-
{Point(0, size.height), Point(0, 1)},
59+
{Point(0, 0), dst_uvs[0], src_uvs[0]},
60+
{Point(size.width, 0), dst_uvs[1], src_uvs[1]},
61+
{Point(size.width, size.height), dst_uvs[3], src_uvs[3]},
62+
{Point(0, 0), dst_uvs[0], src_uvs[0]},
63+
{Point(size.width, size.height), dst_uvs[3], src_uvs[3]},
64+
{Point(0, size.height), dst_uvs[2], src_uvs[2]},
4565
});
4666
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
4767

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

5878
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
79+
FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, sampler);
80+
FS::BindTextureSamplerSrc(cmd, src_snapshot->texture, sampler);
81+
5982
typename VS::FrameInfo frame_info;
6083
frame_info.mvp = Matrix::MakeOrthographic(size);
6184

62-
auto dst_snapshot = inputs[1]->GetSnapshot(renderer, entity);
63-
FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, sampler);
64-
frame_info.dst_uv_transform =
65-
Matrix::MakeTranslation(-(dst_snapshot->position - bounds.origin) /
66-
size) *
67-
Matrix::MakeScale(
68-
Vector3(Size(size) / Size(dst_snapshot->texture->GetSize())));
69-
70-
auto src_snapshot = inputs[0]->GetSnapshot(renderer, entity);
71-
FS::BindTextureSamplerDst(cmd, src_snapshot->texture, sampler);
72-
frame_info.src_uv_transform =
73-
Matrix::MakeTranslation(-(src_snapshot->position - bounds.origin) /
74-
size) *
75-
Matrix::MakeScale(
76-
Vector3(Size(size) / Size(src_snapshot->texture->GetSize())));
77-
7885
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
7986
VS::BindFrameInfo(cmd, uniform_view);
8087
pass.AddCommand(cmd);
@@ -99,11 +106,11 @@ void BlendFilterContents::SetBlendMode(Entity::BlendMode blend_mode) {
99106
advanced_blend_proc_ = [](const FilterInput::Vector& inputs,
100107
const ContentContext& renderer,
101108
const Entity& entity, RenderPass& pass,
102-
const Rect& bounds) {
109+
const Rect& coverage) {
103110
PipelineProc p = &ContentContext::GetTextureBlendScreenPipeline;
104111
return AdvancedBlend<TextureBlendScreenPipeline::VertexShader,
105112
TextureBlendScreenPipeline::FragmentShader>(
106-
inputs, renderer, entity, pass, bounds, p);
113+
inputs, renderer, entity, pass, coverage, p);
107114
};
108115
break;
109116
default:
@@ -116,49 +123,62 @@ static bool BasicBlend(const FilterInput::Vector& inputs,
116123
const ContentContext& renderer,
117124
const Entity& entity,
118125
RenderPass& pass,
119-
const Rect& bounds,
126+
const Rect& coverage,
120127
Entity::BlendMode basic_blend) {
121128
using VS = TextureBlendPipeline::VertexShader;
122129
using FS = TextureBlendPipeline::FragmentShader;
123130

124131
auto& host_buffer = pass.GetTransientsBuffer();
125132

126-
auto size = pass.GetRenderTargetSize();
127-
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
128-
vtx_builder.AddVertices({
129-
{Point(0, 0), Point(0, 0)},
130-
{Point(size.width, 0), Point(1, 0)},
131-
{Point(size.width, size.height), Point(1, 1)},
132-
{Point(0, 0), Point(0, 0)},
133-
{Point(size.width, size.height), Point(1, 1)},
134-
{Point(0, size.height), Point(0, 1)},
135-
});
136-
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
137-
138133
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
139134

140-
// Draw the first texture using kSource.
141-
142135
Command cmd;
143136
cmd.label = "Basic Blend Filter";
144-
cmd.BindVertices(vtx_buffer);
145137
auto options = OptionsFromPass(pass);
146-
options.blend_mode = Entity::BlendMode::kSource;
147-
cmd.pipeline = renderer.GetTextureBlendPipeline(options);
148-
{
149-
auto input = inputs[0]->GetSnapshot(renderer, entity);
138+
139+
auto add_blend_command = [&](std::optional<Snapshot> input) {
140+
if (!input.has_value()) {
141+
return false;
142+
}
143+
auto input_coverage = input->GetCoverage();
144+
if (!input_coverage.has_value()) {
145+
return false;
146+
}
147+
150148
FS::BindTextureSamplerSrc(cmd, input->texture, sampler);
151149

150+
auto size = input->texture->GetSize();
151+
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
152+
vtx_builder.AddVertices({
153+
{Point(0, 0), Point(0, 0)},
154+
{Point(size.width, 0), Point(1, 0)},
155+
{Point(size.width, size.height), Point(1, 1)},
156+
{Point(0, 0), Point(0, 0)},
157+
{Point(size.width, size.height), Point(1, 1)},
158+
{Point(0, size.height), Point(0, 1)},
159+
});
160+
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
161+
cmd.BindVertices(vtx_buffer);
162+
152163
VS::FrameInfo frame_info;
153-
frame_info.mvp =
154-
Matrix::MakeOrthographic(size) *
155-
Matrix::MakeTranslation(input->position - bounds.origin) *
156-
Matrix::MakeScale(Size(input->texture->GetSize()) / Size(size));
164+
frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
165+
Matrix::MakeTranslation(-coverage.origin) *
166+
input->transform;
157167

158168
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
159169
VS::BindFrameInfo(cmd, uniform_view);
170+
171+
pass.AddCommand(cmd);
172+
return true;
173+
};
174+
175+
// Draw the first texture using kSource.
176+
177+
options.blend_mode = Entity::BlendMode::kSource;
178+
cmd.pipeline = renderer.GetTextureBlendPipeline(options);
179+
if (!add_blend_command(inputs[0]->GetSnapshot(renderer, entity))) {
180+
return true;
160181
}
161-
pass.AddCommand(cmd);
162182

163183
if (inputs.size() < 2) {
164184
return true;
@@ -172,17 +192,9 @@ static bool BasicBlend(const FilterInput::Vector& inputs,
172192
for (auto texture_i = inputs.begin() + 1; texture_i < inputs.end();
173193
texture_i++) {
174194
auto input = texture_i->get()->GetSnapshot(renderer, entity);
175-
FS::BindTextureSamplerSrc(cmd, input->texture, sampler);
176-
177-
VS::FrameInfo frame_info;
178-
frame_info.mvp = frame_info.mvp =
179-
Matrix::MakeOrthographic(size) *
180-
Matrix::MakeTranslation(input->position - bounds.origin) *
181-
Matrix::MakeScale(Size(input->texture->GetSize()) / Size(size));
182-
183-
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
184-
VS::BindFrameInfo(cmd, uniform_view);
185-
pass.AddCommand(cmd);
195+
if (!add_blend_command(input)) {
196+
return true;
197+
}
186198
}
187199

188200
return true;
@@ -192,23 +204,23 @@ bool BlendFilterContents::RenderFilter(const FilterInput::Vector& inputs,
192204
const ContentContext& renderer,
193205
const Entity& entity,
194206
RenderPass& pass,
195-
const Rect& bounds) const {
207+
const Rect& coverage) const {
196208
if (inputs.empty()) {
197209
return true;
198210
}
199211

200212
if (inputs.size() == 1) {
201213
// Nothing to blend.
202-
return BasicBlend(inputs, renderer, entity, pass, bounds,
214+
return BasicBlend(inputs, renderer, entity, pass, coverage,
203215
Entity::BlendMode::kSource);
204216
}
205217

206218
if (blend_mode_ <= Entity::BlendMode::kLastPipelineBlendMode) {
207-
return BasicBlend(inputs, renderer, entity, pass, bounds, blend_mode_);
219+
return BasicBlend(inputs, renderer, entity, pass, coverage, blend_mode_);
208220
}
209221

210222
if (blend_mode_ <= Entity::BlendMode::kLastAdvancedBlendMode) {
211-
return advanced_blend_proc_(inputs, renderer, entity, pass, bounds);
223+
return advanced_blend_proc_(inputs, renderer, entity, pass, coverage);
212224
}
213225

214226
FML_UNREACHABLE();

impeller/entity/contents/filters/blend_filter_contents.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class BlendFilterContents : public FilterContents {
1616
const ContentContext& renderer,
1717
const Entity& entity,
1818
RenderPass& pass,
19-
const Rect& bounds)>;
19+
const Rect& coverage)>;
2020

2121
BlendFilterContents();
2222

@@ -30,7 +30,7 @@ class BlendFilterContents : public FilterContents {
3030
const ContentContext& renderer,
3131
const Entity& entity,
3232
RenderPass& pass,
33-
const Rect& bounds) const override;
33+
const Rect& coverage) const override;
3434

3535
Entity::BlendMode blend_mode_;
3636
AdvancedBlendProc advanced_blend_proc_;

impeller/entity/contents/filters/filter_contents.cc

+7-4
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ std::shared_ptr<FilterContents> FilterContents::MakeBlend(
5050
new_blend = std::make_shared<BlendFilterContents>();
5151
new_blend->SetInputs({blend_input, *in_i});
5252
new_blend->SetBlendMode(blend_mode);
53-
blend_input = FilterInput::Make(new_blend);
53+
if (in_i < inputs.end() - 1) {
54+
blend_input = FilterInput::Make(new_blend);
55+
}
5456
}
5557
// new_blend will always be assigned because inputs.size() >= 2.
5658
return new_blend;
@@ -104,7 +106,7 @@ bool FilterContents::Render(const ContentContext& renderer,
104106

105107
// Run the filter.
106108

107-
auto maybe_snapshot = RenderToTexture(renderer, entity);
109+
auto maybe_snapshot = RenderToSnapshot(renderer, entity);
108110
if (!maybe_snapshot.has_value()) {
109111
return false;
110112
}
@@ -147,7 +149,7 @@ std::optional<Rect> FilterContents::GetCoverage(const Entity& entity) const {
147149
return result;
148150
}
149151

150-
std::optional<Snapshot> FilterContents::RenderToTexture(
152+
std::optional<Snapshot> FilterContents::RenderToSnapshot(
151153
const ContentContext& renderer,
152154
const Entity& entity) const {
153155
auto bounds = GetCoverage(entity);
@@ -166,7 +168,8 @@ std::optional<Snapshot> FilterContents::RenderToTexture(
166168
return std::nullopt;
167169
}
168170

169-
return Snapshot{.texture = texture, .position = bounds->origin};
171+
return Snapshot{.texture = texture,
172+
.transform = Matrix::MakeTranslation(bounds->origin)};
170173
}
171174

172175
} // namespace impeller

impeller/entity/contents/filters/filter_contents.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class FilterContents : public Contents {
116116
std::optional<Rect> GetCoverage(const Entity& entity) const override;
117117

118118
// |Contents|
119-
virtual std::optional<Snapshot> RenderToTexture(
119+
virtual std::optional<Snapshot> RenderToSnapshot(
120120
const ContentContext& renderer,
121121
const Entity& entity) const override;
122122

impeller/entity/contents/filters/filter_input.cc

+17-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <cstdarg>
88
#include <initializer_list>
99
#include <memory>
10+
#include <optional>
1011

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

3334
std::optional<Rect> FilterInput::GetCoverage(const Entity& entity) const {
3435
if (snapshot_) {
35-
return Rect(snapshot_->position, Size(snapshot_->texture->GetSize()));
36+
return snapshot_->GetCoverage();
3637
}
3738

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

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

6162
FilterInput::~FilterInput() = default;
6263

63-
std::optional<Snapshot> FilterInput::RenderToTexture(
64+
std::optional<Snapshot> FilterInput::MakeSnapshot(
6465
const ContentContext& renderer,
6566
const Entity& entity) const {
6667
if (auto contents = std::get_if<std::shared_ptr<Contents>>(&input_)) {
67-
return contents->get()->RenderToTexture(renderer, entity);
68+
return contents->get()->RenderToSnapshot(renderer, entity);
6869
}
6970

7071
if (auto texture = std::get_if<std::shared_ptr<Texture>>(&input_)) {
71-
return Snapshot::FromTransformedTexture(renderer, entity, *texture);
72+
// Rendered textures stretch to fit the entity path coverage, so we
73+
// incorporate this behavior by translating and scaling the snapshot
74+
// transform.
75+
auto path_bounds = entity.GetPath().GetBoundingBox();
76+
if (!path_bounds.has_value()) {
77+
return std::nullopt;
78+
}
79+
auto transform = entity.GetTransformation() *
80+
Matrix::MakeTranslation(path_bounds->origin) *
81+
Matrix::MakeScale(Vector2(path_bounds->size) /
82+
texture->get()->GetSize());
83+
return Snapshot{.texture = *texture, .transform = transform};
7284
}
7385

7486
FML_UNREACHABLE();

impeller/entity/contents/filters/filter_input.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ class FilterInput final {
5050
private:
5151
FilterInput(Variant input);
5252

53-
std::optional<Snapshot> RenderToTexture(const ContentContext& renderer,
54-
const Entity& entity) const;
53+
std::optional<Snapshot> MakeSnapshot(const ContentContext& renderer,
54+
const Entity& entity) const;
55+
56+
std::optional<Snapshot> MakeSnapshotForTexture(const Entity& entity) const;
5557

5658
Variant input_;
5759
mutable std::optional<Snapshot> snapshot_;

0 commit comments

Comments
 (0)