[Impeller] mark the end of a frame boundary for system compositor interop. (flutter/engine#53722)
Fixes https://github.com/flutter/flutter/issues/151274 This is only an issue on iOS (so far) because of the platform view rendering strategy that involves submitting multiple impeller frames per compositor frame. FYI @bdero
This commit is contained in:
parent
b4a744f468
commit
efbf7ddc57
@ -80,6 +80,13 @@ class SurfaceFrame {
|
||||
// Time at which this frame is scheduled to be presented. This is a hint
|
||||
// that can be passed to the platform to drop queued frames.
|
||||
std::optional<fml::TimePoint> presentation_time;
|
||||
|
||||
// Whether this surface frame represents the last in a group frames that
|
||||
// were submitted as part of a platform compositor interop step, such as
|
||||
// during iOS platform view compositing.
|
||||
//
|
||||
// Defaults to true, which is generally a safe value.
|
||||
bool frame_boundary = true;
|
||||
};
|
||||
|
||||
bool Submit();
|
||||
|
@ -127,14 +127,16 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceGLImpeller::AcquireFrame(
|
||||
impeller_dispatcher,
|
||||
SkIRect::MakeWH(cull_rect.width, cull_rect.height));
|
||||
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
||||
const bool reset_host_buffer =
|
||||
surface_frame.submit_info().frame_boundary;
|
||||
|
||||
return renderer->Render(
|
||||
std::move(surface),
|
||||
fml::MakeCopyable(
|
||||
[aiks_context, picture = std::move(picture)](
|
||||
[aiks_context, picture = std::move(picture), reset_host_buffer](
|
||||
impeller::RenderTarget& render_target) -> bool {
|
||||
return aiks_context->Render(picture, render_target,
|
||||
/*reset_host_buffer=*/true);
|
||||
reset_host_buffer);
|
||||
}));
|
||||
});
|
||||
|
||||
|
@ -187,12 +187,13 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLa
|
||||
impeller::DlDispatcher impeller_dispatcher(cull_rect);
|
||||
display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
|
||||
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
||||
const bool reset_host_buffer = surface_frame.submit_info().frame_boundary;
|
||||
|
||||
return renderer->Render(
|
||||
std::move(surface),
|
||||
fml::MakeCopyable([aiks_context, picture = std::move(picture)](
|
||||
impeller::RenderTarget& render_target) -> bool {
|
||||
return aiks_context->Render(picture, render_target, /*reset_host_buffer=*/true);
|
||||
fml::MakeCopyable([aiks_context, picture = std::move(picture),
|
||||
reset_host_buffer](impeller::RenderTarget& render_target) -> bool {
|
||||
return aiks_context->Render(picture, render_target, reset_host_buffer);
|
||||
}));
|
||||
#endif
|
||||
});
|
||||
@ -307,11 +308,12 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromMTLTextur
|
||||
display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
|
||||
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
||||
|
||||
const bool reset_host_buffer = surface_frame.submit_info().frame_boundary;
|
||||
bool render_result = renderer->Render(
|
||||
std::move(surface),
|
||||
fml::MakeCopyable([aiks_context, picture = std::move(picture)](
|
||||
impeller::RenderTarget& render_target) -> bool {
|
||||
return aiks_context->Render(picture, render_target, /*reset_host_buffer=*/true);
|
||||
fml::MakeCopyable([aiks_context, picture = std::move(picture),
|
||||
reset_host_buffer](impeller::RenderTarget& render_target) -> bool {
|
||||
return aiks_context->Render(picture, render_target, reset_host_buffer);
|
||||
}));
|
||||
#endif
|
||||
if (!render_result) {
|
||||
|
@ -97,5 +97,32 @@ TEST(GPUSurfaceMetalImpeller, AcquireFrameFromCAMetalLayerDoesNotRetainThis) {
|
||||
ASSERT_TRUE(frame->Submit());
|
||||
}
|
||||
|
||||
TEST(GPUSurfaceMetalImpeller, ResetHostBufferBasedOnFrameBoundary) {
|
||||
auto delegate = std::make_shared<TestGPUSurfaceMetalDelegate>();
|
||||
delegate->SetDevice();
|
||||
|
||||
auto context = CreateImpellerContext();
|
||||
std::unique_ptr<Surface> surface =
|
||||
std::make_unique<GPUSurfaceMetalImpeller>(delegate.get(), CreateImpellerContext());
|
||||
|
||||
ASSERT_TRUE(surface->IsValid());
|
||||
|
||||
auto& host_buffer = surface->GetAiksContext()->GetContentContext().GetTransientsBuffer();
|
||||
|
||||
EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u);
|
||||
|
||||
auto frame = surface->AcquireFrame(SkISize::Make(100, 100));
|
||||
frame->set_submit_info({.frame_boundary = false});
|
||||
|
||||
ASSERT_TRUE(frame->Submit());
|
||||
EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u);
|
||||
|
||||
frame = surface->AcquireFrame(SkISize::Make(100, 100));
|
||||
frame->set_submit_info({.frame_boundary = true});
|
||||
|
||||
ASSERT_TRUE(frame->Submit());
|
||||
EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
@ -117,9 +117,10 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceVulkanImpeller::AcquireFrame(
|
||||
impeller_dispatcher,
|
||||
SkIRect::MakeWH(cull_rect.width, cull_rect.height));
|
||||
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
||||
|
||||
const bool reset_host_buffer =
|
||||
surface_frame.submit_info().frame_boundary;
|
||||
return aiks_context->Render(picture, render_target,
|
||||
/*reset_host_buffer=*/true);
|
||||
reset_host_buffer);
|
||||
#endif
|
||||
}));
|
||||
});
|
||||
|
@ -864,6 +864,10 @@ std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewsController::GetLay
|
||||
slice->render_into(overlay_canvas);
|
||||
overlay_canvas->RestoreToCount(restore_count);
|
||||
|
||||
// This flutter view is never the last in a frame, since we always submit the
|
||||
// underlay view last.
|
||||
frame->set_submit_info({.frame_boundary = false});
|
||||
|
||||
layer->did_submit_last_frame = frame->Submit();
|
||||
return layer;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user