Commit f63fbcd5 by Michael Spang Committed by Commit Bot

Fuchsia: Limit number of concurrent presents in ScenicWindow

The test suite occasionally runs into the following error: [02036.794449][326733][326738][klog] INFO: [ERROR:src/ui/scenic/lib/scenic/session.cc(412)] Scenic session error (session_id: 1): Present2() called with no more present calls allowed. Terminating session. This is actually a problem with the test harness as resetting the window triggers a present with no fences and no OnFramePresentedCallback which means there is no way to know if we will exceed the limit. Add an OnFramePresentedCallback and count presents to stay under the limit. This blocks if there's more than 2 in flight presents. A dedicated async loop is used to avoid re-entering other code while waiting to present (there is no such case in the ANGLE test suite currently, but better safe than sorry). Typically if we run the whole suite there will be a failure in the middle, but re-trying the test that failed won't repro the issue. Add a test that reliably exhausts the limit by calling resetNativeWindow() in a loop. Bug: angleproject:4360 Change-Id: I24eb01fd72fc0be57c36e49b5875023a80d6ab91 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2027934 Commit-Queue: Michael Spang <spang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent a36f8bd4
...@@ -528,6 +528,27 @@ TEST_P(EGLSurfaceTest, ResizeWindowWithDraw) ...@@ -528,6 +528,27 @@ TEST_P(EGLSurfaceTest, ResizeWindowWithDraw)
EXPECT_PIXEL_COLOR_EQ(size, size, GLColor::transparentBlack); EXPECT_PIXEL_COLOR_EQ(size, size, GLColor::transparentBlack);
} }
// Test that the window can be reset repeatedly before surface creation.
TEST_P(EGLSurfaceTest, ResetNativeWindow)
{
mOSWindow->setVisible(true);
initializeDisplay();
for (int i = 0; i < 10; ++i)
{
mOSWindow->resetNativeWindow();
}
initializeSurfaceWithDefaultConfig();
initializeContext();
eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
eglSwapBuffers(mDisplay, mWindowSurface);
ASSERT_EGL_SUCCESS();
}
// Test that swap interval works. // Test that swap interval works.
TEST_P(EGLSurfaceTest, SwapInterval) TEST_P(EGLSurfaceTest, SwapInterval)
{ {
......
...@@ -27,7 +27,7 @@ namespace ...@@ -27,7 +27,7 @@ namespace
async::Loop *GetDefaultLoop() async::Loop *GetDefaultLoop()
{ {
static async::Loop *defaultLoop = new async::Loop(&kAsyncLoopConfigAttachToCurrentThread); static async::Loop *defaultLoop = new async::Loop(&kAsyncLoopConfigNeverAttachToThread);
return defaultLoop; return defaultLoop;
} }
...@@ -50,10 +50,11 @@ zx_status_t ConnectToService(zx_handle_t serviceRoot, fidl::InterfaceRequest<Int ...@@ -50,10 +50,11 @@ zx_status_t ConnectToService(zx_handle_t serviceRoot, fidl::InterfaceRequest<Int
} }
template <typename Interface> template <typename Interface>
fidl::InterfacePtr<Interface> ConnectToService(zx_handle_t serviceRoot) fidl::InterfacePtr<Interface> ConnectToService(zx_handle_t serviceRoot,
async_dispatcher_t *dispatcher)
{ {
fidl::InterfacePtr<Interface> result; fidl::InterfacePtr<Interface> result;
ConnectToService(serviceRoot, result.NewRequest()); ConnectToService(serviceRoot, result.NewRequest(dispatcher));
return result; return result;
} }
...@@ -62,12 +63,18 @@ fidl::InterfacePtr<Interface> ConnectToService(zx_handle_t serviceRoot) ...@@ -62,12 +63,18 @@ fidl::InterfacePtr<Interface> ConnectToService(zx_handle_t serviceRoot)
ScenicWindow::ScenicWindow() ScenicWindow::ScenicWindow()
: mLoop(GetDefaultLoop()), : mLoop(GetDefaultLoop()),
mServiceRoot(ConnectToServiceRoot()), mServiceRoot(ConnectToServiceRoot()),
mScenic(ConnectToService<fuchsia::ui::scenic::Scenic>(mServiceRoot.get())), mScenic(
mPresenter(ConnectToService<fuchsia::ui::policy::Presenter>(mServiceRoot.get())), ConnectToService<fuchsia::ui::scenic::Scenic>(mServiceRoot.get(), mLoop->dispatcher())),
mScenicSession(mScenic.get()), mPresenter(ConnectToService<fuchsia::ui::policy::Presenter>(mServiceRoot.get(),
mLoop->dispatcher())),
mScenicSession(mScenic.get(), mLoop->dispatcher()),
mShape(&mScenicSession), mShape(&mScenicSession),
mMaterial(&mScenicSession) mMaterial(&mScenicSession)
{} {
mScenicSession.set_error_handler(fit::bind_member(this, &ScenicWindow::onScenicError));
mScenicSession.set_on_frame_presented_handler(
fit::bind_member(this, &ScenicWindow::onFramePresented));
}
ScenicWindow::~ScenicWindow() ScenicWindow::~ScenicWindow()
{ {
...@@ -87,8 +94,6 @@ bool ScenicWindow::initialize(const std::string &name, int width, int height) ...@@ -87,8 +94,6 @@ bool ScenicWindow::initialize(const std::string &name, int width, int height)
// Create view. // Create view.
mView = std::make_unique<scenic::View>(&mScenicSession, std::move(viewToken), name); mView = std::make_unique<scenic::View>(&mScenicSession, std::move(viewToken), name);
mView->AddChild(mShape); mView->AddChild(mShape);
mScenicSession.Present2(0, 0,
[](fuchsia::scenic::scheduling::FuturePresentationTimes info) {});
// Present view. // Present view.
mPresenter->PresentView(std::move(viewHolderToken), nullptr); mPresenter->PresentView(std::move(viewHolderToken), nullptr);
...@@ -103,6 +108,14 @@ bool ScenicWindow::initialize(const std::string &name, int width, int height) ...@@ -103,6 +108,14 @@ bool ScenicWindow::initialize(const std::string &name, int width, int height)
void ScenicWindow::destroy() void ScenicWindow::destroy()
{ {
while (mInFlightPresents != 0 && !mLostSession)
{
mLoop->ResetQuit();
mLoop->Run();
}
ASSERT(mInFlightPresents == 0 || mLostSession);
mFuchsiaEGLWindow.reset(); mFuchsiaEGLWindow.reset();
} }
...@@ -110,13 +123,13 @@ void ScenicWindow::resetNativeWindow() ...@@ -110,13 +123,13 @@ void ScenicWindow::resetNativeWindow()
{ {
fuchsia::images::ImagePipe2Ptr imagePipe; fuchsia::images::ImagePipe2Ptr imagePipe;
uint32_t imagePipeId = mScenicSession.AllocResourceId(); uint32_t imagePipeId = mScenicSession.AllocResourceId();
mScenicSession.Enqueue(scenic::NewCreateImagePipe2Cmd(imagePipeId, imagePipe.NewRequest())); mScenicSession.Enqueue(
scenic::NewCreateImagePipe2Cmd(imagePipeId, imagePipe.NewRequest(mLoop->dispatcher())));
zx_handle_t imagePipeHandle = imagePipe.Unbind().TakeChannel().release(); zx_handle_t imagePipeHandle = imagePipe.Unbind().TakeChannel().release();
mMaterial.SetTexture(imagePipeId); mMaterial.SetTexture(imagePipeId);
mScenicSession.ReleaseResource(imagePipeId); mScenicSession.ReleaseResource(imagePipeId);
mScenicSession.Present2(0, 0, present();
[](fuchsia::scenic::scheduling::FuturePresentationTimes info) {});
mFuchsiaEGLWindow.reset(fuchsia_egl_window_create(imagePipeHandle, mWidth, mHeight)); mFuchsiaEGLWindow.reset(fuchsia_egl_window_create(imagePipeHandle, mWidth, mHeight));
} }
...@@ -133,7 +146,8 @@ EGLNativeDisplayType ScenicWindow::getNativeDisplay() const ...@@ -133,7 +146,8 @@ EGLNativeDisplayType ScenicWindow::getNativeDisplay() const
void ScenicWindow::messageLoop() void ScenicWindow::messageLoop()
{ {
mLoop->Run(zx::deadline_after({}), true /* once */); mLoop->ResetQuit();
mLoop->RunUntilIdle();
} }
void ScenicWindow::setMousePosition(int x, int y) void ScenicWindow::setMousePosition(int x, int y)
...@@ -161,14 +175,42 @@ void ScenicWindow::setVisible(bool isVisible) {} ...@@ -161,14 +175,42 @@ void ScenicWindow::setVisible(bool isVisible) {}
void ScenicWindow::signalTestEvent() {} void ScenicWindow::signalTestEvent() {}
void ScenicWindow::OnScenicEvents(std::vector<fuchsia::ui::scenic::Event> events) void ScenicWindow::present()
{
while (mInFlightPresents >= kMaxInFlightPresents && !mLostSession)
{
mLoop->ResetQuit();
mLoop->Run();
}
if (mLostSession)
{
return;
}
ASSERT(mInFlightPresents < kMaxInFlightPresents);
++mInFlightPresents;
mScenicSession.Present2(0, 0, [](fuchsia::scenic::scheduling::FuturePresentationTimes info) {});
}
void ScenicWindow::onFramePresented(fuchsia::scenic::scheduling::FramePresentedInfo info)
{
mInFlightPresents -= info.presentation_infos.size();
ASSERT(mInFlightPresents >= 0);
mLoop->Quit();
}
void ScenicWindow::onScenicEvents(std::vector<fuchsia::ui::scenic::Event> events)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void ScenicWindow::OnScenicError(zx_status_t status) void ScenicWindow::onScenicError(zx_status_t status)
{ {
WARN() << "OnScenicError: " << zx_status_get_string(status); WARN() << "OnScenicError: " << zx_status_get_string(status);
mLostSession = true;
mLoop->Quit();
} }
// static // static
......
...@@ -53,13 +53,20 @@ class ANGLE_UTIL_EXPORT ScenicWindow : public OSWindow ...@@ -53,13 +53,20 @@ class ANGLE_UTIL_EXPORT ScenicWindow : public OSWindow
void setVisible(bool isVisible) override; void setVisible(bool isVisible) override;
void signalTestEvent() override; void signalTestEvent() override;
// Presents the window to Scenic.
//
// We need to do this once per EGL window surface after adding the
// surface's image pipe as a child of our window.
void present();
// FIDL callbacks: // FIDL callbacks:
void OnScenicEvents(std::vector<fuchsia::ui::scenic::Event> events); void onScenicEvents(std::vector<fuchsia::ui::scenic::Event> events);
void OnScenicError(zx_status_t status); void onScenicError(zx_status_t status);
void onFramePresented(fuchsia::scenic::scheduling::FramePresentedInfo info);
private: private:
// Default message loop. // ScenicWindow async loop.
async::Loop *mLoop; async::Loop *const mLoop;
// System services. // System services.
zx::channel mServiceRoot; zx::channel mServiceRoot;
...@@ -71,6 +78,13 @@ class ANGLE_UTIL_EXPORT ScenicWindow : public OSWindow ...@@ -71,6 +78,13 @@ class ANGLE_UTIL_EXPORT ScenicWindow : public OSWindow
scenic::ShapeNode mShape; scenic::ShapeNode mShape;
scenic::Material mMaterial; scenic::Material mMaterial;
// Whether our scenic session has disconnected.
bool mLostSession = false;
// Present limiting.
static constexpr int kMaxInFlightPresents = 2;
int mInFlightPresents = 0;
// Scenic view. // Scenic view.
std::unique_ptr<scenic::View> mView; std::unique_ptr<scenic::View> mView;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment