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

Commit 6e983b3

Browse files
authored
[Impeller] added mipmaps to subpasses directly on a draw call (#50157)
fixes flutter/flutter#142001 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
1 parent e0237a0 commit 6e983b3

26 files changed

Lines changed: 141 additions & 46 deletions

impeller/aiks/aiks_unittests.cc

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2750,7 +2750,7 @@ TEST_P(AiksTest, CanRenderClippedBlur) {
27502750
.color = Color::Green(),
27512751
.image_filter = ImageFilter::MakeBlur(
27522752
Sigma(20.0), Sigma(20.0), FilterContents::BlurStyle::kNormal,
2753-
Entity::TileMode::kClamp),
2753+
Entity::TileMode::kDecal),
27542754
});
27552755
canvas.Restore();
27562756

@@ -3960,6 +3960,48 @@ TEST_P(AiksTest, GaussianBlurMipMapImageFilter) {
39603960
#endif
39613961
}
39623962

3963+
TEST_P(AiksTest, GaussianBlurMipMapSolidColor) {
3964+
size_t blur_required_mip_count =
3965+
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
3966+
fml::testing::LogCapture log_capture;
3967+
Canvas canvas;
3968+
canvas.DrawPath(PathBuilder{}
3969+
.MoveTo({100, 100})
3970+
.LineTo({200, 100})
3971+
.LineTo({150, 200})
3972+
.LineTo({50, 200})
3973+
.Close()
3974+
.TakePath(),
3975+
{.color = Color::Chartreuse(),
3976+
.image_filter = ImageFilter::MakeBlur(
3977+
Sigma(30), Sigma(30), FilterContents::BlurStyle::kNormal,
3978+
Entity::TileMode::kClamp)});
3979+
3980+
Picture picture = canvas.EndRecordingAsPicture();
3981+
std::shared_ptr<RenderTargetCache> cache =
3982+
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
3983+
AiksContext aiks_context(GetContext(), nullptr, cache);
3984+
picture.ToImage(aiks_context, {1024, 768});
3985+
3986+
size_t max_mip_count = 0;
3987+
for (auto it = cache->GetTextureDataBegin(); it != cache->GetTextureDataEnd();
3988+
++it) {
3989+
max_mip_count =
3990+
std::max(it->texture->GetTextureDescriptor().mip_count, max_mip_count);
3991+
}
3992+
EXPECT_EQ(max_mip_count, blur_required_mip_count);
3993+
// The log is FML_DLOG, so only check in debug builds.
3994+
#ifndef NDEBUG
3995+
if (GetParam() != PlaygroundBackend::kOpenGLES) {
3996+
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
3997+
std::string::npos);
3998+
} else {
3999+
EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
4000+
std::string::npos);
4001+
}
4002+
#endif
4003+
}
4004+
39634005
TEST_P(AiksTest, ImageColorSourceEffectTransform) {
39644006
// Compare with https://fiddle.skia.org/c/6cdc5aefb291fda3833b806ca347a885
39654007

impeller/display_list/dl_image_impeller.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ sk_sp<DlImageImpeller> DlImageImpeller::MakeFromYUVTextures(
3636
std::nullopt, // coverage_limit
3737
std::nullopt, // sampler_descriptor
3838
true, // msaa_enabled
39-
"MakeYUVToRGBFilter Snapshot"); // label
39+
/*mip_count=*/1,
40+
"MakeYUVToRGBFilter Snapshot"); // label
4041
if (!snapshot.has_value()) {
4142
return nullptr;
4243
}

impeller/entity/contents/atlas_contents.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ bool AtlasContents::Render(const ContentContext& renderer,
304304
std::nullopt, // coverage_limit
305305
std::nullopt, // sampler_descriptor
306306
true, // msaa_enabled
307+
/*mip_count=*/1,
307308
"AtlasContents Snapshot"); // label
308309
if (!snapshot.has_value()) {
309310
return false;

impeller/entity/contents/content_context.cc

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "impeller/renderer/pipeline_descriptor.h"
1616
#include "impeller/renderer/pipeline_library.h"
1717
#include "impeller/renderer/render_target.h"
18+
#include "impeller/renderer/texture_mipmap.h"
1819
#include "impeller/tessellator/tessellator.h"
1920
#include "impeller/typographer/typographer_context.h"
2021

@@ -429,20 +430,21 @@ fml::StatusOr<RenderTarget> ContentContext::MakeSubpass(
429430
const std::string& label,
430431
ISize texture_size,
431432
const SubpassCallback& subpass_callback,
432-
bool msaa_enabled) const {
433+
bool msaa_enabled,
434+
int32_t mip_count) const {
433435
const std::shared_ptr<Context>& context = GetContext();
434436
RenderTarget subpass_target;
435437
if (context->GetCapabilities()->SupportsOffscreenMSAA() && msaa_enabled) {
436438
subpass_target = RenderTarget::CreateOffscreenMSAA(
437-
*context, *GetRenderTargetCache(), texture_size, /*mip_count=*/1,
438-
SPrintF("%s Offscreen", label.c_str()),
439+
*context, *GetRenderTargetCache(), texture_size,
440+
/*mip_count=*/mip_count, SPrintF("%s Offscreen", label.c_str()),
439441
RenderTarget::kDefaultColorAttachmentConfigMSAA,
440442
std::nullopt // stencil_attachment_config
441443
);
442444
} else {
443445
subpass_target = RenderTarget::CreateOffscreen(
444-
*context, *GetRenderTargetCache(), texture_size, /*mip_count=*/1,
445-
SPrintF("%s Offscreen", label.c_str()),
446+
*context, *GetRenderTargetCache(), texture_size,
447+
/*mip_count=*/mip_count, SPrintF("%s Offscreen", label.c_str()),
446448
RenderTarget::kDefaultColorAttachmentConfig, //
447449
std::nullopt // stencil_attachment_config
448450
);
@@ -477,7 +479,21 @@ fml::StatusOr<RenderTarget> ContentContext::MakeSubpass(
477479
return fml::Status(fml::StatusCode::kUnknown, "");
478480
}
479481

480-
if (!sub_command_buffer->EncodeAndSubmit(sub_renderpass)) {
482+
if (!sub_renderpass->EncodeCommands()) {
483+
return fml::Status(fml::StatusCode::kUnknown, "");
484+
}
485+
486+
const std::shared_ptr<Texture>& target_texture =
487+
subpass_target.GetRenderTargetTexture();
488+
if (target_texture->GetMipCount() > 1) {
489+
fml::Status mipmap_status =
490+
AddMipmapGeneration(sub_command_buffer, context, target_texture);
491+
if (!mipmap_status.ok()) {
492+
return mipmap_status;
493+
}
494+
}
495+
496+
if (!sub_command_buffer->SubmitCommands()) {
481497
return fml::Status(fml::StatusCode::kUnknown, "");
482498
}
483499

impeller/entity/contents/content_context.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,8 @@ class ContentContext {
724724
const std::string& label,
725725
ISize texture_size,
726726
const SubpassCallback& subpass_callback,
727-
bool msaa_enabled = true) const;
727+
bool msaa_enabled = true,
728+
int32_t mip_count = 1) const;
728729

729730
/// Makes a subpass that will render to `subpass_target`.
730731
fml::StatusOr<RenderTarget> MakeSubpass(

impeller/entity/contents/contents.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ std::optional<Snapshot> Contents::RenderToSnapshot(
6060
std::optional<Rect> coverage_limit,
6161
const std::optional<SamplerDescriptor>& sampler_descriptor,
6262
bool msaa_enabled,
63+
int32_t mip_count,
6364
const std::string& label) const {
6465
auto coverage = GetCoverage(entity);
6566
if (!coverage.has_value()) {
@@ -90,7 +91,7 @@ std::optional<Snapshot> Contents::RenderToSnapshot(
9091
entity.GetTransform());
9192
return contents.Render(renderer, sub_entity, pass);
9293
},
93-
msaa_enabled);
94+
msaa_enabled, mip_count);
9495

9596
if (!render_target.ok()) {
9697
return std::nullopt;

impeller/entity/contents/contents.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class Contents {
121121
std::optional<Rect> coverage_limit = std::nullopt,
122122
const std::optional<SamplerDescriptor>& sampler_descriptor = std::nullopt,
123123
bool msaa_enabled = true,
124+
int32_t mip_count = 1,
124125
const std::string& label = "Snapshot") const;
125126

126127
virtual bool ShouldRender(const Entity& entity,

impeller/entity/contents/filters/filter_contents.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ std::shared_ptr<FilterContents> FilterContents::MakeDirectionalGaussianBlur(
5050
return blur;
5151
}
5252

53-
const int32_t FilterContents::kBlurFilterRequiredMipCount = 4;
53+
const int32_t FilterContents::kBlurFilterRequiredMipCount =
54+
GaussianBlurFilterContents::kBlurFilterRequiredMipCount;
5455

5556
std::shared_ptr<FilterContents> FilterContents::MakeGaussianBlur(
5657
const FilterInput::Ref& input,
@@ -262,6 +263,7 @@ std::optional<Snapshot> FilterContents::RenderToSnapshot(
262263
std::optional<Rect> coverage_limit,
263264
const std::optional<SamplerDescriptor>& sampler_descriptor,
264265
bool msaa_enabled,
266+
int32_t mip_count,
265267
const std::string& label) const {
266268
// Resolve the render instruction (entity) from the filter and render it to a
267269
// snapshot.
@@ -274,7 +276,8 @@ std::optional<Snapshot> FilterContents::RenderToSnapshot(
274276
coverage_limit, // coverage_limit
275277
std::nullopt, // sampler_descriptor
276278
true, // msaa_enabled
277-
label); // label
279+
/*mip_count=*/mip_count,
280+
label); // label
278281
}
279282

280283
return std::nullopt;

impeller/entity/contents/filters/filter_contents.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class FilterContents : public Contents {
131131
std::optional<Rect> coverage_limit = std::nullopt,
132132
const std::optional<SamplerDescriptor>& sampler_descriptor = std::nullopt,
133133
bool msaa_enabled = true,
134+
int32_t mip_count = 1,
134135
const std::string& label = "Filter Snapshot") const override;
135136

136137
// |Contents|

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ namespace impeller {
1919
using GaussianBlurVertexShader = KernelPipeline::VertexShader;
2020
using GaussianBlurFragmentShader = KernelPipeline::FragmentShader;
2121

22+
const int32_t GaussianBlurFilterContents::kBlurFilterRequiredMipCount = 4;
23+
2224
namespace {
2325

2426
SamplerDescriptor MakeSamplerDescriptor(MinMagFilter filter,
@@ -269,9 +271,18 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
269271
expanded_coverage_hint = coverage_hint->Expand(local_padding);
270272
}
271273

274+
int32_t mip_count = kBlurFilterRequiredMipCount;
275+
if (renderer.GetContext()->GetBackendType() ==
276+
Context::BackendType::kOpenGLES) {
277+
// TODO(https://github.com/flutter/flutter/issues/141732): Implement mip map
278+
// generation on opengles.
279+
mip_count = 1;
280+
}
281+
272282
std::optional<Snapshot> input_snapshot =
273283
inputs[0]->GetSnapshot("GaussianBlur", renderer, entity,
274-
/*coverage_limit=*/expanded_coverage_hint);
284+
/*coverage_limit=*/expanded_coverage_hint,
285+
/*mip_count=*/mip_count);
275286
if (!input_snapshot.has_value()) {
276287
return std::nullopt;
277288
}

0 commit comments

Comments
 (0)