Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b803359
[Impeller] new blur: added mipmap generation
gaaclarke Jan 8, 2024
6f20569
added lod parameter
gaaclarke Jan 8, 2024
92859a2
started sending the correct lod
gaaclarke Jan 8, 2024
48522bb
textureLod
gaaclarke Jan 8, 2024
7b248f7
hack to set mip level to 4
gaaclarke Jan 9, 2024
cd3136d
started invalidating mipmaps
gaaclarke Jan 9, 2024
8bf8bb9
Added texture_mipmap
gaaclarke Jan 10, 2024
97f5799
moved mipmap generation to the spots identified by brandon
gaaclarke Jan 10, 2024
80813fe
moved mipmap generation to the inline pass context
gaaclarke Jan 10, 2024
2b5790e
format
gaaclarke Jan 10, 2024
7204e7c
removed logs
gaaclarke Jan 10, 2024
afdc277
Removed invalidation and updated the docstring on NeedsMipmapGeneration
gaaclarke Jan 11, 2024
6aa39c3
brought over the mip_count parameter to non msaa paths
gaaclarke Jan 11, 2024
6896e32
added todo
gaaclarke Jan 11, 2024
e59dc8c
license
gaaclarke Jan 11, 2024
3f52295
added decal lod support
gaaclarke Jan 11, 2024
a61094b
removed check for needsmipmapgeneration
gaaclarke Jan 12, 2024
1930bfd
Revert "added decal lod support"
gaaclarke Jan 12, 2024
c42daef
removed explicit lod
gaaclarke Jan 12, 2024
eb84964
only started incrementing the mip_count if we are using blur
gaaclarke Jan 12, 2024
039b1b4
put the mipcount behind the flag for the new blur
gaaclarke Jan 12, 2024
f13d449
added test
gaaclarke Jan 12, 2024
345cb30
turned off hack
gaaclarke Jan 12, 2024
b04debf
fixed linux usage of mip_count
gaaclarke Jan 12, 2024
12a1d30
added another test for setting mip count levels
gaaclarke Jan 12, 2024
4bea7dc
added another test
gaaclarke Jan 12, 2024
9bf4355
removed todo
gaaclarke Jan 12, 2024
7cba038
updated comment
gaaclarke Jan 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -5553,6 +5553,8 @@ ORIGIN: ../../../flutter/impeller/renderer/snapshot.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/stroke.comp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/surface.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/surface.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/texture_mipmap.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/texture_mipmap.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/threadgroup_sizing_test.comp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/vertex_buffer_builder.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/vertex_buffer_builder.h + ../../../flutter/LICENSE
Expand Down Expand Up @@ -8381,6 +8383,8 @@ FILE: ../../../flutter/impeller/renderer/snapshot.h
FILE: ../../../flutter/impeller/renderer/stroke.comp
FILE: ../../../flutter/impeller/renderer/surface.cc
FILE: ../../../flutter/impeller/renderer/surface.h
FILE: ../../../flutter/impeller/renderer/texture_mipmap.cc
FILE: ../../../flutter/impeller/renderer/texture_mipmap.h
FILE: ../../../flutter/impeller/renderer/threadgroup_sizing_test.comp
FILE: ../../../flutter/impeller/renderer/vertex_buffer_builder.cc
FILE: ../../../flutter/impeller/renderer/vertex_buffer_builder.h
Expand Down
8 changes: 6 additions & 2 deletions impeller/aiks/aiks_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ namespace impeller {

AiksContext::AiksContext(
std::shared_ptr<Context> context,
std::shared_ptr<TypographerContext> typographer_context)
std::shared_ptr<TypographerContext> typographer_context,
std::optional<std::shared_ptr<RenderTargetAllocator>>
render_target_allocator)
: context_(std::move(context)) {
if (!context_ || !context_->IsValid()) {
return;
}

content_context_ = std::make_unique<ContentContext>(
context_, std::move(typographer_context));
context_, std::move(typographer_context),
render_target_allocator.has_value() ? render_target_allocator.value()
: nullptr);
if (!content_context_->IsValid()) {
return;
}
Expand Down
6 changes: 5 additions & 1 deletion impeller/aiks/aiks_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ class AiksContext {
/// `nullptr` is supplied, then attempting to draw
/// text with Aiks will result in validation
/// errors.
/// @param render_target_allocator Injects a render target allocator or
/// allocates its own if none is supplied.
AiksContext(std::shared_ptr<Context> context,
std::shared_ptr<TypographerContext> typographer_context);
std::shared_ptr<TypographerContext> typographer_context,
std::optional<std::shared_ptr<RenderTargetAllocator>>
render_target_allocator = std::nullopt);

~AiksContext();

Expand Down
78 changes: 78 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "flutter/impeller/aiks/aiks_unittests.h"

#include <algorithm>
#include <array>
#include <cmath>
#include <cstdlib>
Expand All @@ -26,6 +27,7 @@
#include "impeller/entity/contents/radial_gradient_contents.h"
#include "impeller/entity/contents/solid_color_contents.h"
#include "impeller/entity/contents/sweep_gradient_contents.h"
#include "impeller/entity/render_target_cache.h"
#include "impeller/geometry/color.h"
#include "impeller/geometry/constants.h"
#include "impeller/geometry/geometry_asserts.h"
Expand Down Expand Up @@ -3716,5 +3718,81 @@ TEST_P(AiksTest, SubpassWithClearColorOptimization) {
// will be filled with NaNs and may produce a magenta texture on macOS or iOS.
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, GuassianBlurUpdatesMipmapContents) {
// This makes sure if mip maps are recycled across invocations of blurs the
// contents get updated each frame correctly. If they aren't updated the color
// inside the blur and outside the blur will be different.
//
// If there is some change to render target caching this could display a false
// positive in the future. Also, if the LOD that is rendered is 1 it could
// present a false positive.
int32_t count = 0;
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
Canvas canvas;
if (count++ == 0) {
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
} else {
canvas.DrawCircle({100, 100}, 50, {.color = Color::Chartreuse()});
}
canvas.ClipRRect(Rect::MakeLTRB(75, 50, 375, 275), {20, 20});
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
ImageFilter::MakeBlur(Sigma(30.0), Sigma(30.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
canvas.Restore();
return canvas.EndRecordingAsPicture();
};

ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_P(AiksTest, GaussianBlurSetsMipCountOnPass) {
Canvas canvas;
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
canvas.SaveLayer({}, std::nullopt,
ImageFilter::MakeBlur(Sigma(3), Sigma(3),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
canvas.Restore();

Picture picture = canvas.EndRecordingAsPicture();

int32_t max_mip_count = 0;
picture.pass->IterateAllElements([&](EntityPass::Element& element) -> bool {
if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
max_mip_count =
std::max(max_mip_count, subpass->get()->GetRequiredMipCount());
}
return true;
});

EXPECT_EQ(1, max_mip_count);
}

TEST_P(AiksTest, GaussianBlurAllocatesCorrectMipCountRenderTarget) {
Canvas canvas;
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
canvas.SaveLayer({}, std::nullopt,
ImageFilter::MakeBlur(Sigma(3), Sigma(3),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
canvas.Restore();

Picture picture = canvas.EndRecordingAsPicture();
std::shared_ptr<RenderTargetCache> cache =
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
AiksContext aiks_context(GetContext(), nullptr, cache);
picture.ToImage(aiks_context, {100, 100});

size_t max_mip_count = 0;
for (auto it = cache->GetTextureDataBegin(); it != cache->GetTextureDataEnd();
++it) {
max_mip_count =
std::max(it->texture->GetTextureDescriptor().mip_count, max_mip_count);
}
EXPECT_EQ(max_mip_count, 1lu);
}

} // namespace testing
} // namespace impeller
34 changes: 34 additions & 0 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,37 @@ void Canvas::Save() {
Save(false);
}

namespace {
class MipCountVisitor : public ImageFilterVisitor {
public:
virtual void Visit(const BlurImageFilter& filter) {
required_mip_count_ = FilterContents::kBlurFilterRequiredMipCount;
}
virtual void Visit(const LocalMatrixImageFilter& filter) {
required_mip_count_ = 1;
}
virtual void Visit(const DilateImageFilter& filter) {
required_mip_count_ = 1;
}
virtual void Visit(const ErodeImageFilter& filter) {
required_mip_count_ = 1;
}
virtual void Visit(const MatrixImageFilter& filter) {
required_mip_count_ = 1;
}
virtual void Visit(const ComposeImageFilter& filter) {
required_mip_count_ = 1;
}
virtual void Visit(const ColorImageFilter& filter) {
required_mip_count_ = 1;
}
int32_t GetRequiredMipCount() const { return required_mip_count_; }

private:
int32_t required_mip_count_ = -1;
};
} // namespace

void Canvas::Save(bool create_subpass,
BlendMode blend_mode,
const std::shared_ptr<ImageFilter>& backdrop_filter) {
Expand All @@ -156,6 +187,9 @@ void Canvas::Save(bool create_subpass,
return filter;
};
subpass->SetBackdropFilter(backdrop_filter_proc);
MipCountVisitor mip_count_visitor;
backdrop_filter->Visit(mip_count_visitor);
subpass->SetRequiredMipCount(mip_count_visitor.GetRequiredMipCount());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can work out the required mip level for the EntityPass texture in Canvas::Save without look-aheads later on.

  • When creating a new subpass:
    • If the new subpass has backdrop filter, assign the current pass (not the child pass being created) a new max mip level: GetCurrentPass().SetRequiredMipCount(std::max(GetCurrentPass().GetRequiredMipCount(), backdrop_filter_mip_count))
    • If the Canvas paint state has an image filter, then initialize the max mip level of the subpass with the image filter's max mip level: subpass->SetRequiredMipCount(paint_image_filter_mip_count)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then, we just use subpass->required_mip_count_ in the two places where we provision the child pass texture in EntityPass.

}
subpass->SetBlendMode(blend_mode);
current_pass_ = GetCurrentPass().AddSubpass(std::move(subpass));
Expand Down
8 changes: 5 additions & 3 deletions impeller/aiks/picture.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,18 @@ std::shared_ptr<Texture> Picture::RenderToTexture(
*impeller_context, // context
render_target_allocator, // allocator
size, // size
/*mip_count=*/1,
"Picture Snapshot MSAA", // label
RenderTarget::
kDefaultColorAttachmentConfigMSAA, // color_attachment_config
std::nullopt // stencil_attachment_config
);
} else {
target = RenderTarget::CreateOffscreen(
*impeller_context, // context
render_target_allocator, // allocator
size, // size
*impeller_context, // context
render_target_allocator, // allocator
size, // size
/*mip_count=*/1,
"Picture Snapshot", // label
RenderTarget::kDefaultColorAttachmentConfig, // color_attachment_config
std::nullopt // stencil_attachment_config
Expand Down
3 changes: 3 additions & 0 deletions impeller/core/texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class Texture {

virtual Scalar GetYCoordScale() const;

/// Returns true if mipmaps have never been generated.
/// The contents of the mipmap may be out of date if the root texture has been
/// modified and the mipmaps hasn't been regenerated.
bool NeedsMipmapGeneration() const;

protected:
Expand Down
3 changes: 2 additions & 1 deletion impeller/entity/contents/checkerboard_contents_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ TEST_P(EntityTest, RendersWithoutError) {
auto buffer = content_context->GetContext()->CreateCommandBuffer();
auto render_target = RenderTarget::CreateOffscreenMSAA(
*content_context->GetContext(),
*GetContentContext()->GetRenderTargetCache(), {100, 100});
*GetContentContext()->GetRenderTargetCache(), {100, 100},
/*mip_count=*/1);
auto render_pass = buffer->CreateRenderPass(render_target);
Entity entity;

Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -418,14 +418,14 @@ fml::StatusOr<RenderTarget> ContentContext::MakeSubpass(
RenderTarget subpass_target;
if (context->GetCapabilities()->SupportsOffscreenMSAA() && msaa_enabled) {
subpass_target = RenderTarget::CreateOffscreenMSAA(
*context, *GetRenderTargetCache(), texture_size,
*context, *GetRenderTargetCache(), texture_size, /*mip_count=*/1,
SPrintF("%s Offscreen", label.c_str()),
RenderTarget::kDefaultColorAttachmentConfigMSAA,
std::nullopt // stencil_attachment_config
);
} else {
subpass_target = RenderTarget::CreateOffscreen(
*context, *GetRenderTargetCache(), texture_size,
*context, *GetRenderTargetCache(), texture_size, /*mip_count=*/1,
SPrintF("%s Offscreen", label.c_str()),
RenderTarget::kDefaultColorAttachmentConfig, //
std::nullopt // stencil_attachment_config
Expand Down
6 changes: 6 additions & 0 deletions impeller/entity/contents/filters/filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ std::shared_ptr<FilterContents> FilterContents::MakeDirectionalGaussianBlur(
return blur;
}

#ifdef IMPELLER_ENABLE_NEW_GAUSSIAN_FILTER
const int32_t FilterContents::kBlurFilterRequiredMipCount = 4;
#else
const int32_t FilterContents::kBlurFilterRequiredMipCount = 1;
#endif

std::shared_ptr<FilterContents> FilterContents::MakeGaussianBlur(
const FilterInput::Ref& input,
Sigma sigma_x,
Expand Down
2 changes: 2 additions & 0 deletions impeller/entity/contents/filters/filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ namespace impeller {

class FilterContents : public Contents {
public:
static const int32_t kBlurFilterRequiredMipCount;

enum class BlurStyle {
/// Blurred inside and outside.
kNormal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/renderer/command.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/texture_mipmap.h"
#include "impeller/renderer/vertex_buffer_builder.h"

namespace impeller {
Expand Down Expand Up @@ -192,7 +193,6 @@ Rect MakeReferenceUVs(const Rect& reference, const Rect& rect) {
rect.GetSize());
return result.Scale(1.0f / Vector2(reference.GetSize()));
}

} // namespace

GaussianBlurFilterContents::GaussianBlurFilterContents(
Expand Down Expand Up @@ -284,6 +284,12 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
entity.GetClipDepth()); // No blur to render.
}

// In order to avoid shimmering in downsampling step, we should have mips.
if (input_snapshot->texture->GetMipCount() <= 1) {
FML_DLOG(ERROR) << "Applying gaussian blur without mipmap.";
}
FML_DCHECK(!input_snapshot->texture->NeedsMipmapGeneration());

Scalar desired_scalar =
std::min(CalculateScale(scaled_sigma.x), CalculateScale(scaled_sigma.y));
// TODO(jonahwilliams): If desired_scalar is 1.0 and we fully acquired the
Expand Down
6 changes: 4 additions & 2 deletions impeller/entity/contents/scene_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ bool SceneContents::Render(const ContentContext& renderer,
*renderer.GetContext(), // context
*renderer.GetRenderTargetCache(), // allocator
ISize(coverage.value().GetSize()), // size
"SceneContents", // label
/*mip_count=*/1,
"SceneContents", // label
RenderTarget::AttachmentConfigMSAA{
.storage_mode = StorageMode::kDeviceTransient,
.resolve_storage_mode = StorageMode::kDevicePrivate,
Expand All @@ -68,7 +69,8 @@ bool SceneContents::Render(const ContentContext& renderer,
*renderer.GetContext(), // context
*renderer.GetRenderTargetCache(), // allocator
ISize(coverage.value().GetSize()), // size
"SceneContents", // label
/*mip_count=*/1,
"SceneContents", // label
RenderTarget::AttachmentConfig{
.storage_mode = StorageMode::kDevicePrivate,
.load_action = LoadAction::kClear,
Expand Down
6 changes: 4 additions & 2 deletions impeller/entity/contents/tiled_texture_contents_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ TEST_P(EntityTest, TiledTextureContentsRendersWithCorrectPipeline) {
auto buffer = content_context->GetContext()->CreateCommandBuffer();
auto render_target = RenderTarget::CreateOffscreenMSAA(
*content_context->GetContext(),
*GetContentContext()->GetRenderTargetCache(), {100, 100});
*GetContentContext()->GetRenderTargetCache(), {100, 100},
/*mip_count=*/1);
auto render_pass = buffer->CreateRenderPass(render_target);

ASSERT_TRUE(contents.Render(*GetContentContext(), {}, *render_pass));
Expand Down Expand Up @@ -68,7 +69,8 @@ TEST_P(EntityTest, TiledTextureContentsRendersWithCorrectPipelineExternalOES) {
auto buffer = content_context->GetContext()->CreateCommandBuffer();
auto render_target = RenderTarget::CreateOffscreenMSAA(
*content_context->GetContext(),
*GetContentContext()->GetRenderTargetCache(), {100, 100});
*GetContentContext()->GetRenderTargetCache(), {100, 100},
/*mip_count=*/1);
auto render_pass = buffer->CreateRenderPass(render_target);

ASSERT_TRUE(contents.Render(*GetContentContext(), {}, *render_pass));
Expand Down
3 changes: 2 additions & 1 deletion impeller/entity/contents/vertices_contents_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ TEST_P(EntityTest, RendersDstPerColorWithAlpha) {
auto buffer = content_context->GetContext()->CreateCommandBuffer();
auto render_target = RenderTarget::CreateOffscreenMSAA(
*content_context->GetContext(),
*GetContentContext()->GetRenderTargetCache(), {100, 100});
*GetContentContext()->GetRenderTargetCache(), {100, 100},
/*mip_count=*/1);
auto render_pass = buffer->CreateRenderPass(render_target);
Entity entity;

Expand Down
Loading