mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Fix damage calculation when not providing populate_existing_damage for gl embedder (flutter/engine#45611)
# Description This PR fixes the `gl_populate_existing_damage` in embedder.cc, which currently returns an empty rectangle when a full repaint is needed. This leads to the `frame_damage` being considered empty in rasterizer.cc, causing incorrect partial repaint within Flutter when `gl_populate_existing_damage` is not provided by the embedder. # Related Issue https://github.com/flutter/flutter/issues/119601 # Tests Add a new test. Also fixes damage calculation related tests in EmbedderTest by * Use a new Dart embedder fixture entry point `render_gradient_retained` which retains the old layer to make sure layer tree diff happens. * Add `latch.Wait()` after `SetGLPresentCallback` to make sure assertions have been executed. * Make `existing_damage_rects` static since it should be valid after `populate_existing_damage` returns.
This commit is contained in:
parent
c94d335b6b
commit
86b582a6bc
@ -27,8 +27,6 @@ struct GLFrameInfo {
|
||||
struct GLFBOInfo {
|
||||
// The frame buffer's ID.
|
||||
uint32_t fbo_id;
|
||||
// This boolean flags whether the returned FBO supports partial repaint.
|
||||
const bool partial_repaint_enabled;
|
||||
// The frame buffer's existing damage (i.e. damage since it was last used).
|
||||
const std::optional<SkIRect> existing_damage;
|
||||
};
|
||||
|
||||
@ -166,7 +166,6 @@ GLFBOInfo AndroidSurfaceGLSkia::GLContextFBO(GLFrameInfo frame_info) const {
|
||||
// The default window bound framebuffer on Android.
|
||||
return GLFBOInfo{
|
||||
.fbo_id = 0,
|
||||
.partial_repaint_enabled = onscreen_surface_->SupportsPartialRepaint(),
|
||||
.existing_damage = onscreen_surface_->InitialDamage(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -363,8 +363,7 @@ InferOpenGLPlatformViewCreationCallback(
|
||||
if (!populate_existing_damage) {
|
||||
return flutter::GLFBOInfo{
|
||||
.fbo_id = static_cast<uint32_t>(id),
|
||||
.partial_repaint_enabled = false,
|
||||
.existing_damage = SkIRect::MakeEmpty(),
|
||||
.existing_damage = std::nullopt,
|
||||
};
|
||||
}
|
||||
|
||||
@ -372,29 +371,22 @@ InferOpenGLPlatformViewCreationCallback(
|
||||
FlutterDamage existing_damage;
|
||||
populate_existing_damage(user_data, id, &existing_damage);
|
||||
|
||||
bool partial_repaint_enabled = true;
|
||||
SkIRect existing_damage_rect;
|
||||
std::optional<SkIRect> existing_damage_rect = std::nullopt;
|
||||
|
||||
// Verify that at least one damage rectangle was provided.
|
||||
if (existing_damage.num_rects <= 0 || existing_damage.damage == nullptr) {
|
||||
FML_LOG(INFO) << "No damage was provided. Forcing full repaint.";
|
||||
existing_damage_rect = SkIRect::MakeEmpty();
|
||||
partial_repaint_enabled = false;
|
||||
} else if (existing_damage.num_rects > 1) {
|
||||
// Log message notifying users that multi-damage is not yet available in
|
||||
// case they try to make use of it.
|
||||
FML_LOG(INFO) << "Damage with multiple rectangles not yet supported. "
|
||||
"Repainting the whole frame.";
|
||||
existing_damage_rect = SkIRect::MakeEmpty();
|
||||
partial_repaint_enabled = false;
|
||||
} else {
|
||||
existing_damage_rect = FlutterRectToSkIRect(*(existing_damage.damage));
|
||||
existing_damage_rect = SkIRect::MakeEmpty();
|
||||
for (size_t i = 0; i < existing_damage.num_rects; i++) {
|
||||
existing_damage_rect->join(
|
||||
FlutterRectToSkIRect(existing_damage.damage[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Pass the information about this FBO to the rendering backend.
|
||||
return flutter::GLFBOInfo{
|
||||
.fbo_id = static_cast<uint32_t>(id),
|
||||
.partial_repaint_enabled = partial_repaint_enabled,
|
||||
.existing_damage = existing_damage_rect,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1298,3 +1298,25 @@ void channel_listener_response() async {
|
||||
});
|
||||
signalNativeTest();
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
void render_gradient_retained() {
|
||||
OffsetEngineLayer? offsetLayer; // Retain the offset layer.
|
||||
PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
|
||||
Size size = Size(800.0, 600.0);
|
||||
|
||||
SceneBuilder builder = SceneBuilder();
|
||||
|
||||
offsetLayer = builder.pushOffset(0.0, 0.0, oldLayer: offsetLayer);
|
||||
|
||||
// display_list_layer will comparing the display_list
|
||||
// no need to retain the picture
|
||||
builder.addPicture(
|
||||
Offset(0.0, 0.0), CreateGradientBox(size)); // gradient - flutter
|
||||
|
||||
builder.pop();
|
||||
|
||||
PlatformDispatcher.instance.views.first.render(builder.build());
|
||||
};
|
||||
PlatformDispatcher.instance.scheduleFrame();
|
||||
}
|
||||
|
||||
@ -3655,7 +3655,7 @@ TEST_F(EmbedderTest,
|
||||
|
||||
EmbedderConfigBuilder builder(context);
|
||||
builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
|
||||
builder.SetDartEntrypoint("render_gradient");
|
||||
builder.SetDartEntrypoint("render_gradient_retained");
|
||||
builder.GetRendererConfig().open_gl.populate_existing_damage =
|
||||
[](void* context, const intptr_t id,
|
||||
FlutterDamage* existing_damage) -> void {
|
||||
@ -3668,7 +3668,8 @@ TEST_F(EmbedderTest,
|
||||
.SetGLPopulateExistingDamageCallback(
|
||||
[](const intptr_t id, FlutterDamage* existing_damage_ptr) {
|
||||
const size_t num_rects = 1;
|
||||
FlutterRect existing_damage_rects[num_rects] = {
|
||||
// The array must be valid after the callback returns.
|
||||
static FlutterRect existing_damage_rects[num_rects] = {
|
||||
FlutterRect{0, 0, 800, 600}};
|
||||
existing_damage_ptr->num_rects = num_rects;
|
||||
existing_damage_ptr->damage = existing_damage_rects;
|
||||
@ -3677,9 +3678,11 @@ TEST_F(EmbedderTest,
|
||||
auto engine = builder.LaunchEngine();
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
|
||||
fml::AutoResetWaitableEvent latch;
|
||||
|
||||
// First frame should be entirely rerendered.
|
||||
static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
|
||||
[](FlutterPresentInfo present_info) {
|
||||
[&](FlutterPresentInfo present_info) {
|
||||
const size_t num_rects = 1;
|
||||
ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->left, 0);
|
||||
@ -3692,6 +3695,8 @@ TEST_F(EmbedderTest,
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
|
||||
|
||||
latch.Signal();
|
||||
});
|
||||
|
||||
// Send a window metrics events so frames may be scheduled.
|
||||
@ -3702,12 +3707,13 @@ TEST_F(EmbedderTest,
|
||||
event.pixel_ratio = 1.0;
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
latch.Wait();
|
||||
|
||||
// Because it's the same as the first frame, the second frame damage should
|
||||
// be empty but, because there was a full existing buffer damage, the buffer
|
||||
// damage should be the entire screen.
|
||||
static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
|
||||
[](FlutterPresentInfo present_info) {
|
||||
[&](FlutterPresentInfo present_info) {
|
||||
const size_t num_rects = 1;
|
||||
ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->left, 0);
|
||||
@ -3720,10 +3726,13 @@ TEST_F(EmbedderTest,
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
|
||||
|
||||
latch.Signal();
|
||||
});
|
||||
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
latch.Wait();
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) {
|
||||
@ -3731,7 +3740,7 @@ TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) {
|
||||
|
||||
EmbedderConfigBuilder builder(context);
|
||||
builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
|
||||
builder.SetDartEntrypoint("render_gradient");
|
||||
builder.SetDartEntrypoint("render_gradient_retained");
|
||||
builder.GetRendererConfig().open_gl.populate_existing_damage =
|
||||
[](void* context, const intptr_t id,
|
||||
FlutterDamage* existing_damage) -> void {
|
||||
@ -3744,7 +3753,8 @@ TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) {
|
||||
.SetGLPopulateExistingDamageCallback(
|
||||
[](const intptr_t id, FlutterDamage* existing_damage_ptr) {
|
||||
const size_t num_rects = 1;
|
||||
FlutterRect existing_damage_rects[num_rects] = {
|
||||
// The array must be valid after the callback returns.
|
||||
static FlutterRect existing_damage_rects[num_rects] = {
|
||||
FlutterRect{0, 0, 0, 0}};
|
||||
existing_damage_ptr->num_rects = num_rects;
|
||||
existing_damage_ptr->damage = existing_damage_rects;
|
||||
@ -3753,9 +3763,11 @@ TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) {
|
||||
auto engine = builder.LaunchEngine();
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
|
||||
fml::AutoResetWaitableEvent latch;
|
||||
|
||||
// First frame should be entirely rerendered.
|
||||
static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
|
||||
[](FlutterPresentInfo present_info) {
|
||||
[&](FlutterPresentInfo present_info) {
|
||||
const size_t num_rects = 1;
|
||||
ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->left, 0);
|
||||
@ -3768,6 +3780,8 @@ TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) {
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
|
||||
|
||||
latch.Signal();
|
||||
});
|
||||
|
||||
// Send a window metrics events so frames may be scheduled.
|
||||
@ -3778,11 +3792,12 @@ TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) {
|
||||
event.pixel_ratio = 1.0;
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
latch.Wait();
|
||||
|
||||
// Because it's the same as the first frame, the second frame should not be
|
||||
// rerendered assuming there is no existing damage.
|
||||
static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
|
||||
[](FlutterPresentInfo present_info) {
|
||||
[&](FlutterPresentInfo present_info) {
|
||||
const size_t num_rects = 1;
|
||||
ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->left, 0);
|
||||
@ -3795,10 +3810,13 @@ TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) {
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->right, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->bottom, 0);
|
||||
|
||||
latch.Signal();
|
||||
});
|
||||
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
latch.Wait();
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) {
|
||||
@ -3806,7 +3824,7 @@ TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) {
|
||||
|
||||
EmbedderConfigBuilder builder(context);
|
||||
builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
|
||||
builder.SetDartEntrypoint("render_gradient");
|
||||
builder.SetDartEntrypoint("render_gradient_retained");
|
||||
builder.GetRendererConfig().open_gl.populate_existing_damage =
|
||||
[](void* context, const intptr_t id,
|
||||
FlutterDamage* existing_damage) -> void {
|
||||
@ -3817,9 +3835,10 @@ TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) {
|
||||
// Return existing damage as only part of the screen on purpose.
|
||||
static_cast<EmbedderTestContextGL&>(context)
|
||||
.SetGLPopulateExistingDamageCallback(
|
||||
[](const intptr_t id, FlutterDamage* existing_damage_ptr) {
|
||||
[&](const intptr_t id, FlutterDamage* existing_damage_ptr) {
|
||||
const size_t num_rects = 1;
|
||||
FlutterRect existing_damage_rects[num_rects] = {
|
||||
// The array must be valid after the callback returns.
|
||||
static FlutterRect existing_damage_rects[num_rects] = {
|
||||
FlutterRect{200, 150, 400, 300}};
|
||||
existing_damage_ptr->num_rects = num_rects;
|
||||
existing_damage_ptr->damage = existing_damage_rects;
|
||||
@ -3828,9 +3847,11 @@ TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) {
|
||||
auto engine = builder.LaunchEngine();
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
|
||||
fml::AutoResetWaitableEvent latch;
|
||||
|
||||
// First frame should be entirely rerendered.
|
||||
static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
|
||||
[](FlutterPresentInfo present_info) {
|
||||
[&](FlutterPresentInfo present_info) {
|
||||
const size_t num_rects = 1;
|
||||
ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->left, 0);
|
||||
@ -3843,6 +3864,8 @@ TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) {
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
|
||||
|
||||
latch.Signal();
|
||||
});
|
||||
|
||||
// Send a window metrics events so frames may be scheduled.
|
||||
@ -3853,12 +3876,13 @@ TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) {
|
||||
event.pixel_ratio = 1.0;
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
latch.Wait();
|
||||
|
||||
// Because it's the same as the first frame, the second frame damage should be
|
||||
// empty but, because there was a partial existing damage, the buffer damage
|
||||
// should represent that partial damage area.
|
||||
static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
|
||||
[](FlutterPresentInfo present_info) {
|
||||
[&](FlutterPresentInfo present_info) {
|
||||
const size_t num_rects = 1;
|
||||
ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->left, 0);
|
||||
@ -3871,10 +3895,13 @@ TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) {
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->top, 150);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->right, 400);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->bottom, 300);
|
||||
|
||||
latch.Signal();
|
||||
});
|
||||
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
latch.Wait();
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, PopulateExistingDamageReceivesValidID) {
|
||||
@ -3882,7 +3909,7 @@ TEST_F(EmbedderTest, PopulateExistingDamageReceivesValidID) {
|
||||
|
||||
EmbedderConfigBuilder builder(context);
|
||||
builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
|
||||
builder.SetDartEntrypoint("render_gradient");
|
||||
builder.SetDartEntrypoint("render_gradient_retained");
|
||||
builder.GetRendererConfig().open_gl.populate_existing_damage =
|
||||
[](void* context, const intptr_t id,
|
||||
FlutterDamage* existing_damage) -> void {
|
||||
@ -3900,6 +3927,8 @@ TEST_F(EmbedderTest, PopulateExistingDamageReceivesValidID) {
|
||||
[window_fbo_id = window_fbo_id](intptr_t id,
|
||||
FlutterDamage* existing_damage) {
|
||||
ASSERT_EQ(id, window_fbo_id);
|
||||
existing_damage->num_rects = 0;
|
||||
existing_damage->damage = nullptr;
|
||||
});
|
||||
|
||||
// Send a window metrics events so frames may be scheduled.
|
||||
@ -3917,7 +3946,7 @@ TEST_F(EmbedderTest, PopulateExistingDamageReceivesInvalidID) {
|
||||
|
||||
EmbedderConfigBuilder builder(context);
|
||||
builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
|
||||
builder.SetDartEntrypoint("render_gradient");
|
||||
builder.SetDartEntrypoint("render_gradient_retained");
|
||||
builder.GetRendererConfig().open_gl.populate_existing_damage =
|
||||
[](void* context, const intptr_t id,
|
||||
FlutterDamage* existing_damage) -> void {
|
||||
@ -3946,6 +3975,8 @@ TEST_F(EmbedderTest, PopulateExistingDamageReceivesInvalidID) {
|
||||
[window_fbo_id = window_fbo_id](intptr_t id,
|
||||
FlutterDamage* existing_damage) {
|
||||
ASSERT_NE(id, window_fbo_id);
|
||||
existing_damage->num_rects = 0;
|
||||
existing_damage->damage = nullptr;
|
||||
});
|
||||
|
||||
// Send a window metrics events so frames may be scheduled.
|
||||
@ -4510,24 +4541,162 @@ TEST_F(EmbedderTest, ExternalTextureGLRefreshedTooOften) {
|
||||
glFinish();
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest,
|
||||
PresentInfoReceivesNoDamageWhenPopulateExistingDamageIsUndefined) {
|
||||
TEST_F(
|
||||
EmbedderTest,
|
||||
PresentInfoReceivesFullScreenDamageWhenPopulateExistingDamageIsNotProvided) {
|
||||
auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
|
||||
|
||||
EmbedderConfigBuilder builder(context);
|
||||
builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
|
||||
builder.SetDartEntrypoint("render_gradient");
|
||||
builder.SetDartEntrypoint("render_gradient_retained");
|
||||
builder.GetRendererConfig().open_gl.populate_existing_damage = nullptr;
|
||||
|
||||
auto engine = builder.LaunchEngine();
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
|
||||
// No damage should be passed.
|
||||
fml::AutoResetWaitableEvent latch;
|
||||
|
||||
// First frame should be entirely rerendered.
|
||||
static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
|
||||
[](FlutterPresentInfo present_info) {
|
||||
ASSERT_EQ(present_info.frame_damage.damage, nullptr);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage, nullptr);
|
||||
[&](FlutterPresentInfo present_info) {
|
||||
const size_t num_rects = 1;
|
||||
ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->left, 0);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->right, 800);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
|
||||
|
||||
ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
|
||||
|
||||
latch.Signal();
|
||||
});
|
||||
|
||||
// Send a window metrics events so frames may be scheduled.
|
||||
FlutterWindowMetricsEvent event = {};
|
||||
event.struct_size = sizeof(event);
|
||||
event.width = 800;
|
||||
event.height = 600;
|
||||
event.pixel_ratio = 1.0;
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
latch.Wait();
|
||||
|
||||
// Since populate_existing_damage is not provided, the partial repaint
|
||||
// functionality is actually disabled. So, the next frame should be entirely
|
||||
// new frame.
|
||||
static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
|
||||
[&](FlutterPresentInfo present_info) {
|
||||
const size_t num_rects = 1;
|
||||
ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->left, 0);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->right, 800);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
|
||||
|
||||
ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
|
||||
|
||||
latch.Signal();
|
||||
});
|
||||
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
latch.Wait();
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest,
|
||||
PresentInfoReceivesJoinedDamageWhenExistingDamageContainsMultipleRects) {
|
||||
auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
|
||||
|
||||
EmbedderConfigBuilder builder(context);
|
||||
builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
|
||||
builder.SetDartEntrypoint("render_gradient_retained");
|
||||
builder.GetRendererConfig().open_gl.populate_existing_damage =
|
||||
[](void* context, const intptr_t id,
|
||||
FlutterDamage* existing_damage) -> void {
|
||||
return reinterpret_cast<EmbedderTestContextGL*>(context)
|
||||
->GLPopulateExistingDamage(id, existing_damage);
|
||||
};
|
||||
|
||||
// Return existing damage as the entire screen on purpose.
|
||||
static_cast<EmbedderTestContextGL&>(context)
|
||||
.SetGLPopulateExistingDamageCallback(
|
||||
[](const intptr_t id, FlutterDamage* existing_damage_ptr) {
|
||||
const size_t num_rects = 2;
|
||||
// The array must be valid after the callback returns.
|
||||
static FlutterRect existing_damage_rects[num_rects] = {
|
||||
FlutterRect{100, 150, 200, 250},
|
||||
FlutterRect{200, 250, 300, 350},
|
||||
};
|
||||
existing_damage_ptr->num_rects = num_rects;
|
||||
existing_damage_ptr->damage = existing_damage_rects;
|
||||
});
|
||||
|
||||
auto engine = builder.LaunchEngine();
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
|
||||
fml::AutoResetWaitableEvent latch;
|
||||
|
||||
// First frame should be entirely rerendered.
|
||||
static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
|
||||
[&](FlutterPresentInfo present_info) {
|
||||
const size_t num_rects = 1;
|
||||
ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->left, 0);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->right, 800);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
|
||||
|
||||
ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
|
||||
|
||||
latch.Signal();
|
||||
});
|
||||
|
||||
// Send a window metrics events so frames may be scheduled.
|
||||
FlutterWindowMetricsEvent event = {};
|
||||
event.struct_size = sizeof(event);
|
||||
event.width = 800;
|
||||
event.height = 600;
|
||||
event.pixel_ratio = 1.0;
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
latch.Wait();
|
||||
|
||||
// Because it's the same as the first frame, the second frame damage should
|
||||
// be empty but, because there was a full existing buffer damage, the buffer
|
||||
// damage should be the entire screen.
|
||||
static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
|
||||
[&](FlutterPresentInfo present_info) {
|
||||
const size_t num_rects = 1;
|
||||
ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->left, 0);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->top, 0);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->right, 0);
|
||||
ASSERT_EQ(present_info.frame_damage.damage->bottom, 0);
|
||||
|
||||
ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->left, 100);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->top, 150);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->right, 300);
|
||||
ASSERT_EQ(present_info.buffer_damage.damage->bottom, 350);
|
||||
|
||||
latch.Signal();
|
||||
});
|
||||
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
latch.Wait();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user