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
This commit is contained in:
Jamie Nicol 2022-04-25 18:20:55 +00:00
parent f3a5471268
commit 0691a2b63f
10 changed files with 46 additions and 0 deletions

View File

@ -109,5 +109,10 @@ LayoutDeviceIntSize AndroidCompositorWidget::GetClientSize() {
return mClientSize;
}
void AndroidCompositorWidget::NotifyClientSizeChanged(
const LayoutDeviceIntSize& aClientSize) {
mClientSize = aClientSize;
}
} // namespace widget
} // namespace mozilla

View File

@ -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.

View File

@ -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

View File

@ -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<CompositorVsyncDispatcher> mVsyncDispatcher;
RefPtr<CompositorWidgetVsyncObserver> mVsyncObserver;

View File

@ -37,6 +37,12 @@ RefPtr<VsyncObserver> 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::

View File

@ -26,6 +26,9 @@ class CompositorWidgetParent final : public PCompositorWidgetParent,
void ObserveVsync(VsyncObserver* aObserver) override;
RefPtr<VsyncObserver> GetVsyncObserver() const override;
mozilla::ipc::IPCResult RecvNotifyClientSizeChanged(
const LayoutDeviceIntSize& aClientSize) override;
private:
// AndroidCompositorWidget overrides
void OnCompositorSurfaceChanged() override;

View File

@ -55,5 +55,10 @@ void InProcessAndroidCompositorWidget::OnCompositorSurfaceChanged() {
}
}
void InProcessAndroidCompositorWidget::NotifyClientSizeChanged(
const LayoutDeviceIntSize& aClientSize) {
AndroidCompositorWidget::NotifyClientSizeChanged(aClientSize);
}
} // namespace widget
} // namespace mozilla

View File

@ -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;

View File

@ -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();

View File

@ -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) {