When snapshotting a surface, upper-bound the render target size to the device limit. (flutter/engine#25213)

This commit is contained in:
Brandon DeRosier 2021-03-29 13:54:02 -07:00 committed by GitHub
parent 4f3e691b5a
commit ace4d489a0
7 changed files with 109 additions and 5 deletions

View File

@ -1227,6 +1227,7 @@ FILE: ../../../flutter/shell/platform/embedder/fixtures/gradient_xform.png
FILE: ../../../flutter/shell/platform/embedder/fixtures/main.dart
FILE: ../../../flutter/shell/platform/embedder/fixtures/scene_without_custom_compositor.png
FILE: ../../../flutter/shell/platform/embedder/fixtures/scene_without_custom_compositor_with_xform.png
FILE: ../../../flutter/shell/platform/embedder/fixtures/snapshot_large_scene.png
FILE: ../../../flutter/shell/platform/embedder/fixtures/verifyb143464703.png
FILE: ../../../flutter/shell/platform/embedder/fixtures/verifyb143464703_soft_noxform.png
FILE: ../../../flutter/shell/platform/embedder/platform_view_embedder.cc

View File

@ -4,6 +4,7 @@
#include "flutter/shell/common/rasterizer.h"
#include <algorithm>
#include <utility>
#include "flutter/common/graphics/persistent_cache.h"
@ -270,13 +271,30 @@ sk_sp<SkImage> Rasterizer::DoMakeRasterSnapshot(
return;
}
GrRecordingContext* context = surface_->GetContext();
auto max_size = context->maxRenderTargetSize();
double scale_factor = std::min(
1.0, static_cast<double>(max_size) /
static_cast<double>(std::max(image_info.width(),
image_info.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) {
image_info = image_info.makeWH(
static_cast<double>(image_info.width()) * scale_factor,
static_cast<double>(image_info.height()) * scale_factor);
}
// When there is an on screen surface, we need a render target
// SkSurface because we want to access texture backed images.
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
surface_->GetContext(), // context
SkBudgeted::kNo, // budgeted
image_info // image info
);
sk_sp<SkSurface> surface =
SkSurface::MakeRenderTarget(context, // context
SkBudgeted::kNo, // budgeted
image_info // image info
);
surface->getCanvas()->scale(scale_factor, scale_factor);
result = DrawSnapshot(surface, draw_callback);
}));
}

View File

@ -164,6 +164,7 @@ test_fixtures("fixtures") {
"fixtures/gradient_xform.png",
"fixtures/scene_without_custom_compositor.png",
"fixtures/scene_without_custom_compositor_with_xform.png",
"fixtures/snapshot_large_scene.png",
"fixtures/verifyb143464703.png",
"fixtures/verifyb143464703_soft_noxform.png",
]

View File

@ -879,3 +879,39 @@ void nativeArgumentsCallback(List<String> args) native 'NativeArgumentsCallback'
void dart_entrypoint_args(List<String> args) {
nativeArgumentsCallback(args);
}
void snapshotsCallback(Image big_image, Image small_image) native 'SnapshotsCallback';
@pragma('vm:entry-point')
void snapshot_large_scene(int max_size) async {
// Set width to double the max size, which will result in height being half the max size after scaling.
double width = max_size * 2.0, height = max_size.toDouble();
PictureRecorder recorder = PictureRecorder();
{
Canvas canvas = Canvas(recorder, Rect.fromLTWH(0, 0, width, height));
Paint paint = Paint();
// Bottom left
paint.color = Color.fromARGB(255, 100, 255, 100);
canvas.drawRect(Rect.fromLTWH(0, height / 2, width / 2, height / 2), paint);
// Top right
paint.color = Color.fromARGB(255, 100, 100, 255);
canvas.drawRect(Rect.fromLTWH(width / 2, 0, width / 2, height / 2), paint);
}
Picture picture = recorder.endRecording();
Image big_image = await picture.toImage(width.toInt(), height.toInt());
// The max size varies across hardware/drivers, so normalize the result to a smaller target size in
// order to reliably test against an image fixture.
double small_width = 128, small_height = 64;
recorder = PictureRecorder();
{
Canvas canvas = Canvas(recorder, Rect.fromLTWH(0, 0, small_width, small_height));
canvas.scale(small_width / big_image.width);
canvas.drawImage(big_image, Offset.zero, Paint());
}
picture = recorder.endRecording();
Image small_image = await picture.toImage(small_width.toInt(), small_height.toInt());
snapshotsCallback(big_image, small_image);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

View File

@ -18,6 +18,7 @@
#include "flutter/fml/synchronization/count_down_latch.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/fml/thread.h"
#include "flutter/lib/ui/painting/image.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/shell/platform/embedder/tests/embedder_assertions.h"
#include "flutter/shell/platform/embedder/tests/embedder_config_builder.h"
@ -3399,5 +3400,48 @@ TEST_F(EmbedderTest, CompositorRenderTargetsNotRecycledWhenAvoidsCacheSet) {
ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
}
TEST_F(EmbedderTest, SnapshotRenderTargetScalesDownToDriverMax) {
auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
EmbedderConfigBuilder builder(context);
builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
builder.SetCompositor();
auto max_size = context.GetCompositor().GetGrContext()->maxRenderTargetSize();
context.AddIsolateCreateCallback([&]() {
Dart_Handle snapshot_large_scene = Dart_GetField(
Dart_RootLibrary(), tonic::ToDart("snapshot_large_scene"));
tonic::DartInvoke(snapshot_large_scene, {tonic::ToDart<int64_t>(max_size)});
});
fml::AutoResetWaitableEvent latch;
context.AddNativeCallback(
"SnapshotsCallback", CREATE_NATIVE_ENTRY(([&](Dart_NativeArguments args) {
auto get_arg = [&args](int index) {
Dart_Handle dart_image = Dart_GetNativeArgument(args, index);
Dart_Handle internal_image =
Dart_GetField(dart_image, tonic::ToDart("_image"));
return tonic::DartConverter<flutter::CanvasImage*>::FromDart(
internal_image);
};
CanvasImage* big_image = get_arg(0);
ASSERT_EQ(big_image->width(), max_size);
ASSERT_EQ(big_image->height(), max_size / 2);
CanvasImage* small_image = get_arg(1);
ASSERT_TRUE(ImageMatchesFixture("snapshot_large_scene.png",
small_image->image()));
latch.Signal();
})));
UniqueEngine engine = builder.LaunchEngine();
ASSERT_TRUE(engine.is_valid());
latch.Wait();
}
} // namespace testing
} // namespace flutter

View File

@ -834,6 +834,10 @@ fuchsia_test_archive("embedder_tests") {
path = "$root_gen_dir/flutter/shell/platform/embedder/assets/scene_without_custom_compositor_with_xform.png"
dest = "assets/scene_without_custom_compositor_with_xform.png"
},
{
path = "$root_gen_dir/flutter/shell/platform/embedder/assets/snapshot_large_scene.png"
dest = "assets/snapshot_large_scene.png"
},
{
path = "$root_gen_dir/flutter/shell/platform/embedder/assets/verifyb143464703.png"
dest = "assets/verifyb143464703.png"