зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1645528 - Connect nsRefreshDrivers in content processes with a widget-local vsync source r=mattwoodrow,emilio
To allow `requestAnimationFrame()` and similar things to run at monitor speed if there is only a window-specific vsyncsource available. This is the case for Wayland and, in the future, EGL/X11. Other backends may opt for window specific vsyncsources as well at some point. The idea is to, instead of using global vsync objects, expose a vsyncsource from nsWindow and use it for refresh drivers. For the content process, move VsyncChild to BrowserChild, so for each Browserchild there is only one VsyncChild to which all refresh drivers connect. IPC in managed either by PBrowser or PBackground. Right now, PBrowser is only used on Wayland, as both PBrowser and the Wayland vsyncsource run on the main thread. Other backends keep using the background thread for now. While at it, make it so that we constantly update the refresh rate. This is necessary for Wayland, but also on other platforms variable refresh rates are increasingly common. Do that by transimitting the vsync rate `SendNotify()`. How to test: - run the Wayland backend - enable `widget.wayland_vsync.enabled` - optionally: disable `privacy.reduceTimerPrecision` - run `vsynctester.com` or `testufo.com` Expected results: Instead of fixed 60Hz, things should update at monitor refresh rate - e.g. 144Hz Original patch by Kenny Levinsen. Differential Revision: https://phabricator.services.mozilla.com/D93173
This commit is contained in:
Родитель
26311e778c
Коммит
5ccb38b25c
|
@ -14,6 +14,7 @@
|
|||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "BackgroundChild.h"
|
||||
#include "BrowserParent.h"
|
||||
#include "ClientLayerManager.h"
|
||||
#include "ContentChild.h"
|
||||
|
@ -74,6 +75,7 @@
|
|||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||
#include "mozilla/layers/APZCTreeManagerChild.h"
|
||||
|
@ -142,6 +144,10 @@
|
|||
# include "mozilla/plugins/PluginWidgetChild.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WAYLAND
|
||||
# include "nsAppRunner.h"
|
||||
#endif
|
||||
|
||||
#ifdef NS_PRINTING
|
||||
# include "nsIPrintSession.h"
|
||||
# include "nsIPrintSettings.h"
|
||||
|
@ -314,6 +320,7 @@ BrowserChild::BrowserChild(ContentChild* aManager, const TabId& aTabId,
|
|||
mDidFakeShow(false),
|
||||
mTriedBrowserInit(false),
|
||||
mOrientation(hal::eScreenOrientation_PortraitPrimary),
|
||||
mVsyncChild(nullptr),
|
||||
mIgnoreKeyPressEvent(false),
|
||||
mHasValidInnerSize(false),
|
||||
mDestroyed(false),
|
||||
|
@ -550,6 +557,8 @@ nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
#endif
|
||||
|
||||
InitVsyncChild();
|
||||
|
||||
// We've all set up, make sure our visibility state is consistent. This is
|
||||
// important for OOP iframes, which start off as hidden.
|
||||
UpdateVisibility();
|
||||
|
@ -557,6 +566,20 @@ nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void BrowserChild::InitVsyncChild() {
|
||||
#if defined(MOZ_WAYLAND)
|
||||
if (!IsWaylandDisabled()) {
|
||||
PVsyncChild* actor = SendPVsyncConstructor();
|
||||
mVsyncChild = static_cast<VsyncChild*>(actor);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
PBackgroundChild* actorChild =
|
||||
BackgroundChild::GetOrCreateForCurrentThread();
|
||||
mVsyncChild = static_cast<VsyncChild*>(actorChild->SendPVsyncConstructor());
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserChild::NotifyTabContextUpdated() {
|
||||
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
|
||||
MOZ_ASSERT(docShell);
|
||||
|
@ -2143,6 +2166,23 @@ bool BrowserChild::DeallocPFilePickerChild(PFilePickerChild* actor) {
|
|||
return true;
|
||||
}
|
||||
|
||||
PVsyncChild* BrowserChild::AllocPVsyncChild() {
|
||||
RefPtr<dom::VsyncChild> actor = new VsyncChild();
|
||||
// There still has one ref-count after return, and it will be released in
|
||||
// DeallocPVsyncChild().
|
||||
return actor.forget().take();
|
||||
}
|
||||
|
||||
bool BrowserChild::DeallocPVsyncChild(PVsyncChild* aActor) {
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
// This actor already has one ref-count. Please check AllocPVsyncChild().
|
||||
RefPtr<VsyncChild> actor = dont_AddRef(static_cast<VsyncChild*>(aActor));
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<VsyncChild> BrowserChild::GetVsyncChild() { return mVsyncChild; }
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvActivateFrameEvent(
|
||||
const nsString& aType, const bool& capture) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "mozilla/dom/CoalescedMouseData.h"
|
||||
#include "mozilla/dom/CoalescedWheelData.h"
|
||||
#include "mozilla/dom/MessageManagerCallback.h"
|
||||
#include "mozilla/dom/VsyncChild.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
|
@ -436,6 +437,12 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
PFilePickerChild* AllocPFilePickerChild(const nsString& aTitle,
|
||||
const int16_t& aMode);
|
||||
|
||||
virtual PVsyncChild* AllocPVsyncChild();
|
||||
|
||||
virtual bool DeallocPVsyncChild(PVsyncChild* aActor);
|
||||
|
||||
RefPtr<VsyncChild> GetVsyncChild();
|
||||
|
||||
bool DeallocPFilePickerChild(PFilePickerChild* aActor);
|
||||
|
||||
nsIWebNavigation* WebNavigation() const { return mWebNav; }
|
||||
|
@ -747,6 +754,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
const mozilla::layers::CompositorOptions& aCompositorOptions);
|
||||
void InitAPZState();
|
||||
|
||||
void InitVsyncChild();
|
||||
|
||||
void DestroyWindow();
|
||||
|
||||
void ApplyParentShowInfo(const ParentShowInfo&);
|
||||
|
@ -814,6 +823,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
bool mTriedBrowserInit;
|
||||
hal::ScreenOrientation mOrientation;
|
||||
|
||||
RefPtr<VsyncChild> mVsyncChild;
|
||||
|
||||
bool mIgnoreKeyPressEvent;
|
||||
RefPtr<APZEventState> mAPZEventState;
|
||||
SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback;
|
||||
|
|
|
@ -129,6 +129,7 @@
|
|||
#include "mozilla/dom/CrashReport.h"
|
||||
#include "nsISecureBrowserUI.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "VsyncSource.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
# include "mozilla/plugins/PluginWidgetParent.h"
|
||||
|
@ -224,6 +225,7 @@ BrowserParent::BrowserParent(ContentParent* aManager, const TabId& aTabId,
|
|||
mCustomCursorHotspotX(0),
|
||||
mCustomCursorHotspotY(0),
|
||||
mVerifyDropLinks{},
|
||||
mVsyncParent(nullptr),
|
||||
mDocShellIsActive(false),
|
||||
mMarkedDestroying(false),
|
||||
mIsDestroyed(false),
|
||||
|
@ -563,6 +565,8 @@ void BrowserParent::SetOwnerElement(Element* aElement) {
|
|||
mBrowsingContext->SetEmbedderElement(mFrameElement);
|
||||
}
|
||||
|
||||
UpdateVsyncParentVsyncSource();
|
||||
|
||||
VisitChildren([aElement](BrowserBridgeParent* aBrowser) {
|
||||
if (auto* browserParent = aBrowser->GetBrowserParent()) {
|
||||
browserParent->SetOwnerElement(aElement);
|
||||
|
@ -1346,6 +1350,29 @@ IPCResult BrowserParent::RecvNewWindowGlobal(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PVsyncParent* BrowserParent::AllocPVsyncParent() {
|
||||
MOZ_ASSERT(!mVsyncParent);
|
||||
mVsyncParent = new VsyncParent();
|
||||
UpdateVsyncParentVsyncSource();
|
||||
return mVsyncParent.get();
|
||||
}
|
||||
|
||||
bool BrowserParent::DeallocPVsyncParent(PVsyncParent* aActor) {
|
||||
MOZ_ASSERT(aActor);
|
||||
mVsyncParent = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BrowserParent::UpdateVsyncParentVsyncSource() {
|
||||
if (!mVsyncParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
|
||||
mVsyncParent->UpdateVsyncSource(widget->GetVsyncSource());
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserParent::SendMouseEvent(const nsAString& aType, float aX, float aY,
|
||||
int32_t aButton, int32_t aClickCount,
|
||||
int32_t aModifiers) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "mozilla/dom/BrowserBridgeParent.h"
|
||||
#include "mozilla/dom/PBrowserParent.h"
|
||||
#include "mozilla/dom/TabContext.h"
|
||||
#include "mozilla/dom/VsyncParent.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/layout/RemoteLayerTreeOwner.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -460,6 +461,10 @@ class BrowserParent final : public PBrowserParent,
|
|||
|
||||
bool DeallocPColorPickerParent(PColorPickerParent* aColorPicker);
|
||||
|
||||
PVsyncParent* AllocPVsyncParent();
|
||||
|
||||
bool DeallocPVsyncParent(PVsyncParent* aActor);
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
PDocAccessibleParent* AllocPDocAccessibleParent(PDocAccessibleParent*,
|
||||
const uint64_t&,
|
||||
|
@ -872,6 +877,8 @@ class BrowserParent final : public PBrowserParent,
|
|||
void SendRealTouchMoveEvent(WidgetTouchEvent& aEvent, APZData& aAPZData,
|
||||
uint32_t aConsecutiveTouchMoveCount);
|
||||
|
||||
void UpdateVsyncParentVsyncSource();
|
||||
|
||||
public:
|
||||
// Unsets sTopLevelWebFocus regardless of its current value.
|
||||
static void UnsetTopLevelWebFocusAll();
|
||||
|
@ -957,6 +964,8 @@ class BrowserParent final : public PBrowserParent,
|
|||
|
||||
nsTArray<nsString> mVerifyDropLinks;
|
||||
|
||||
RefPtr<VsyncParent> mVsyncParent;
|
||||
|
||||
#ifdef DEBUG
|
||||
int32_t mActiveSupressDisplayportCount = 0;
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,7 @@ include protocol PRemoteLazyInputStream;
|
|||
include protocol PPaymentRequest;
|
||||
include protocol PWindowGlobal;
|
||||
include protocol PBrowserBridge;
|
||||
include protocol PVsync;
|
||||
|
||||
include DOMTypes;
|
||||
include NeckoChannelParams;
|
||||
|
@ -190,6 +191,7 @@ nested(upto inside_cpow) sync refcounted protocol PBrowser
|
|||
manages PPaymentRequest;
|
||||
manages PWindowGlobal;
|
||||
manages PBrowserBridge;
|
||||
manages PVsync;
|
||||
|
||||
both:
|
||||
async AsyncMessage(nsString aMessage, ClonedMessageData aData);
|
||||
|
@ -217,6 +219,11 @@ parent:
|
|||
|
||||
async PPaymentRequest();
|
||||
|
||||
/**
|
||||
* Create a new Vsync connection for our associated root widget
|
||||
*/
|
||||
async PVsync();
|
||||
|
||||
/**
|
||||
* Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the
|
||||
* widget's shareable window on the chrome side. Only used on Windows.
|
||||
|
|
|
@ -4,41 +4,37 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PBrowser;
|
||||
include "mozilla/layers/LayersMessageUtils.h";
|
||||
|
||||
using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
|
||||
using mozilla::VsyncEvent from "mozilla/VsyncDispatcher.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace layout {
|
||||
namespace dom {
|
||||
|
||||
/*
|
||||
* The PVsync is a sub-protocol in PBackground and it is used to notify
|
||||
* the vsync event from chrome to content process. It also provides the
|
||||
* The PVsync is a sub-protocol in PBackground or PBrowser and it is used to
|
||||
* notify the vsync event from chrome to content process. It also provides the
|
||||
* interfaces for content to observe/unobserve vsync event notifications.
|
||||
*/
|
||||
async protocol PVsync
|
||||
{
|
||||
manager PBackground;
|
||||
manager PBackground or PBrowser;
|
||||
|
||||
child:
|
||||
// Send vsync event from chrome to content process.
|
||||
prio(high) async Notify(VsyncEvent aVsync) compress;
|
||||
|
||||
// Send the vsync rate to the content process.
|
||||
async VsyncRate(float aVsyncRate);
|
||||
// Send vsync event and vsync rate from chrome to content process.
|
||||
prio(high) async Notify(VsyncEvent aVsync, float aVsyncRate) compress;
|
||||
|
||||
parent:
|
||||
// Content process use these messages to acquire the vsync event.
|
||||
async Observe();
|
||||
async Unobserve();
|
||||
async RequestVsyncRate();
|
||||
|
||||
// This message is never sent. Each PVsync actor will stay alive as long as
|
||||
// its PBackground manager.
|
||||
// its PBackground or PBrowser manager.
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace layout
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
@ -10,17 +10,17 @@
|
|||
#include "mozilla/VsyncDispatcher.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla::layout {
|
||||
namespace mozilla::dom {
|
||||
|
||||
VsyncChild::VsyncChild()
|
||||
: mObservingVsync(false),
|
||||
mIsShutdown(false),
|
||||
: mIsShutdown(false),
|
||||
mVsyncRate(TimeDuration::Forever()) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
VsyncChild::~VsyncChild() { MOZ_ASSERT(NS_IsMainThread()); }
|
||||
|
||||
/* do not delete yet so the file history is preserved
|
||||
bool VsyncChild::SendObserve() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mObservingVsync && !mIsShutdown) {
|
||||
|
@ -38,43 +38,61 @@ bool VsyncChild::SendUnobserve() {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
void VsyncChild::AddChildRefreshTimer(VsyncObserver* aVsyncObserver) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mObservers.Contains(aVsyncObserver));
|
||||
|
||||
if (mIsShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mObservers.IsEmpty()) {
|
||||
Unused << PVsyncChild::SendObserve();
|
||||
}
|
||||
mObservers.AppendElement(std::move(aVsyncObserver));
|
||||
}
|
||||
|
||||
void VsyncChild::RemoveChildRefreshTimer(VsyncObserver* aVsyncObserver) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mIsShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mObservers.RemoveElement(aVsyncObserver) && mObservers.IsEmpty()) {
|
||||
Unused << PVsyncChild::SendUnobserve();
|
||||
}
|
||||
}
|
||||
|
||||
void VsyncChild::ActorDestroy(ActorDestroyReason aActorDestroyReason) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
mIsShutdown = true;
|
||||
mObserver = nullptr;
|
||||
|
||||
if (!mObservers.IsEmpty()) {
|
||||
Unused << PVsyncChild::SendUnobserve();
|
||||
}
|
||||
mObservers.Clear();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult VsyncChild::RecvNotify(const VsyncEvent& aVsync) {
|
||||
mozilla::ipc::IPCResult VsyncChild::RecvNotify(const VsyncEvent& aVsync,
|
||||
const float& aVsyncRate) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
|
||||
SchedulerGroup::MarkVsyncRan();
|
||||
if (mObservingVsync && mObserver) {
|
||||
mObserver->NotifyVsync(aVsync);
|
||||
|
||||
mVsyncRate = TimeDuration::FromMilliseconds(aVsyncRate);
|
||||
|
||||
for (VsyncObserver* observer : mObservers.ForwardRange()) {
|
||||
observer->NotifyVsync(aVsync);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void VsyncChild::SetVsyncObserver(VsyncObserver* aVsyncObserver) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mObserver = aVsyncObserver;
|
||||
}
|
||||
|
||||
TimeDuration VsyncChild::GetVsyncRate() {
|
||||
if (mVsyncRate == TimeDuration::Forever()) {
|
||||
PVsyncChild::SendRequestVsyncRate();
|
||||
}
|
||||
|
||||
return mVsyncRate;
|
||||
}
|
||||
|
||||
TimeDuration VsyncChild::VsyncRate() { return mVsyncRate; }
|
||||
|
||||
mozilla::ipc::IPCResult VsyncChild::RecvVsyncRate(const float& aVsyncRate) {
|
||||
mVsyncRate = TimeDuration::FromMilliseconds(aVsyncRate);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace mozilla::layout
|
||||
} // namespace mozilla::dom
|
|
@ -4,22 +4,19 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_layout_ipc_VsyncChild_h
|
||||
#define mozilla_layout_ipc_VsyncChild_h
|
||||
#ifndef mozilla_dom_ipc_VsyncChild_h
|
||||
#define mozilla_dom_ipc_VsyncChild_h
|
||||
|
||||
#include "mozilla/layout/PVsyncChild.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/dom/PVsyncChild.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsTObserverArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class VsyncObserver;
|
||||
|
||||
namespace ipc {
|
||||
class BackgroundChildImpl;
|
||||
} // namespace ipc
|
||||
|
||||
namespace layout {
|
||||
namespace dom {
|
||||
|
||||
// The PVsyncChild actor receives a vsync event from the main process and
|
||||
// delivers it to the child process. Currently this is restricted to the main
|
||||
|
@ -28,15 +25,17 @@ namespace layout {
|
|||
class VsyncChild final : public PVsyncChild {
|
||||
NS_INLINE_DECL_REFCOUNTING(VsyncChild)
|
||||
|
||||
friend class mozilla::ipc::BackgroundChildImpl;
|
||||
friend class PVsyncChild;
|
||||
|
||||
public:
|
||||
// Hide the SendObserve/SendUnobserve in PVsyncChild. We add an flag
|
||||
// mObservingVsync to handle the race problem of unobserving vsync event.
|
||||
bool SendObserve();
|
||||
bool SendUnobserve();
|
||||
VsyncChild();
|
||||
|
||||
void AddChildRefreshTimer(VsyncObserver* aVsyncObserver);
|
||||
void RemoveChildRefreshTimer(VsyncObserver* aVsyncObserver);
|
||||
|
||||
TimeDuration GetVsyncRate();
|
||||
|
||||
/*
|
||||
// Bind a VsyncObserver into VsyncChild after ipc channel connected.
|
||||
void SetVsyncObserver(VsyncObserver* aVsyncObserver);
|
||||
// GetVsyncRate is a getter for mVsyncRate which sends a requests to
|
||||
|
@ -48,24 +47,21 @@ class VsyncChild final : public PVsyncChild {
|
|||
// TimeDuration::Forever() if mVsyncRate hasn't been set by calling
|
||||
// GetVsyncRate.
|
||||
TimeDuration VsyncRate();
|
||||
*/
|
||||
|
||||
private:
|
||||
VsyncChild();
|
||||
virtual ~VsyncChild();
|
||||
|
||||
mozilla::ipc::IPCResult RecvNotify(const VsyncEvent& aVsync);
|
||||
mozilla::ipc::IPCResult RecvVsyncRate(const float& aVsyncRate);
|
||||
mozilla::ipc::IPCResult RecvNotify(const VsyncEvent& aVsync,
|
||||
const float& aVsyncRate);
|
||||
virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
|
||||
|
||||
bool mObservingVsync;
|
||||
bool mIsShutdown;
|
||||
|
||||
// The content side vsync observer.
|
||||
RefPtr<VsyncObserver> mObserver;
|
||||
TimeDuration mVsyncRate;
|
||||
nsTObserverArray<VsyncObserver*> mObservers;
|
||||
};
|
||||
|
||||
} // namespace layout
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_layout_ipc_VsyncChild_h
|
||||
#endif // mozilla_dom_ipc_VsyncChild_h
|
|
@ -13,48 +13,45 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "VsyncSource.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace ipc;
|
||||
|
||||
namespace layout {
|
||||
|
||||
/*static*/
|
||||
already_AddRefed<VsyncParent> VsyncParent::Create() {
|
||||
AssertIsOnBackgroundThread();
|
||||
RefPtr<gfx::VsyncSource> vsyncSource =
|
||||
gfxPlatform::GetPlatform()->GetHardwareVsync();
|
||||
RefPtr<VsyncParent> vsyncParent = new VsyncParent();
|
||||
vsyncParent->mVsyncDispatcher = vsyncSource->GetRefreshTimerVsyncDispatcher();
|
||||
return vsyncParent.forget();
|
||||
}
|
||||
namespace mozilla::dom {
|
||||
|
||||
VsyncParent::VsyncParent()
|
||||
: mObservingVsync(false),
|
||||
mDestroyed(false),
|
||||
mBackgroundThread(NS_GetCurrentThread()) {
|
||||
MOZ_ASSERT(mBackgroundThread);
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
mInitialThread(NS_GetCurrentThread()) {}
|
||||
|
||||
VsyncParent::~VsyncParent() {
|
||||
// Since we use NS_INLINE_DECL_THREADSAFE_REFCOUNTING, we can't make sure
|
||||
// VsyncParent is always released on the background thread.
|
||||
void VsyncParent::UpdateVsyncSource(
|
||||
const RefPtr<gfx::VsyncSource>& aVsyncSource) {
|
||||
mVsyncSource = aVsyncSource;
|
||||
if (!mVsyncSource) {
|
||||
mVsyncSource = gfxPlatform::GetPlatform()->GetHardwareVsync();
|
||||
}
|
||||
|
||||
if (mObservingVsync) {
|
||||
mVsyncDispatcher->RemoveChildRefreshTimer(this);
|
||||
}
|
||||
mVsyncDispatcher = mVsyncSource->GetRefreshTimerVsyncDispatcher();
|
||||
if (mObservingVsync) {
|
||||
mVsyncDispatcher->AddChildRefreshTimer(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool VsyncParent::NotifyVsync(const VsyncEvent& aVsync) {
|
||||
if (IsOnInitialThread()) {
|
||||
DispatchVsyncEvent(aVsync);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called on hardware vsync thread. We should post to current ipc thread.
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
nsCOMPtr<nsIRunnable> vsyncEvent = NewRunnableMethod<VsyncEvent>(
|
||||
"layout::VsyncParent::DispatchVsyncEvent", this,
|
||||
"dom::VsyncParent::DispatchVsyncEvent", this,
|
||||
&VsyncParent::DispatchVsyncEvent, aVsync);
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
mBackgroundThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL));
|
||||
MOZ_ALWAYS_SUCCEEDS(mInitialThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL));
|
||||
return true;
|
||||
}
|
||||
|
||||
void VsyncParent::DispatchVsyncEvent(const VsyncEvent& aVsync) {
|
||||
AssertIsOnBackgroundThread();
|
||||
AssertIsOnInitialThread();
|
||||
|
||||
// If we call NotifyVsync() when we handle ActorDestroy() message, we might
|
||||
// still call DispatchVsyncEvent().
|
||||
|
@ -62,22 +59,13 @@ void VsyncParent::DispatchVsyncEvent(const VsyncEvent& aVsync) {
|
|||
// NotifyVsync(). We use mObservingVsync and mDestroyed flags to skip this
|
||||
// notification.
|
||||
if (mObservingVsync && !mDestroyed) {
|
||||
Unused << SendNotify(aVsync);
|
||||
TimeDuration vsyncRate = mVsyncSource->GetGlobalDisplay().GetVsyncRate();
|
||||
Unused << SendNotify(aVsync, vsyncRate.ToMilliseconds());
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult VsyncParent::RecvRequestVsyncRate() {
|
||||
AssertIsOnBackgroundThread();
|
||||
TimeDuration vsyncRate = gfxPlatform::GetPlatform()
|
||||
->GetHardwareVsync()
|
||||
->GetGlobalDisplay()
|
||||
.GetVsyncRate();
|
||||
Unused << SendVsyncRate(vsyncRate.ToMilliseconds());
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult VsyncParent::RecvObserve() {
|
||||
AssertIsOnBackgroundThread();
|
||||
AssertIsOnInitialThread();
|
||||
if (!mObservingVsync) {
|
||||
mVsyncDispatcher->AddChildRefreshTimer(this);
|
||||
mObservingVsync = true;
|
||||
|
@ -87,7 +75,7 @@ mozilla::ipc::IPCResult VsyncParent::RecvObserve() {
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult VsyncParent::RecvUnobserve() {
|
||||
AssertIsOnBackgroundThread();
|
||||
AssertIsOnInitialThread();
|
||||
if (mObservingVsync) {
|
||||
mVsyncDispatcher->RemoveChildRefreshTimer(this);
|
||||
mObservingVsync = false;
|
||||
|
@ -96,9 +84,9 @@ mozilla::ipc::IPCResult VsyncParent::RecvUnobserve() {
|
|||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
void VsyncParent::ActorDestroy(ActorDestroyReason aReason) {
|
||||
void VsyncParent::ActorDestroy(ActorDestroyReason aActorDestroyReason) {
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
AssertIsOnBackgroundThread();
|
||||
AssertIsOnInitialThread();
|
||||
if (mObservingVsync) {
|
||||
mVsyncDispatcher->RemoveChildRefreshTimer(this);
|
||||
}
|
||||
|
@ -106,5 +94,10 @@ void VsyncParent::ActorDestroy(ActorDestroyReason aReason) {
|
|||
mDestroyed = true;
|
||||
}
|
||||
|
||||
} // namespace layout
|
||||
} // namespace mozilla
|
||||
bool VsyncParent::IsOnInitialThread() {
|
||||
return NS_GetCurrentThread() == mInitialThread;
|
||||
}
|
||||
|
||||
void VsyncParent::AssertIsOnInitialThread() { MOZ_ASSERT(IsOnInitialThread()); }
|
||||
|
||||
} // namespace mozilla::dom
|
|
@ -4,53 +4,51 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_layout_ipc_VsyncParent_h
|
||||
#define mozilla_layout_ipc_VsyncParent_h
|
||||
#ifndef mozilla_dom_ipc_VsyncParent_h
|
||||
#define mozilla_dom_ipc_VsyncParent_h
|
||||
|
||||
#include "mozilla/layout/PVsyncParent.h"
|
||||
#include "mozilla/dom/PVsyncParent.h"
|
||||
#include "mozilla/VsyncDispatcher.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "VsyncSource.h"
|
||||
|
||||
class nsIThread;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace ipc {
|
||||
class BackgroundParentImpl;
|
||||
} // namespace ipc
|
||||
|
||||
namespace layout {
|
||||
namespace mozilla::dom {
|
||||
|
||||
// Use PBackground thread in the main process to send vsync notifications to
|
||||
// content process. This actor will be released when its parent protocol calls
|
||||
// DeallocPVsyncParent().
|
||||
class VsyncParent final : public PVsyncParent, public VsyncObserver {
|
||||
friend class mozilla::ipc::BackgroundParentImpl;
|
||||
friend class PVsyncParent;
|
||||
|
||||
private:
|
||||
static already_AddRefed<VsyncParent> Create();
|
||||
|
||||
public:
|
||||
VsyncParent();
|
||||
virtual ~VsyncParent();
|
||||
void UpdateVsyncSource(const RefPtr<gfx::VsyncSource>& aVsyncSource);
|
||||
|
||||
private:
|
||||
virtual ~VsyncParent() = default;
|
||||
|
||||
virtual bool NotifyVsync(const VsyncEvent& aVsync) override;
|
||||
mozilla::ipc::IPCResult RecvRequestVsyncRate();
|
||||
virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvObserve();
|
||||
mozilla::ipc::IPCResult RecvUnobserve();
|
||||
virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
|
||||
|
||||
void DispatchVsyncEvent(const VsyncEvent& aVsync);
|
||||
void UpdateVsyncRate();
|
||||
|
||||
bool IsOnInitialThread();
|
||||
void AssertIsOnInitialThread();
|
||||
|
||||
bool mObservingVsync;
|
||||
bool mDestroyed;
|
||||
nsCOMPtr<nsIThread> mBackgroundThread;
|
||||
nsCOMPtr<nsIThread> mInitialThread;
|
||||
RefPtr<gfx::VsyncSource> mVsyncSource;
|
||||
RefPtr<RefreshTimerVsyncDispatcher> mVsyncDispatcher;
|
||||
};
|
||||
|
||||
} // namespace layout
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_layout_ipc_VsyncParent_h
|
||||
#endif // mozilla_dom_ipc_VsyncParent_h
|
|
@ -71,6 +71,8 @@ EXPORTS.mozilla.dom += [
|
|||
"URLClassifierChild.h",
|
||||
"URLClassifierParent.h",
|
||||
"UserActivationIPCUtils.h",
|
||||
"VsyncChild.h",
|
||||
"VsyncParent.h",
|
||||
"WindowGlobalActor.h",
|
||||
"WindowGlobalChild.h",
|
||||
"WindowGlobalParent.h",
|
||||
|
@ -130,6 +132,8 @@ UNIFIED_SOURCES += [
|
|||
SOURCES += [
|
||||
"ContentChild.cpp",
|
||||
"ProcessHangMonitor.cpp",
|
||||
"VsyncChild.cpp",
|
||||
"VsyncParent.cpp",
|
||||
]
|
||||
|
||||
PREPROCESSED_IPDL_SOURCES += [
|
||||
|
@ -155,6 +159,7 @@ IPDL_SOURCES += [
|
|||
"PURLClassifier.ipdl",
|
||||
"PURLClassifierInfo.ipdlh",
|
||||
"PURLClassifierLocal.ipdl",
|
||||
"PVsync.ipdl",
|
||||
"PWindowGlobal.ipdl",
|
||||
"ServiceWorkerConfiguration.ipdlh",
|
||||
"WindowGlobalTypes.ipdlh",
|
||||
|
|
|
@ -46,11 +46,11 @@
|
|||
#include "mozilla/dom/ServiceWorkerContainerChild.h"
|
||||
#include "mozilla/dom/ServiceWorkerManagerChild.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/VsyncChild.h"
|
||||
#include "mozilla/ipc/IPCStreamAlloc.h"
|
||||
#include "mozilla/ipc/PBackgroundTestChild.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamChild.h"
|
||||
#include "mozilla/ipc/PParentToChildStreamChild.h"
|
||||
#include "mozilla/layout/VsyncChild.h"
|
||||
#include "mozilla/net/HttpBackgroundChannelChild.h"
|
||||
#include "mozilla/net/PUDPSocketChild.h"
|
||||
#include "mozilla/dom/network/UDPSocketChild.h"
|
||||
|
@ -408,8 +408,8 @@ bool BackgroundChildImpl::DeallocPFileDescriptorSetChild(
|
|||
return true;
|
||||
}
|
||||
|
||||
BackgroundChildImpl::PVsyncChild* BackgroundChildImpl::AllocPVsyncChild() {
|
||||
RefPtr<mozilla::layout::VsyncChild> actor = new mozilla::layout::VsyncChild();
|
||||
dom::PVsyncChild* BackgroundChildImpl::AllocPVsyncChild() {
|
||||
RefPtr<dom::VsyncChild> actor = new dom::VsyncChild();
|
||||
// There still has one ref-count after return, and it will be released in
|
||||
// DeallocPVsyncChild().
|
||||
return actor.forget().take();
|
||||
|
@ -419,8 +419,8 @@ bool BackgroundChildImpl::DeallocPVsyncChild(PVsyncChild* aActor) {
|
|||
MOZ_ASSERT(aActor);
|
||||
|
||||
// This actor already has one ref-count. Please check AllocPVsyncChild().
|
||||
RefPtr<mozilla::layout::VsyncChild> actor =
|
||||
dont_AddRef(static_cast<mozilla::layout::VsyncChild*>(aActor));
|
||||
RefPtr<dom::VsyncChild> actor =
|
||||
dont_AddRef(static_cast<dom::VsyncChild*>(aActor));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -619,7 +619,7 @@ bool BackgroundChildImpl::DeallocPClientManagerChild(
|
|||
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
void BackgroundChildImpl::OnChannelReceivedMessage(const Message& aMsg) {
|
||||
if (aMsg.type() == layout::PVsync::MessageType::Msg_Notify__ID) {
|
||||
if (aMsg.type() == dom::PVsync::MessageType::Msg_Notify__ID) {
|
||||
// Not really necessary to look at the message payload, it will be
|
||||
// <0.5ms away from TimeStamp::Now()
|
||||
SchedulerGroup::MarkVsyncReceived();
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "mozilla/dom/network/UDPSocketParent.h"
|
||||
#include "mozilla/dom/quota/ActorsParent.h"
|
||||
#include "mozilla/dom/simpledb/ActorsParent.h"
|
||||
#include "mozilla/dom/VsyncParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/Endpoint.h"
|
||||
|
@ -64,7 +65,6 @@
|
|||
#include "mozilla/ipc/PBackgroundTestParent.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamParent.h"
|
||||
#include "mozilla/ipc/PParentToChildStreamParent.h"
|
||||
#include "mozilla/layout/VsyncParent.h"
|
||||
#include "mozilla/media/MediaParent.h"
|
||||
#include "mozilla/net/BackgroundDataBridgeParent.h"
|
||||
#include "mozilla/net/HttpBackgroundChannelParent.h"
|
||||
|
@ -717,8 +717,8 @@ BackgroundParentImpl::PVsyncParent* BackgroundParentImpl::AllocPVsyncParent() {
|
|||
AssertIsInMainOrSocketProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
RefPtr<mozilla::layout::VsyncParent> actor =
|
||||
mozilla::layout::VsyncParent::Create();
|
||||
RefPtr<mozilla::dom::VsyncParent> actor = new mozilla::dom::VsyncParent();
|
||||
actor->UpdateVsyncSource(nullptr);
|
||||
// There still has one ref-count after return, and it will be released in
|
||||
// DeallocPVsyncParent().
|
||||
return actor.forget().take();
|
||||
|
@ -730,8 +730,8 @@ bool BackgroundParentImpl::DeallocPVsyncParent(PVsyncParent* aActor) {
|
|||
MOZ_ASSERT(aActor);
|
||||
|
||||
// This actor already has one ref-count. Please check AllocPVsyncParent().
|
||||
RefPtr<mozilla::layout::VsyncParent> actor =
|
||||
dont_AddRef(static_cast<mozilla::layout::VsyncParent*>(aActor));
|
||||
RefPtr<mozilla::dom::VsyncParent> actor =
|
||||
dont_AddRef(static_cast<mozilla::dom::VsyncParent*>(aActor));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,11 +12,6 @@
|
|||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layout {
|
||||
class VsyncParent;
|
||||
} // namespace layout
|
||||
|
||||
namespace ipc {
|
||||
|
||||
// Instances of this class should never be created directly. This class is meant
|
||||
|
|
|
@ -692,9 +692,6 @@ nsresult nsPresContext::Init(nsDeviceContext* aDeviceContext) {
|
|||
|
||||
if (!mRefreshDriver) {
|
||||
mRefreshDriver = new nsRefreshDriver(this);
|
||||
if (XRE_IsContentProcess()) {
|
||||
mRefreshDriver->InitializeTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,10 +59,12 @@
|
|||
#include "nsViewManager.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/CallbackDebuggerNotification.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/Performance.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/dom/VsyncChild.h"
|
||||
#include "mozilla/dom/WindowBinding.h"
|
||||
#include "mozilla/RestyleManager.h"
|
||||
#include "Layers.h"
|
||||
|
@ -75,7 +77,6 @@
|
|||
|
||||
#include "BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/layout/VsyncChild.h"
|
||||
#include "VsyncSource.h"
|
||||
#include "mozilla/VsyncDispatcher.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
@ -246,26 +247,6 @@ class RefreshDriverTimer {
|
|||
|
||||
TimeStamp MostRecentRefresh() const { return mLastFireTime; }
|
||||
|
||||
void SwapRefreshDrivers(RefreshDriverTimer* aNewTimer) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
for (nsRefreshDriver* driver : mContentRefreshDrivers) {
|
||||
aNewTimer->AddRefreshDriver(driver);
|
||||
driver->mActiveTimer = aNewTimer;
|
||||
}
|
||||
mContentRefreshDrivers.Clear();
|
||||
|
||||
for (nsRefreshDriver* driver : mRootRefreshDrivers) {
|
||||
aNewTimer->AddRefreshDriver(driver);
|
||||
driver->mActiveTimer = aNewTimer;
|
||||
}
|
||||
mRootRefreshDrivers.Clear();
|
||||
|
||||
aNewTimer->mLastFireTime = mLastFireTime;
|
||||
|
||||
StopTimer();
|
||||
}
|
||||
|
||||
virtual TimeDuration GetTimerRate() = 0;
|
||||
|
||||
TimeStamp GetIdleDeadlineHint(TimeStamp aDefault) {
|
||||
|
@ -446,56 +427,48 @@ class SimpleTimerBasedRefreshDriverTimer : public RefreshDriverTimer {
|
|||
*/
|
||||
class VsyncRefreshDriverTimer : public RefreshDriverTimer {
|
||||
public:
|
||||
VsyncRefreshDriverTimer() : mVsyncChild(nullptr) {
|
||||
VsyncRefreshDriverTimer()
|
||||
: mVsyncDispatcher(nullptr),
|
||||
mVsyncChild(nullptr),
|
||||
mVsyncRate(TimeDuration::Forever()) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mVsyncSource = gfxPlatform::GetPlatform()->GetHardwareVsync();
|
||||
mVsyncObserver = new RefreshDriverVsyncObserver(this);
|
||||
RefPtr<mozilla::gfx::VsyncSource> vsyncSource =
|
||||
gfxPlatform::GetPlatform()->GetHardwareVsync();
|
||||
MOZ_ALWAYS_TRUE(mVsyncDispatcher =
|
||||
vsyncSource->GetRefreshTimerVsyncDispatcher());
|
||||
mVsyncDispatcher->AddChildRefreshTimer(mVsyncObserver);
|
||||
mVsyncRate = vsyncSource->GetGlobalDisplay().GetVsyncRate();
|
||||
}
|
||||
|
||||
explicit VsyncRefreshDriverTimer(VsyncChild* aVsyncChild)
|
||||
: mVsyncChild(aVsyncChild) {
|
||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mVsyncChild);
|
||||
mVsyncObserver = new RefreshDriverVsyncObserver(this);
|
||||
mVsyncChild->SetVsyncObserver(mVsyncObserver);
|
||||
mVsyncRate = mVsyncChild->GetVsyncRate();
|
||||
mVsyncSource->GetRefreshTimerVsyncDispatcher());
|
||||
}
|
||||
|
||||
// Constructor for when we have a local vsync source. As it is local, we do
|
||||
// not have to worry about it being re-inited by gfxPlatform on frame rate
|
||||
// change on the global source.
|
||||
explicit VsyncRefreshDriverTimer(const RefPtr<gfx::VsyncSource>& aVsyncSource)
|
||||
: mVsyncChild(nullptr) {
|
||||
: mVsyncSource(aVsyncSource),
|
||||
mVsyncDispatcher(nullptr),
|
||||
mVsyncChild(nullptr),
|
||||
mVsyncRate(TimeDuration::Forever()) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mVsyncSource = aVsyncSource;
|
||||
mVsyncObserver = new RefreshDriverVsyncObserver(this);
|
||||
MOZ_ALWAYS_TRUE(mVsyncDispatcher =
|
||||
aVsyncSource->GetRefreshTimerVsyncDispatcher());
|
||||
mVsyncDispatcher->AddChildRefreshTimer(mVsyncObserver);
|
||||
mVsyncRate = aVsyncSource->GetGlobalDisplay().GetVsyncRate();
|
||||
}
|
||||
|
||||
explicit VsyncRefreshDriverTimer(const RefPtr<VsyncChild>& aVsyncChild)
|
||||
: mVsyncSource(nullptr),
|
||||
mVsyncDispatcher(nullptr),
|
||||
mVsyncChild(aVsyncChild),
|
||||
mVsyncRate(TimeDuration::Forever()) {
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mVsyncObserver = new RefreshDriverVsyncObserver(this);
|
||||
}
|
||||
|
||||
TimeDuration GetTimerRate() override {
|
||||
if (mVsyncRate != TimeDuration::Forever()) {
|
||||
return mVsyncRate;
|
||||
}
|
||||
|
||||
if (mVsyncChild) {
|
||||
// VsyncChild::VsyncRate() is a simple getter for the cached
|
||||
// hardware vsync rate. We depend on that
|
||||
// VsyncChild::GetVsyncRate() being called in the constructor
|
||||
// will result in a response with the actual vsync rate sooner
|
||||
// or later. Until that happens VsyncChild::VsyncRate() returns
|
||||
// TimeDuration::Forever() and we have to guess below.
|
||||
mVsyncRate = mVsyncChild->VsyncRate();
|
||||
if (mVsyncSource) {
|
||||
mVsyncRate = mVsyncSource->GetGlobalDisplay().GetVsyncRate();
|
||||
} else if (mVsyncChild) {
|
||||
mVsyncRate = mVsyncChild->GetVsyncRate();
|
||||
}
|
||||
|
||||
// If hardware queries fail / are unsupported, we have to just guess.
|
||||
|
@ -772,16 +745,11 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer {
|
|||
}; // RefreshDriverVsyncObserver
|
||||
|
||||
~VsyncRefreshDriverTimer() override {
|
||||
if (XRE_IsParentProcess()) {
|
||||
if (mVsyncDispatcher) {
|
||||
mVsyncDispatcher->RemoveChildRefreshTimer(mVsyncObserver);
|
||||
mVsyncDispatcher = nullptr;
|
||||
} else {
|
||||
// Since the PVsyncChild actors live through the life of the process, just
|
||||
// send the unobserveVsync message to disable vsync event. We don't need
|
||||
// to handle the cleanup stuff of this actor. PVsyncChild::ActorDestroy()
|
||||
// will be called and clean up this actor.
|
||||
Unused << mVsyncChild->SendUnobserve();
|
||||
mVsyncChild->SetVsyncObserver(nullptr);
|
||||
} else if (mVsyncChild) {
|
||||
mVsyncChild->RemoveChildRefreshTimer(mVsyncObserver);
|
||||
mVsyncChild = nullptr;
|
||||
}
|
||||
|
||||
|
@ -797,10 +765,10 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer {
|
|||
|
||||
mLastFireTime = TimeStamp::Now();
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
if (mVsyncDispatcher) {
|
||||
mVsyncDispatcher->AddChildRefreshTimer(mVsyncObserver);
|
||||
} else {
|
||||
Unused << mVsyncChild->SendObserve();
|
||||
} else if (mVsyncChild) {
|
||||
mVsyncChild->AddChildRefreshTimer(mVsyncObserver);
|
||||
mVsyncObserver->OnTimerStart();
|
||||
}
|
||||
|
||||
|
@ -811,10 +779,10 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer {
|
|||
// Protect updates to `sActiveVsyncTimers`.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
if (mVsyncDispatcher) {
|
||||
mVsyncDispatcher->RemoveChildRefreshTimer(mVsyncObserver);
|
||||
} else {
|
||||
Unused << mVsyncChild->SendUnobserve();
|
||||
} else if (mVsyncChild) {
|
||||
mVsyncChild->RemoveChildRefreshTimer(mVsyncObserver);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(sActiveVsyncTimers > 0);
|
||||
|
@ -1007,33 +975,12 @@ class InactiveRefreshDriverTimer final
|
|||
} // namespace mozilla
|
||||
|
||||
static StaticRefPtr<RefreshDriverTimer> sRegularRateTimer;
|
||||
static nsTArray<RefreshDriverTimer*>* sRegularRateTimerList;
|
||||
static StaticRefPtr<InactiveRefreshDriverTimer> sThrottledRateTimer;
|
||||
|
||||
static void CreateContentVsyncRefreshTimer(void*) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||
|
||||
// Create the PVsync actor child for vsync-base refresh timer.
|
||||
// PBackgroundChild is created synchronously. We will still use software
|
||||
// timer before PVsync ready, and change to use hw timer when the connection
|
||||
// is done. Please check nsRefreshDriver::PVsyncActorCreated().
|
||||
|
||||
PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
|
||||
if (NS_WARN_IF(!actorChild)) {
|
||||
return;
|
||||
}
|
||||
|
||||
layout::PVsyncChild* actor = actorChild->SendPVsyncConstructor();
|
||||
if (NS_WARN_IF(!actor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
layout::VsyncChild* child = static_cast<layout::VsyncChild*>(actor);
|
||||
nsRefreshDriver::PVsyncActorCreated(child);
|
||||
}
|
||||
|
||||
void nsRefreshDriver::CreateVsyncRefreshTimer() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mOwnTimer);
|
||||
|
||||
PodArrayZero(sJankLevels);
|
||||
|
||||
|
@ -1042,32 +989,29 @@ void nsRefreshDriver::CreateVsyncRefreshTimer() {
|
|||
}
|
||||
|
||||
// If available, we fetch the widget-specific vsync source.
|
||||
//
|
||||
// NOTE(heycam): If we are initializing an nsRefreshDriver under
|
||||
// nsPresContext::Init, then this GetRootWidget() call will fail, as the
|
||||
// pres context does not yet have a pres shell. For now, null check the
|
||||
// pres shell to avoid a console warning.
|
||||
nsPresContext* pc = GetPresContext();
|
||||
nsIWidget* widget = pc->GetPresShell() ? pc->GetRootWidget() : nullptr;
|
||||
nsIWidget* widget = pc->GetRootWidget();
|
||||
if (widget) {
|
||||
RefPtr<gfx::VsyncSource> localVsyncSource = widget->GetVsyncSource();
|
||||
if (localVsyncSource) {
|
||||
if (RefPtr<gfx::VsyncSource> localVsyncSource = widget->GetVsyncSource()) {
|
||||
mOwnTimer = new VsyncRefreshDriverTimer(localVsyncSource);
|
||||
sRegularRateTimerList->AppendElement(mOwnTimer.get());
|
||||
return;
|
||||
}
|
||||
if (BrowserChild* browserChild = widget->GetOwningBrowserChild()) {
|
||||
if (RefPtr<VsyncChild> localVsyncSource = browserChild->GetVsyncChild()) {
|
||||
mOwnTimer = new VsyncRefreshDriverTimer(localVsyncSource);
|
||||
sRegularRateTimerList->AppendElement(mOwnTimer.get());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
if (!sRegularRateTimer && XRE_IsParentProcess()) {
|
||||
// Make sure all vsync systems are ready.
|
||||
gfxPlatform::GetPlatform();
|
||||
// In parent process, we don't need to use ipc. We can create the
|
||||
// VsyncRefreshDriverTimer directly.
|
||||
// In parent process, we can create the VsyncRefreshDriverTimer directly.
|
||||
sRegularRateTimer = new VsyncRefreshDriverTimer();
|
||||
return;
|
||||
sRegularRateTimerList->AppendElement(sRegularRateTimer);
|
||||
}
|
||||
|
||||
// If this process is not created by NUWA, just create the vsync timer here.
|
||||
CreateContentVsyncRefreshTimer(nullptr);
|
||||
}
|
||||
|
||||
static uint32_t GetFirstFrameDelay(imgIRequest* req) {
|
||||
|
@ -1085,8 +1029,11 @@ static uint32_t GetFirstFrameDelay(imgIRequest* req) {
|
|||
|
||||
/* static */
|
||||
void nsRefreshDriver::Shutdown() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// clean up our timers
|
||||
sRegularRateTimer = nullptr;
|
||||
delete sRegularRateTimerList;
|
||||
sRegularRateTimerList = nullptr;
|
||||
sThrottledRateTimer = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1142,25 +1089,20 @@ RefreshDriverTimer* nsRefreshDriver::ChooseTimer() {
|
|||
return sThrottledRateTimer;
|
||||
}
|
||||
|
||||
if (!sRegularRateTimer && !mOwnTimer) {
|
||||
double rate = GetRegularTimerInterval();
|
||||
|
||||
// Try to use vsync-base refresh timer first for sRegularRateTimer.
|
||||
if (!mOwnTimer) {
|
||||
CreateVsyncRefreshTimer();
|
||||
|
||||
if (mOwnTimer) {
|
||||
return mOwnTimer.get();
|
||||
}
|
||||
|
||||
if (!sRegularRateTimer) {
|
||||
sRegularRateTimer = new StartupRefreshDriverTimer(rate);
|
||||
}
|
||||
}
|
||||
|
||||
if (mOwnTimer) {
|
||||
return mOwnTimer.get();
|
||||
}
|
||||
|
||||
if (!sRegularRateTimer) {
|
||||
double rate = GetRegularTimerInterval();
|
||||
sRegularRateTimer = new StartupRefreshDriverTimer(rate);
|
||||
sRegularRateTimerList->AppendElement(sRegularRateTimer);
|
||||
}
|
||||
|
||||
return sRegularRateTimer;
|
||||
}
|
||||
|
||||
|
@ -1196,6 +1138,9 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext)
|
|||
mNextThrottledFrameRequestTick = mMostRecentRefresh;
|
||||
mNextRecomputeVisibilityTick = mMostRecentRefresh;
|
||||
|
||||
if (!sRegularRateTimerList) {
|
||||
sRegularRateTimerList = new nsTArray<RefreshDriverTimer*>();
|
||||
}
|
||||
++sRefreshDriverCount;
|
||||
}
|
||||
|
||||
|
@ -1213,6 +1158,9 @@ nsRefreshDriver::~nsRefreshDriver() {
|
|||
mRootRefresh->RemoveRefreshObserver(this, FlushType::Style);
|
||||
mRootRefresh = nullptr;
|
||||
}
|
||||
if (mOwnTimer && sRegularRateTimerList) {
|
||||
sRegularRateTimerList->RemoveElement(mOwnTimer.get());
|
||||
}
|
||||
}
|
||||
|
||||
// Method for testing. See nsIDOMWindowUtils.advanceTimeAndRefresh
|
||||
|
@ -2675,21 +2623,6 @@ void nsRefreshDriver::SetThrottled(bool aThrottled) {
|
|||
|
||||
nsPresContext* nsRefreshDriver::GetPresContext() const { return mPresContext; }
|
||||
|
||||
/*static*/
|
||||
void nsRefreshDriver::PVsyncActorCreated(VsyncChild* aVsyncChild) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||
RefPtr<RefreshDriverTimer> vsyncRefreshDriverTimer =
|
||||
new VsyncRefreshDriverTimer(aVsyncChild);
|
||||
|
||||
// If we are using software timer, swap current timer to
|
||||
// VsyncRefreshDriverTimer.
|
||||
if (sRegularRateTimer) {
|
||||
sRegularRateTimer->SwapRefreshDrivers(vsyncRefreshDriverTimer);
|
||||
}
|
||||
sRegularRateTimer = std::move(vsyncRefreshDriverTimer);
|
||||
}
|
||||
|
||||
void nsRefreshDriver::DoRefresh() {
|
||||
// Don't do a refresh unless we're in a state where we should be refreshing.
|
||||
if (!IsFrozen() && mPresContext && mActiveTimer) {
|
||||
|
@ -2766,27 +2699,40 @@ TimeStamp nsRefreshDriver::GetIdleDeadlineHint(TimeStamp aDefault) {
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aDefault.IsNull());
|
||||
|
||||
if (!sRegularRateTimer) {
|
||||
return aDefault;
|
||||
}
|
||||
|
||||
// For computing idleness of refresh drivers we only care about
|
||||
// sRegularRateTimer, since we consider refresh drivers attached to
|
||||
// sRegularRateTimerList, since we consider refresh drivers attached to
|
||||
// sThrottledRateTimer to be inactive. This implies that tasks
|
||||
// resulting from a tick on the sRegularRateTimer counts as being
|
||||
// busy but tasks resulting from a tick on sThrottledRateTimer
|
||||
// counts as being idle.
|
||||
return sRegularRateTimer->GetIdleDeadlineHint(aDefault);
|
||||
TimeStamp hint = aDefault;
|
||||
if (sRegularRateTimerList) {
|
||||
for (RefreshDriverTimer* timer : *sRegularRateTimerList) {
|
||||
TimeStamp newHint = timer->GetIdleDeadlineHint(aDefault);
|
||||
if (newHint > hint) {
|
||||
hint = newHint;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint;
|
||||
}
|
||||
|
||||
/* static */
|
||||
Maybe<TimeStamp> nsRefreshDriver::GetNextTickHint() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sRegularRateTimer) {
|
||||
return Nothing();
|
||||
Maybe<TimeStamp> hint = Nothing();
|
||||
if (sRegularRateTimerList) {
|
||||
for (RefreshDriverTimer* timer : *sRegularRateTimerList) {
|
||||
Maybe<TimeStamp> newHint = timer->GetNextTickHint();
|
||||
if ((newHint.isSome() && hint.isNothing()) ||
|
||||
(newHint.isSome() && hint.isSome() &&
|
||||
newHint.value() > hint.value())) {
|
||||
hint = newHint;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sRegularRateTimer->GetNextTickHint();
|
||||
return hint;
|
||||
}
|
||||
|
||||
void nsRefreshDriver::Disconnect() {
|
||||
|
|
|
@ -43,10 +43,6 @@ class PresShell;
|
|||
class RefreshDriverTimer;
|
||||
class Runnable;
|
||||
|
||||
namespace layout {
|
||||
class VsyncChild;
|
||||
} // namespace layout
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
|
||||
|
@ -298,14 +294,6 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
|
|||
*/
|
||||
nsPresContext* GetPresContext() const;
|
||||
|
||||
/**
|
||||
* PBackgroundChild actor is created asynchronously in content process.
|
||||
* We can't create vsync-based timers during PBackground startup. This
|
||||
* function will be called when PBackgroundChild actor is created. Then we can
|
||||
* do the pending vsync-based timer creation.
|
||||
*/
|
||||
static void PVsyncActorCreated(mozilla::layout::VsyncChild* aVsyncChild);
|
||||
|
||||
void CreateVsyncRefreshTimer();
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -23,9 +23,6 @@ class AnimationEventDispatcher;
|
|||
class PendingFullscreenEvent;
|
||||
class PresShell;
|
||||
class RefreshDriverTimer;
|
||||
namespace layout {
|
||||
class VsyncChild;
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,23 +9,12 @@ with Files("**"):
|
|||
|
||||
EXPORTS.mozilla.layout += [
|
||||
"RemoteLayerTreeOwner.h",
|
||||
"VsyncChild.h",
|
||||
"VsyncParent.h",
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
"RemoteLayerTreeOwner.cpp",
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
"VsyncChild.cpp",
|
||||
"VsyncParent.cpp",
|
||||
]
|
||||
|
||||
IPDL_SOURCES = [
|
||||
"PVsync.ipdl",
|
||||
]
|
||||
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
|
Загрузка…
Ссылка в новой задаче