Skip to content

Commit 82a3403

Browse files
bderodnfield
authored andcommitted
Make filter inputs lazy and sharable (flutter#103)
1 parent 9886da8 commit 82a3403

19 files changed

+447
-263
lines changed

impeller/entity/BUILD.gn

+4
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,14 @@ impeller_component("entity") {
4141
"contents/filters/blend_filter_contents.h",
4242
"contents/filters/filter_contents.cc",
4343
"contents/filters/filter_contents.h",
44+
"contents/filters/filter_input.cc",
45+
"contents/filters/filter_input.h",
4446
"contents/filters/gaussian_blur_filter_contents.cc",
4547
"contents/filters/gaussian_blur_filter_contents.h",
4648
"contents/linear_gradient_contents.cc",
4749
"contents/linear_gradient_contents.h",
50+
"contents/snapshot.cc",
51+
"contents/snapshot.h",
4852
"contents/solid_color_contents.cc",
4953
"contents/solid_color_contents.h",
5054
"contents/solid_stroke_contents.cc",

impeller/entity/contents/content_context.cc

+42
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
#include <sstream>
88

9+
#include "impeller/renderer/command_buffer.h"
10+
#include "impeller/renderer/render_pass.h"
11+
#include "impeller/renderer/render_target.h"
12+
913
namespace impeller {
1014

1115
ContentContext::ContentContext(std::shared_ptr<Context> context)
@@ -60,6 +64,44 @@ bool ContentContext::IsValid() const {
6064
return is_valid_;
6165
}
6266

67+
std::shared_ptr<Texture> ContentContext::MakeSubpass(
68+
ISize texture_size,
69+
SubpassCallback subpass_callback) const {
70+
auto context = GetContext();
71+
72+
auto subpass_target = RenderTarget::CreateOffscreen(*context, texture_size);
73+
auto subpass_texture = subpass_target.GetRenderTargetTexture();
74+
if (!subpass_texture) {
75+
return nullptr;
76+
}
77+
78+
auto sub_command_buffer = context->CreateRenderCommandBuffer();
79+
sub_command_buffer->SetLabel("Offscreen Contents Command Buffer");
80+
if (!sub_command_buffer) {
81+
return nullptr;
82+
}
83+
84+
auto sub_renderpass = sub_command_buffer->CreateRenderPass(subpass_target);
85+
if (!sub_renderpass) {
86+
return nullptr;
87+
}
88+
sub_renderpass->SetLabel("OffscreenContentsPass");
89+
90+
if (!subpass_callback(*this, *sub_renderpass)) {
91+
return nullptr;
92+
}
93+
94+
if (!sub_renderpass->EncodeCommands(*context->GetTransientsAllocator())) {
95+
return nullptr;
96+
}
97+
98+
if (!sub_command_buffer->SubmitCommands()) {
99+
return nullptr;
100+
}
101+
102+
return subpass_texture;
103+
}
104+
63105
std::shared_ptr<Context> ContentContext::GetContext() const {
64106
return context_;
65107
}

impeller/entity/contents/content_context.h

+8
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,14 @@ class ContentContext {
130130

131131
std::shared_ptr<Context> GetContext() const;
132132

133+
using SubpassCallback =
134+
std::function<bool(const ContentContext&, RenderPass&)>;
135+
136+
/// @brief Creates a new texture of size `texture_size` and calls
137+
/// `subpass_callback` with a `RenderPass` for drawing to the texture.
138+
std::shared_ptr<Texture> MakeSubpass(ISize texture_size,
139+
SubpassCallback subpass_callback) const;
140+
133141
private:
134142
std::shared_ptr<Context> context_;
135143

impeller/entity/contents/contents.cc

+5-46
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ Rect Contents::GetBounds(const Entity& entity) const {
3838
return Rect::MakePointBounds({points.begin(), points.end()});
3939
}
4040

41-
std::optional<Contents::Snapshot> Contents::RenderToTexture(
41+
std::optional<Snapshot> Contents::RenderToTexture(
4242
const ContentContext& renderer,
4343
const Entity& entity) const {
4444
auto bounds = GetBounds(entity);
4545

46-
auto texture = MakeSubpass(
47-
renderer, ISize(bounds.size),
46+
auto texture = renderer.MakeSubpass(
47+
ISize::Ceil(bounds.size),
4848
[&contents = *this, &entity, &bounds](const ContentContext& renderer,
4949
RenderPass& pass) -> bool {
5050
Entity sub_entity;
@@ -56,52 +56,11 @@ std::optional<Contents::Snapshot> Contents::RenderToTexture(
5656
return contents.Render(renderer, sub_entity, pass);
5757
});
5858

59-
if (!texture.has_value()) {
59+
if (!texture) {
6060
return std::nullopt;
6161
}
6262

63-
return Snapshot{.texture = texture.value(), .position = bounds.origin};
64-
}
65-
66-
using SubpassCallback = std::function<bool(const ContentContext&, RenderPass&)>;
67-
68-
std::optional<std::shared_ptr<Texture>> Contents::MakeSubpass(
69-
const ContentContext& renderer,
70-
ISize texture_size,
71-
SubpassCallback subpass_callback) {
72-
auto context = renderer.GetContext();
73-
74-
auto subpass_target = RenderTarget::CreateOffscreen(*context, texture_size);
75-
auto subpass_texture = subpass_target.GetRenderTargetTexture();
76-
if (!subpass_texture) {
77-
return std::nullopt;
78-
}
79-
80-
auto sub_command_buffer = context->CreateRenderCommandBuffer();
81-
sub_command_buffer->SetLabel("Offscreen Contents Command Buffer");
82-
if (!sub_command_buffer) {
83-
return std::nullopt;
84-
}
85-
86-
auto sub_renderpass = sub_command_buffer->CreateRenderPass(subpass_target);
87-
if (!sub_renderpass) {
88-
return std::nullopt;
89-
}
90-
sub_renderpass->SetLabel("OffscreenContentsPass");
91-
92-
if (!subpass_callback(renderer, *sub_renderpass)) {
93-
return std::nullopt;
94-
}
95-
96-
if (!sub_renderpass->EncodeCommands(*context->GetTransientsAllocator())) {
97-
return std::nullopt;
98-
}
99-
100-
if (!sub_command_buffer->SubmitCommands()) {
101-
return std::nullopt;
102-
}
103-
104-
return subpass_texture;
63+
return Snapshot{.texture = texture, .position = bounds.origin};
10564
}
10665

10766
} // namespace impeller

impeller/entity/contents/contents.h

+1-15
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <vector>
1010

1111
#include "flutter/fml/macros.h"
12+
#include "impeller/entity/contents/snapshot.h"
1213
#include "impeller/geometry/rect.h"
1314
#include "impeller/renderer/texture.h"
1415

@@ -27,14 +28,6 @@ ContentContextOptions OptionsFromPassAndEntity(const RenderPass& pass,
2728

2829
class Contents {
2930
public:
30-
/// Represents a screen space texture and it's intended draw position.
31-
struct Snapshot {
32-
std::shared_ptr<Texture> texture;
33-
/// The offset from the origin where this texture is intended to be
34-
/// rendered.
35-
Vector2 position;
36-
};
37-
3831
Contents();
3932

4033
virtual ~Contents();
@@ -54,13 +47,6 @@ class Contents {
5447
const ContentContext& renderer,
5548
const Entity& entity) const;
5649

57-
using SubpassCallback =
58-
std::function<bool(const ContentContext&, RenderPass&)>;
59-
static std::optional<std::shared_ptr<Texture>> MakeSubpass(
60-
const ContentContext& renderer,
61-
ISize texture_size,
62-
SubpassCallback subpass_callback);
63-
6450
protected:
6551

6652
private:

impeller/entity/contents/filters/blend_filter_contents.cc

+43-35
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "impeller/entity/contents/filters/blend_filter_contents.h"
66

77
#include "impeller/entity/contents/content_context.h"
8+
#include "impeller/entity/contents/filters/filter_input.h"
89
#include "impeller/renderer/render_pass.h"
910
#include "impeller/renderer/sampler_library.h"
1011

@@ -20,11 +21,13 @@ using PipelineProc =
2021
std::shared_ptr<Pipeline> (ContentContext::*)(ContentContextOptions) const;
2122

2223
template <typename VS, typename FS>
23-
static bool AdvancedBlend(const std::vector<Contents::Snapshot>& input_textures,
24+
static bool AdvancedBlend(const FilterInput::Vector& inputs,
2425
const ContentContext& renderer,
26+
const Entity& entity,
2527
RenderPass& pass,
28+
const Rect& bounds,
2629
PipelineProc pipeline_proc) {
27-
if (input_textures.size() < 2) {
30+
if (inputs.size() < 2) {
2831
return false;
2932
}
3033

@@ -56,19 +59,21 @@ static bool AdvancedBlend(const std::vector<Contents::Snapshot>& input_textures,
5659
typename VS::FrameInfo frame_info;
5760
frame_info.mvp = Matrix::MakeOrthographic(size);
5861

59-
auto dst_snapshot = input_textures[1];
60-
FS::BindTextureSamplerSrc(cmd, dst_snapshot.texture, sampler);
62+
auto dst_snapshot = inputs[1]->GetSnapshot(renderer, entity);
63+
FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, sampler);
6164
frame_info.dst_uv_transform =
62-
Matrix::MakeTranslation(-dst_snapshot.position / size) *
65+
Matrix::MakeTranslation(-(dst_snapshot->position - bounds.origin) /
66+
size) *
6367
Matrix::MakeScale(
64-
Vector3(Size(size) / Size(dst_snapshot.texture->GetSize())));
68+
Vector3(Size(size) / Size(dst_snapshot->texture->GetSize())));
6569

66-
auto src_snapshot = input_textures[0];
67-
FS::BindTextureSamplerDst(cmd, src_snapshot.texture, sampler);
70+
auto src_snapshot = inputs[0]->GetSnapshot(renderer, entity);
71+
FS::BindTextureSamplerDst(cmd, src_snapshot->texture, sampler);
6872
frame_info.src_uv_transform =
69-
Matrix::MakeTranslation(-src_snapshot.position / size) *
73+
Matrix::MakeTranslation(-(src_snapshot->position - bounds.origin) /
74+
size) *
7075
Matrix::MakeScale(
71-
Vector3(Size(size) / Size(src_snapshot.texture->GetSize())));
76+
Vector3(Size(size) / Size(src_snapshot->texture->GetSize())));
7277

7378
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
7479
VS::BindFrameInfo(cmd, uniform_view);
@@ -91,13 +96,14 @@ void BlendFilterContents::SetBlendMode(Entity::BlendMode blend_mode) {
9196

9297
switch (blend_mode) {
9398
case Entity::BlendMode::kScreen:
94-
advanced_blend_proc_ = [](const std::vector<Snapshot>& input_textures,
99+
advanced_blend_proc_ = [](const FilterInput::Vector& inputs,
95100
const ContentContext& renderer,
96-
RenderPass& pass) {
101+
const Entity& entity, RenderPass& pass,
102+
const Rect& bounds) {
97103
PipelineProc p = &ContentContext::GetTextureBlendScreenPipeline;
98104
return AdvancedBlend<TextureBlendScreenPipeline::VertexShader,
99105
TextureBlendScreenPipeline::FragmentShader>(
100-
input_textures, renderer, pass, p);
106+
inputs, renderer, entity, pass, bounds, p);
101107
};
102108
break;
103109
default:
@@ -106,9 +112,11 @@ void BlendFilterContents::SetBlendMode(Entity::BlendMode blend_mode) {
106112
}
107113
}
108114

109-
static bool BasicBlend(const std::vector<Contents::Snapshot>& input_textures,
115+
static bool BasicBlend(const FilterInput::Vector& inputs,
110116
const ContentContext& renderer,
117+
const Entity& entity,
111118
RenderPass& pass,
119+
const Rect& bounds,
112120
Entity::BlendMode basic_blend) {
113121
using VS = TextureBlendPipeline::VertexShader;
114122
using FS = TextureBlendPipeline::FragmentShader;
@@ -138,21 +146,21 @@ static bool BasicBlend(const std::vector<Contents::Snapshot>& input_textures,
138146
options.blend_mode = Entity::BlendMode::kSource;
139147
cmd.pipeline = renderer.GetTextureBlendPipeline(options);
140148
{
141-
auto input = input_textures[0];
142-
FS::BindTextureSamplerSrc(cmd, input.texture, sampler);
149+
auto input = inputs[0]->GetSnapshot(renderer, entity);
150+
FS::BindTextureSamplerSrc(cmd, input->texture, sampler);
143151

144152
VS::FrameInfo frame_info;
145153
frame_info.mvp =
146154
Matrix::MakeOrthographic(size) *
147-
Matrix::MakeTranslation(input.position) *
148-
Matrix::MakeScale(Size(input.texture->GetSize()) / Size(size));
155+
Matrix::MakeTranslation(input->position - bounds.origin) *
156+
Matrix::MakeScale(Size(input->texture->GetSize()) / Size(size));
149157

150158
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
151159
VS::BindFrameInfo(cmd, uniform_view);
152160
}
153161
pass.AddCommand(cmd);
154162

155-
if (input_textures.size() < 2) {
163+
if (inputs.size() < 2) {
156164
return true;
157165
}
158166

@@ -161,16 +169,16 @@ static bool BasicBlend(const std::vector<Contents::Snapshot>& input_textures,
161169
options.blend_mode = basic_blend;
162170
cmd.pipeline = renderer.GetTextureBlendPipeline(options);
163171

164-
for (auto texture_i = input_textures.begin() + 1;
165-
texture_i < input_textures.end(); texture_i++) {
166-
auto input = *texture_i;
167-
FS::BindTextureSamplerSrc(cmd, input.texture, sampler);
172+
for (auto texture_i = inputs.begin() + 1; texture_i < inputs.end();
173+
texture_i++) {
174+
auto input = texture_i->get()->GetSnapshot(renderer, entity);
175+
FS::BindTextureSamplerSrc(cmd, input->texture, sampler);
168176

169177
VS::FrameInfo frame_info;
170178
frame_info.mvp = frame_info.mvp =
171179
Matrix::MakeOrthographic(size) *
172-
Matrix::MakeTranslation(input.position) *
173-
Matrix::MakeScale(Size(input.texture->GetSize()) / Size(size));
180+
Matrix::MakeTranslation(input->position - bounds.origin) *
181+
Matrix::MakeScale(Size(input->texture->GetSize()) / Size(size));
174182

175183
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
176184
VS::BindFrameInfo(cmd, uniform_view);
@@ -180,27 +188,27 @@ static bool BasicBlend(const std::vector<Contents::Snapshot>& input_textures,
180188
return true;
181189
}
182190

183-
bool BlendFilterContents::RenderFilter(
184-
const std::vector<Snapshot>& input_textures,
185-
const ContentContext& renderer,
186-
RenderPass& pass,
187-
const Matrix& transform) const {
188-
if (input_textures.empty()) {
191+
bool BlendFilterContents::RenderFilter(const FilterInput::Vector& inputs,
192+
const ContentContext& renderer,
193+
const Entity& entity,
194+
RenderPass& pass,
195+
const Rect& bounds) const {
196+
if (inputs.empty()) {
189197
return true;
190198
}
191199

192-
if (input_textures.size() == 1) {
200+
if (inputs.size() == 1) {
193201
// Nothing to blend.
194-
return BasicBlend(input_textures, renderer, pass,
202+
return BasicBlend(inputs, renderer, entity, pass, bounds,
195203
Entity::BlendMode::kSource);
196204
}
197205

198206
if (blend_mode_ <= Entity::BlendMode::kLastPipelineBlendMode) {
199-
return BasicBlend(input_textures, renderer, pass, blend_mode_);
207+
return BasicBlend(inputs, renderer, entity, pass, bounds, blend_mode_);
200208
}
201209

202210
if (blend_mode_ <= Entity::BlendMode::kLastAdvancedBlendMode) {
203-
return advanced_blend_proc_(input_textures, renderer, pass);
211+
return advanced_blend_proc_(inputs, renderer, entity, pass, bounds);
204212
}
205213

206214
FML_UNREACHABLE();

0 commit comments

Comments
 (0)