Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 39f4ebd

Browse files
bderodnfield
authored andcommitted
Make the filter DAG render all textures at the correct resolution (#99)
1 parent 32b5a8d commit 39f4ebd

22 files changed

+609
-246
lines changed

impeller/aiks/aiks_unittests.cc

+1
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ TEST_F(AiksTest, TransformMultipliesCorrectly) {
442442
-3, 0, 0, 0,
443443
0, 0, 0, 0,
444444
-500, 400, 0, 1));
445+
// clang-format on
445446
}
446447

447448
} // namespace testing

impeller/entity/contents/contents.cc

+77
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
// found in the LICENSE file.
44

55
#include "impeller/entity/contents/contents.h"
6+
#include <optional>
67

78
#include "impeller/entity/contents/content_context.h"
9+
#include "impeller/renderer/command_buffer.h"
810
#include "impeller/renderer/render_pass.h"
911

1012
namespace impeller {
@@ -27,4 +29,79 @@ Contents::Contents() = default;
2729

2830
Contents::~Contents() = default;
2931

32+
Rect Contents::GetBounds(const Entity& entity) const {
33+
const auto& transform = entity.GetTransformation();
34+
auto points = entity.GetPath().GetBoundingBox()->GetPoints();
35+
for (uint i = 0; i < points.size(); i++) {
36+
points[i] = transform * points[i];
37+
}
38+
return Rect::MakePointBounds({points.begin(), points.end()});
39+
}
40+
41+
std::optional<Contents::Snapshot> Contents::RenderToTexture(
42+
const ContentContext& renderer,
43+
const Entity& entity) const {
44+
auto bounds = GetBounds(entity);
45+
46+
auto texture = MakeSubpass(
47+
renderer, ISize(bounds.size),
48+
[&contents = *this, &entity, &bounds](const ContentContext& renderer,
49+
RenderPass& pass) -> bool {
50+
Entity sub_entity;
51+
sub_entity.SetPath(entity.GetPath());
52+
sub_entity.SetBlendMode(Entity::BlendMode::kSource);
53+
sub_entity.SetTransformation(
54+
Matrix::MakeTranslation(Vector3(-bounds.origin)) *
55+
entity.GetTransformation());
56+
return contents.Render(renderer, sub_entity, pass);
57+
});
58+
59+
if (!texture.has_value()) {
60+
return std::nullopt;
61+
}
62+
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;
105+
}
106+
30107
} // namespace impeller

impeller/entity/contents/contents.h

+30
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <vector>
1010

1111
#include "flutter/fml/macros.h"
12+
#include "impeller/geometry/rect.h"
13+
#include "impeller/renderer/texture.h"
1214

1315
namespace impeller {
1416

@@ -25,6 +27,14 @@ ContentContextOptions OptionsFromPassAndEntity(const RenderPass& pass,
2527

2628
class Contents {
2729
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+
2838
Contents();
2939

3040
virtual ~Contents();
@@ -33,6 +43,26 @@ class Contents {
3343
const Entity& entity,
3444
RenderPass& pass) const = 0;
3545

46+
/// @brief Get the bounding rectangle that this contents modifies in screen
47+
/// space.
48+
virtual Rect GetBounds(const Entity& entity) const;
49+
50+
/// @brief Render this contents to a texture, respecting the entity's
51+
/// transform, path, stencil depth, blend mode, etc.
52+
/// The result texture size is always the size of `GetBounds(entity)`.
53+
virtual std::optional<Snapshot> RenderToTexture(
54+
const ContentContext& renderer,
55+
const Entity& entity) const;
56+
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+
64+
protected:
65+
3666
private:
3767
FML_DISALLOW_COPY_AND_ASSIGN(Contents);
3868
};

impeller/entity/contents/filters/blend_filter_contents.cc

+73-52
Original file line numberDiff line numberDiff line change
@@ -20,42 +20,28 @@ using PipelineProc =
2020
std::shared_ptr<Pipeline> (ContentContext::*)(ContentContextOptions) const;
2121

2222
template <typename VS, typename FS>
23-
static void AdvancedBlendPass(std::shared_ptr<Texture> input_d,
24-
std::shared_ptr<Texture> input_s,
25-
std::shared_ptr<const Sampler> sampler,
26-
const ContentContext& renderer,
27-
RenderPass& pass,
28-
Command& cmd) {}
29-
30-
template <typename VS, typename FS>
31-
static bool AdvancedBlend(
32-
const std::vector<std::shared_ptr<Texture>>& input_textures,
33-
const ContentContext& renderer,
34-
RenderPass& pass,
35-
PipelineProc pipeline_proc) {
23+
static bool AdvancedBlend(const std::vector<Contents::Snapshot>& input_textures,
24+
const ContentContext& renderer,
25+
RenderPass& pass,
26+
PipelineProc pipeline_proc) {
3627
if (input_textures.size() < 2) {
3728
return false;
3829
}
3930

4031
auto& host_buffer = pass.GetTransientsBuffer();
4132

33+
auto size = pass.GetRenderTargetSize();
4234
VertexBufferBuilder<typename VS::PerVertexData> vtx_builder;
4335
vtx_builder.AddVertices({
4436
{Point(0, 0), Point(0, 0)},
45-
{Point(1, 0), Point(1, 0)},
46-
{Point(1, 1), Point(1, 1)},
37+
{Point(size.width, 0), Point(1, 0)},
38+
{Point(size.width, size.height), Point(1, 1)},
4739
{Point(0, 0), Point(0, 0)},
48-
{Point(1, 1), Point(1, 1)},
49-
{Point(0, 1), Point(0, 1)},
40+
{Point(size.width, size.height), Point(1, 1)},
41+
{Point(0, size.height), Point(0, 1)},
5042
});
5143
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
5244

53-
typename VS::FrameInfo frame_info;
54-
frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));
55-
56-
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
57-
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
58-
5945
auto options = OptionsFromPass(pass);
6046
options.blend_mode = Entity::BlendMode::kSource;
6147
std::shared_ptr<Pipeline> pipeline =
@@ -65,10 +51,27 @@ static bool AdvancedBlend(
6551
cmd.label = "Advanced Blend Filter";
6652
cmd.BindVertices(vtx_buffer);
6753
cmd.pipeline = std::move(pipeline);
68-
VS::BindFrameInfo(cmd, uniform_view);
6954

70-
FS::BindTextureSamplerDst(cmd, input_textures[0], sampler);
71-
FS::BindTextureSamplerSrc(cmd, input_textures[1], sampler);
55+
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
56+
typename VS::FrameInfo frame_info;
57+
frame_info.mvp = Matrix::MakeOrthographic(size);
58+
59+
auto dst_snapshot = input_textures[1];
60+
FS::BindTextureSamplerSrc(cmd, dst_snapshot.texture, sampler);
61+
frame_info.dst_uv_transform =
62+
Matrix::MakeTranslation(-dst_snapshot.position / size) *
63+
Matrix::MakeScale(
64+
Vector3(Size(size) / Size(dst_snapshot.texture->GetSize())));
65+
66+
auto src_snapshot = input_textures[0];
67+
FS::BindTextureSamplerDst(cmd, src_snapshot.texture, sampler);
68+
frame_info.src_uv_transform =
69+
Matrix::MakeTranslation(-src_snapshot.position / size) *
70+
Matrix::MakeScale(
71+
Vector3(Size(size) / Size(src_snapshot.texture->GetSize())));
72+
73+
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
74+
VS::BindFrameInfo(cmd, uniform_view);
7275
pass.AddCommand(cmd);
7376

7477
return true;
@@ -88,46 +91,42 @@ void BlendFilterContents::SetBlendMode(Entity::BlendMode blend_mode) {
8891

8992
switch (blend_mode) {
9093
case Entity::BlendMode::kScreen:
91-
advanced_blend_proc_ =
92-
[](const std::vector<std::shared_ptr<Texture>>& input_textures,
93-
const ContentContext& renderer, RenderPass& pass) {
94-
PipelineProc p = &ContentContext::GetTextureBlendScreenPipeline;
95-
return AdvancedBlend<TextureBlendScreenPipeline::VertexShader,
96-
TextureBlendScreenPipeline::FragmentShader>(
97-
input_textures, renderer, pass, p);
98-
};
94+
advanced_blend_proc_ = [](const std::vector<Snapshot>& input_textures,
95+
const ContentContext& renderer,
96+
RenderPass& pass) {
97+
PipelineProc p = &ContentContext::GetTextureBlendScreenPipeline;
98+
return AdvancedBlend<TextureBlendScreenPipeline::VertexShader,
99+
TextureBlendScreenPipeline::FragmentShader>(
100+
input_textures, renderer, pass, p);
101+
};
99102
break;
100103
default:
101104
FML_UNREACHABLE();
102105
}
103106
}
104107
}
105108

106-
static bool BasicBlend(
107-
const std::vector<std::shared_ptr<Texture>>& input_textures,
108-
const ContentContext& renderer,
109-
RenderPass& pass,
110-
Entity::BlendMode basic_blend) {
109+
static bool BasicBlend(const std::vector<Contents::Snapshot>& input_textures,
110+
const ContentContext& renderer,
111+
RenderPass& pass,
112+
Entity::BlendMode basic_blend) {
111113
using VS = TextureBlendPipeline::VertexShader;
112114
using FS = TextureBlendPipeline::FragmentShader;
113115

114116
auto& host_buffer = pass.GetTransientsBuffer();
115117

118+
auto size = pass.GetRenderTargetSize();
116119
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
117120
vtx_builder.AddVertices({
118121
{Point(0, 0), Point(0, 0)},
119-
{Point(1, 0), Point(1, 0)},
120-
{Point(1, 1), Point(1, 1)},
122+
{Point(size.width, 0), Point(1, 0)},
123+
{Point(size.width, size.height), Point(1, 1)},
121124
{Point(0, 0), Point(0, 0)},
122-
{Point(1, 1), Point(1, 1)},
123-
{Point(0, 1), Point(0, 1)},
125+
{Point(size.width, size.height), Point(1, 1)},
126+
{Point(0, size.height), Point(0, 1)},
124127
});
125128
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
126129

127-
VS::FrameInfo frame_info;
128-
frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));
129-
130-
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
131130
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
132131

133132
// Draw the first texture using kSource.
@@ -138,8 +137,19 @@ static bool BasicBlend(
138137
auto options = OptionsFromPass(pass);
139138
options.blend_mode = Entity::BlendMode::kSource;
140139
cmd.pipeline = renderer.GetTextureBlendPipeline(options);
141-
FS::BindTextureSamplerSrc(cmd, input_textures[0], sampler);
142-
VS::BindFrameInfo(cmd, uniform_view);
140+
{
141+
auto input = input_textures[0];
142+
FS::BindTextureSamplerSrc(cmd, input.texture, sampler);
143+
144+
VS::FrameInfo frame_info;
145+
frame_info.mvp =
146+
Matrix::MakeOrthographic(size) *
147+
Matrix::MakeTranslation(input.position) *
148+
Matrix::MakeScale(Size(input.texture->GetSize()) / Size(size));
149+
150+
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
151+
VS::BindFrameInfo(cmd, uniform_view);
152+
}
143153
pass.AddCommand(cmd);
144154

145155
if (input_textures.size() < 2) {
@@ -153,17 +163,28 @@ static bool BasicBlend(
153163

154164
for (auto texture_i = input_textures.begin() + 1;
155165
texture_i < input_textures.end(); texture_i++) {
156-
FS::BindTextureSamplerSrc(cmd, *texture_i, sampler);
166+
auto input = *texture_i;
167+
FS::BindTextureSamplerSrc(cmd, input.texture, sampler);
168+
169+
VS::FrameInfo frame_info;
170+
frame_info.mvp = frame_info.mvp =
171+
Matrix::MakeOrthographic(size) *
172+
Matrix::MakeTranslation(input.position) *
173+
Matrix::MakeScale(Size(input.texture->GetSize()) / Size(size));
174+
175+
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
176+
VS::BindFrameInfo(cmd, uniform_view);
157177
pass.AddCommand(cmd);
158178
}
159179

160180
return true;
161181
}
162182

163183
bool BlendFilterContents::RenderFilter(
164-
const std::vector<std::shared_ptr<Texture>>& input_textures,
184+
const std::vector<Snapshot>& input_textures,
165185
const ContentContext& renderer,
166-
RenderPass& pass) const {
186+
RenderPass& pass,
187+
const Matrix& transform) const {
167188
if (input_textures.empty()) {
168189
return true;
169190
}

impeller/entity/contents/filters/blend_filter_contents.h

+7-6
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ namespace impeller {
1010

1111
class BlendFilterContents : public FilterContents {
1212
public:
13-
using AdvancedBlendProc = std::function<bool(
14-
const std::vector<std::shared_ptr<Texture>>& input_textures,
15-
const ContentContext& renderer,
16-
RenderPass& pass)>;
13+
using AdvancedBlendProc =
14+
std::function<bool(const std::vector<Snapshot>& input_textures,
15+
const ContentContext& renderer,
16+
RenderPass& pass)>;
1717

1818
BlendFilterContents();
1919

@@ -23,9 +23,10 @@ class BlendFilterContents : public FilterContents {
2323

2424
private:
2525
// |FilterContents|
26-
bool RenderFilter(const std::vector<std::shared_ptr<Texture>>& input_textures,
26+
bool RenderFilter(const std::vector<Snapshot>& input_textures,
2727
const ContentContext& renderer,
28-
RenderPass& pass) const override;
28+
RenderPass& pass,
29+
const Matrix& transform) const override;
2930

3031
Entity::BlendMode blend_mode_;
3132
AdvancedBlendProc advanced_blend_proc_;

0 commit comments

Comments
 (0)