[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
|
// 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.
|
// that can be passed to the platform to drop queued frames.
|
||||||
std::optional<fml::TimePoint> presentation_time;
|
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();
|
bool Submit();
|
||||||
|
@ -127,14 +127,16 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceGLImpeller::AcquireFrame(
|
|||||||
impeller_dispatcher,
|
impeller_dispatcher,
|
||||||
SkIRect::MakeWH(cull_rect.width, cull_rect.height));
|
SkIRect::MakeWH(cull_rect.width, cull_rect.height));
|
||||||
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
||||||
|
const bool reset_host_buffer =
|
||||||
|
surface_frame.submit_info().frame_boundary;
|
||||||
|
|
||||||
return renderer->Render(
|
return renderer->Render(
|
||||||
std::move(surface),
|
std::move(surface),
|
||||||
fml::MakeCopyable(
|
fml::MakeCopyable(
|
||||||
[aiks_context, picture = std::move(picture)](
|
[aiks_context, picture = std::move(picture), reset_host_buffer](
|
||||||
impeller::RenderTarget& render_target) -> bool {
|
impeller::RenderTarget& render_target) -> bool {
|
||||||
return aiks_context->Render(picture, render_target,
|
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);
|
impeller::DlDispatcher impeller_dispatcher(cull_rect);
|
||||||
display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
|
display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
|
||||||
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
||||||
|
const bool reset_host_buffer = surface_frame.submit_info().frame_boundary;
|
||||||
|
|
||||||
return renderer->Render(
|
return renderer->Render(
|
||||||
std::move(surface),
|
std::move(surface),
|
||||||
fml::MakeCopyable([aiks_context, picture = std::move(picture)](
|
fml::MakeCopyable([aiks_context, picture = std::move(picture),
|
||||||
impeller::RenderTarget& render_target) -> bool {
|
reset_host_buffer](impeller::RenderTarget& render_target) -> bool {
|
||||||
return aiks_context->Render(picture, render_target, /*reset_host_buffer=*/true);
|
return aiks_context->Render(picture, render_target, reset_host_buffer);
|
||||||
}));
|
}));
|
||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
@ -307,11 +308,12 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromMTLTextur
|
|||||||
display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
|
display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
|
||||||
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
||||||
|
|
||||||
|
const bool reset_host_buffer = surface_frame.submit_info().frame_boundary;
|
||||||
bool render_result = renderer->Render(
|
bool render_result = renderer->Render(
|
||||||
std::move(surface),
|
std::move(surface),
|
||||||
fml::MakeCopyable([aiks_context, picture = std::move(picture)](
|
fml::MakeCopyable([aiks_context, picture = std::move(picture),
|
||||||
impeller::RenderTarget& render_target) -> bool {
|
reset_host_buffer](impeller::RenderTarget& render_target) -> bool {
|
||||||
return aiks_context->Render(picture, render_target, /*reset_host_buffer=*/true);
|
return aiks_context->Render(picture, render_target, reset_host_buffer);
|
||||||
}));
|
}));
|
||||||
#endif
|
#endif
|
||||||
if (!render_result) {
|
if (!render_result) {
|
||||||
|
@ -97,5 +97,32 @@ TEST(GPUSurfaceMetalImpeller, AcquireFrameFromCAMetalLayerDoesNotRetainThis) {
|
|||||||
ASSERT_TRUE(frame->Submit());
|
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 testing
|
||||||
} // namespace flutter
|
} // namespace flutter
|
||||||
|
@ -117,9 +117,10 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceVulkanImpeller::AcquireFrame(
|
|||||||
impeller_dispatcher,
|
impeller_dispatcher,
|
||||||
SkIRect::MakeWH(cull_rect.width, cull_rect.height));
|
SkIRect::MakeWH(cull_rect.width, cull_rect.height));
|
||||||
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
auto picture = impeller_dispatcher.EndRecordingAsPicture();
|
||||||
|
const bool reset_host_buffer =
|
||||||
|
surface_frame.submit_info().frame_boundary;
|
||||||
return aiks_context->Render(picture, render_target,
|
return aiks_context->Render(picture, render_target,
|
||||||
/*reset_host_buffer=*/true);
|
reset_host_buffer);
|
||||||
#endif
|
#endif
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -864,6 +864,10 @@ std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewsController::GetLay
|
|||||||
slice->render_into(overlay_canvas);
|
slice->render_into(overlay_canvas);
|
||||||
overlay_canvas->RestoreToCount(restore_count);
|
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();
|
layer->did_submit_last_frame = frame->Submit();
|
||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user