From 0691a2b63f1da004f74c33125b41a2d25178f848 Mon Sep 17 00:00:00 2001 From: Jamie Nicol Date: Mon, 25 Apr 2022 18:20:55 +0000 Subject: [PATCH] Bug 1766127 - Allow AndroidCompositorWidget::mClientSize to be updated from main thread. r=agi,gfx-reviewers,lsalzman On Android we have long since calculated the compositor widget size from the Surface rather than using the main thread widget size. This is to avoid a trip via the main thread in response to a ResumeAndResize event on the UI thread. AndroidCompositorWidget::mClientSize therefore gets calculated when the compositor is resumed. However, it is possible in some circumstances for the compositor to receive a display list prior to it being resumed. In this bug's case, SyncResumeAndResize is getting called before the UI thread has been notified that the compositor has been initialized. It therefore cannot resume the compositor, and we instead resume the compositor on the subsequent NotifyCompositorCreated call. This starts a race between the main thread paint and NotifyCompositorCreated being scheduled on the UI thread then resuming the compositor via PUiCompositorController. If we receive WebRenderBridgeParent::RecvSetDisplayList prior to UiCompositorControllerParent::RecvResumeAndResize, then AndroidCompositorWidget::mClientSize will be zero. This results in us setting zero-sized webrender scene rect, leading to webrender exiting early during rendering, resulting in a black screen. To fix this, allow the main thread to set the AndroidCompositorWidget size, in addition to the UI thread being able to set it. We do so by adding a NotifyClientSizeChanged method to PlatformCompositorWidgetDelegate, called from nsWindow::OnSizeChanged. The cross-process implementation of this uses an IPDL call on PCompositorWidget, which shares a top-level protocol with PWebRenderBridge, meaning calls are guaranteed to occur in order. This means a resize event on the main thread is guaranteed to set the CompositorWidget size before the display list from the subsequent paint is received. Differential Revision: https://phabricator.services.mozilla.com/D144594 --- widget/android/AndroidCompositorWidget.cpp | 5 +++++ widget/android/AndroidCompositorWidget.h | 5 +++++ widget/android/CompositorWidgetChild.cpp | 5 +++++ widget/android/CompositorWidgetChild.h | 4 ++++ widget/android/CompositorWidgetParent.cpp | 6 ++++++ widget/android/CompositorWidgetParent.h | 3 +++ widget/android/InProcessAndroidCompositorWidget.cpp | 5 +++++ widget/android/InProcessAndroidCompositorWidget.h | 4 ++++ widget/android/PCompositorWidget.ipdl | 4 ++++ widget/android/nsWindow.cpp | 5 +++++ 10 files changed, 46 insertions(+) diff --git a/widget/android/AndroidCompositorWidget.cpp b/widget/android/AndroidCompositorWidget.cpp index 29f2ed5307ef..386970f8cb68 100644 --- a/widget/android/AndroidCompositorWidget.cpp +++ b/widget/android/AndroidCompositorWidget.cpp @@ -109,5 +109,10 @@ LayoutDeviceIntSize AndroidCompositorWidget::GetClientSize() { return mClientSize; } +void AndroidCompositorWidget::NotifyClientSizeChanged( + const LayoutDeviceIntSize& aClientSize) { + mClientSize = aClientSize; +} + } // namespace widget } // namespace mozilla diff --git a/widget/android/AndroidCompositorWidget.h b/widget/android/AndroidCompositorWidget.h index 08ea7a459b72..17f1131e1fbf 100644 --- a/widget/android/AndroidCompositorWidget.h +++ b/widget/android/AndroidCompositorWidget.h @@ -15,6 +15,9 @@ namespace widget { class PlatformCompositorWidgetDelegate : public CompositorWidgetDelegate { public: + virtual void NotifyClientSizeChanged( + const LayoutDeviceIntSize& aClientSize) = 0; + // CompositorWidgetDelegate Overrides PlatformCompositorWidgetDelegate* AsPlatformSpecificDelegate() override { return this; @@ -54,6 +57,8 @@ class AndroidCompositorWidget : public CompositorWidget { int32_t mFormat; LayoutDeviceIntSize mClientSize; + void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize); + private: // Called whenever the compositor surface may have changed. The derived class // should update mSurface to the new compositor surface. diff --git a/widget/android/CompositorWidgetChild.cpp b/widget/android/CompositorWidgetChild.cpp index 38604aaba817..ba51dda7a54d 100644 --- a/widget/android/CompositorWidgetChild.cpp +++ b/widget/android/CompositorWidgetChild.cpp @@ -33,5 +33,10 @@ mozilla::ipc::IPCResult CompositorWidgetChild::RecvUnobserveVsync() { return IPC_OK(); } +void CompositorWidgetChild::NotifyClientSizeChanged( + const LayoutDeviceIntSize& aClientSize) { + Unused << SendNotifyClientSizeChanged(aClientSize); +} + } // namespace widget } // namespace mozilla diff --git a/widget/android/CompositorWidgetChild.h b/widget/android/CompositorWidgetChild.h index 7d41ff4fab6c..88cb2913e90c 100644 --- a/widget/android/CompositorWidgetChild.h +++ b/widget/android/CompositorWidgetChild.h @@ -26,6 +26,10 @@ class CompositorWidgetChild final : public PCompositorWidgetChild, mozilla::ipc::IPCResult RecvObserveVsync() override; mozilla::ipc::IPCResult RecvUnobserveVsync() override; + // PlatformCompositorWidgetDelegate overrides + + void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override; + private: RefPtr mVsyncDispatcher; RefPtr mVsyncObserver; diff --git a/widget/android/CompositorWidgetParent.cpp b/widget/android/CompositorWidgetParent.cpp index 070f5bebfd15..5c586cfb8710 100644 --- a/widget/android/CompositorWidgetParent.cpp +++ b/widget/android/CompositorWidgetParent.cpp @@ -37,6 +37,12 @@ RefPtr CompositorWidgetParent::GetVsyncObserver() const { return mVsyncObserver; } +mozilla::ipc::IPCResult CompositorWidgetParent::RecvNotifyClientSizeChanged( + const LayoutDeviceIntSize& aClientSize) { + NotifyClientSizeChanged(aClientSize); + return IPC_OK(); +} + void CompositorWidgetParent::OnCompositorSurfaceChanged() { java::GeckoServiceGpuProcess::RemoteCompositorSurfaceManager::LocalRef manager = java::GeckoServiceGpuProcess::RemoteCompositorSurfaceManager:: diff --git a/widget/android/CompositorWidgetParent.h b/widget/android/CompositorWidgetParent.h index 8fdf02650924..cd6e4241ca12 100644 --- a/widget/android/CompositorWidgetParent.h +++ b/widget/android/CompositorWidgetParent.h @@ -26,6 +26,9 @@ class CompositorWidgetParent final : public PCompositorWidgetParent, void ObserveVsync(VsyncObserver* aObserver) override; RefPtr GetVsyncObserver() const override; + mozilla::ipc::IPCResult RecvNotifyClientSizeChanged( + const LayoutDeviceIntSize& aClientSize) override; + private: // AndroidCompositorWidget overrides void OnCompositorSurfaceChanged() override; diff --git a/widget/android/InProcessAndroidCompositorWidget.cpp b/widget/android/InProcessAndroidCompositorWidget.cpp index 072fe5a3c511..76dc3fed0cae 100644 --- a/widget/android/InProcessAndroidCompositorWidget.cpp +++ b/widget/android/InProcessAndroidCompositorWidget.cpp @@ -55,5 +55,10 @@ void InProcessAndroidCompositorWidget::OnCompositorSurfaceChanged() { } } +void InProcessAndroidCompositorWidget::NotifyClientSizeChanged( + const LayoutDeviceIntSize& aClientSize) { + AndroidCompositorWidget::NotifyClientSizeChanged(aClientSize); +} + } // namespace widget } // namespace mozilla diff --git a/widget/android/InProcessAndroidCompositorWidget.h b/widget/android/InProcessAndroidCompositorWidget.h index bcdaaba308cf..b7ba280d5cfb 100644 --- a/widget/android/InProcessAndroidCompositorWidget.h +++ b/widget/android/InProcessAndroidCompositorWidget.h @@ -28,6 +28,10 @@ class InProcessAndroidCompositorWidget final nsIWidget* RealWidget() override; CompositorWidgetDelegate* AsDelegate() override { return this; } + // PlatformCompositorWidgetDelegate overrides + + void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override; + private: // AndroidCompositorWidget overrides void OnCompositorSurfaceChanged() override; diff --git a/widget/android/PCompositorWidget.ipdl b/widget/android/PCompositorWidget.ipdl index 9d4d2f03f5d7..35a150cbba27 100644 --- a/widget/android/PCompositorWidget.ipdl +++ b/widget/android/PCompositorWidget.ipdl @@ -6,6 +6,8 @@ include protocol PCompositorBridge; +using mozilla::LayoutDeviceIntSize from "Units.h"; + namespace mozilla { namespace widget { @@ -17,6 +19,8 @@ sync protocol PCompositorWidget parent: async __delete__(); + async NotifyClientSizeChanged(LayoutDeviceIntSize aClientSize); + child: async ObserveVsync(); async UnobserveVsync(); diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 436e70f60480..c1e5eb568753 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -2330,6 +2330,11 @@ void nsWindow::OnSizeChanged(const gfx::IntSize& aSize) { if (mAttachedWidgetListener) { mAttachedWidgetListener->WindowResized(this, aSize.width, aSize.height); } + + if (mCompositorWidgetDelegate) { + mCompositorWidgetDelegate->NotifyClientSizeChanged( + LayoutDeviceIntSize::FromUnknownSize(aSize)); + } } void nsWindow::InitEvent(WidgetGUIEvent& event, LayoutDeviceIntPoint* aPoint) {