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

[Impeller] implement experimental canvas in snapshot controller. #53750

Merged
merged 2 commits into from
Jul 9, 2024
Merged
Changes from 1 commit
Commits
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
104 changes: 77 additions & 27 deletions shell/common/snapshot_controller_impeller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#include "flutter/impeller/display_list/dl_image_impeller.h"
#include "flutter/impeller/geometry/size.h"
#include "flutter/shell/common/snapshot_controller.h"
#include "impeller/renderer/render_target.h"

#define EXPERIMENTAL_CANVAS false
Copy link
Member

Choose a reason for hiding this comment

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

Is there some context on why this isn't in a GN rule somewhere and applied globally instead of on a per TU basis?

Copy link
Member Author

Choose a reason for hiding this comment

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

factoring out to a gn rule seems like a good idea, will make it easier to flip on/off to see if there are any golden diffs or test failures.

Copy link
Member

Choose a reason for hiding this comment

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

Don't mean to block this patch though. We can do that later.

Copy link
Member Author

Choose a reason for hiding this comment

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

It was easy, done.


namespace flutter {

Expand All @@ -21,37 +24,84 @@ sk_sp<DlImage> DoMakeRasterSnapshot(
SkISize size,
const std::shared_ptr<impeller::AiksContext>& context) {
TRACE_EVENT0("flutter", __FUNCTION__);
if (!context) {
return nullptr;
}
// Determine render target size.
auto max_size = context->GetContext()
->GetResourceAllocator()
->GetMaxTextureSizeSupported();
double scale_factor_x =
static_cast<double>(max_size.width) / static_cast<double>(size.width());
double scale_factor_y =
static_cast<double>(max_size.height) / static_cast<double>(size.height());
double scale_factor = std::min(1.0, std::min(scale_factor_x, scale_factor_y));
Copy link
Member

Choose a reason for hiding this comment

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

IIRC, std::min has an overload that takes an initializer list. So you should be able do do just std::min({a, b, c}) instead of std::min(a, std::min(b, c)).

Copy link
Member Author

Choose a reason for hiding this comment

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

Done


auto render_target_size = impeller::ISize(size.width(), size.height());
Copy link
Member

Choose a reason for hiding this comment

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

Nit: TSize has a * operator overload that takes a scalar. So something like size * std::min<Scalar>({1.0, max.width / static_cast<Scalar>(size.width), max.height / static_cast<Scalar>(size.height)) might be more readable.


// Scale down the render target size to the max supported by the
// GPU if necessary. Exceeding the max would otherwise cause a
// null result.
if (scale_factor < 1.0) {
render_target_size.width *= scale_factor;
render_target_size.height *= scale_factor;
}

#if EXPERIMENTAL_CANVAS
// Do not use the render target cache as the lifecycle of this texture
// will outlive a particular frame.
impeller::ISize impeller_size = impeller::ISize(size.width(), size.height());
impeller::RenderTargetAllocator render_target_allocator =
impeller::RenderTargetAllocator(
context->GetContext()->GetResourceAllocator());
impeller::RenderTarget target;
if (context->GetContext()->GetCapabilities()->SupportsOffscreenMSAA()) {
target = render_target_allocator.CreateOffscreenMSAA(
*context->GetContext(), // context
impeller_size, // size
/*mip_count=*/1,
"Picture Snapshot MSAA", // label
impeller::RenderTarget::
Copy link
Member

Choose a reason for hiding this comment

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

Nit: This could perhaps be dried up using a ternary since only the last argument differs based on SupportsOffscreenMSAA and everything else is repeated.

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you mean adding a new CreateOffscreen that differentiates MSAA via an argument?

Copy link
Member

Choose a reason for hiding this comment

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

Nothing as involved as all that. Just context->GetContext()->GetCapabilities()->SupportsOffscreenMSAA() ? kDefaultColorAttachmentConfigMSAA : kDefaultColorAttachmentConfig

Copy link
Member Author

Choose a reason for hiding this comment

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

But the methods are different

Copy link
Member

Choose a reason for hiding this comment

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

derp. Sorry.

kDefaultColorAttachmentConfigMSAA // color_attachment_config
);
} else {
target = render_target_allocator.CreateOffscreen(
*context->GetContext(), // context
impeller_size, // size
/*mip_count=*/1,
"Picture Snapshot", // label
impeller::RenderTarget::
kDefaultColorAttachmentConfig // color_attachment_config
);
}

impeller::TextFrameDispatcher collector(context->GetContentContext(),
impeller::Matrix());
display_list->Dispatch(collector, SkIRect::MakeSize(size));
impeller::ExperimentalDlDispatcher impeller_dispatcher(
context->GetContentContext(), target,
display_list->root_has_backdrop_filter(),
display_list->max_root_blend_mode(),
impeller::IRect::MakeSize(impeller_size));
display_list->Dispatch(impeller_dispatcher, SkIRect::MakeSize(size));
impeller_dispatcher.FinishRecording();

context->GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames();

return impeller::DlImageImpeller::Make(target.GetRenderTargetTexture(),
DlImage::OwningContext::kRaster);
#else
impeller::DlDispatcher dispatcher;
display_list->Dispatch(dispatcher);
impeller::Picture picture = dispatcher.EndRecordingAsPicture();
if (context) {
auto max_size = context->GetContext()
->GetResourceAllocator()
->GetMaxTextureSizeSupported();
double scale_factor_x =
static_cast<double>(max_size.width) / static_cast<double>(size.width());
double scale_factor_y = static_cast<double>(max_size.height) /
static_cast<double>(size.height());
double scale_factor =
std::min(1.0, std::min(scale_factor_x, scale_factor_y));

auto render_target_size = impeller::ISize(size.width(), size.height());

// Scale down the render target size to the max supported by the
// GPU if necessary. Exceeding the max would otherwise cause a
// null result.
if (scale_factor < 1.0) {
render_target_size.width *= scale_factor;
render_target_size.height *= scale_factor;
}

std::shared_ptr<impeller::Image> image =
picture.ToImage(*context, render_target_size);
if (image) {
return impeller::DlImageImpeller::Make(image->GetTexture(),
DlImage::OwningContext::kRaster);
}

std::shared_ptr<impeller::Image> image =
picture.ToImage(*context, render_target_size);
if (image) {
return impeller::DlImageImpeller::Make(image->GetTexture(),
DlImage::OwningContext::kRaster);
}
#endif // EXPERIMENTAL_CANVAS

return nullptr;
}
Expand Down