mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
When snapshotting a surface, upper-bound the render target size to the device limit. (flutter/engine#25213)
This commit is contained in:
parent
4f3e691b5a
commit
ace4d489a0
@ -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
|
||||
|
||||
@ -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);
|
||||
}));
|
||||
}
|
||||
|
||||
@ -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",
|
||||
]
|
||||
|
||||
@ -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 |
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user