Backed out changeset 3a9dce735340 (bug 1645528) for causing crashes with nsRefreshDriver CLOSED TREE

This commit is contained in:
Noemi Erli 2020-11-26 22:57:56 +02:00
parent 77dfbe7938
commit c5213774a6
19 changed files with 305 additions and 294 deletions

View File

@ -14,7 +14,6 @@
#include <algorithm>
#include <utility>
#include "BackgroundChild.h"
#include "BrowserParent.h"
#include "ClientLayerManager.h"
#include "ContentChild.h"
@ -75,7 +74,6 @@
#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"
@ -144,10 +142,6 @@
# include "mozilla/plugins/PluginWidgetChild.h"
#endif
#ifdef MOZ_WAYLAND
# include "nsAppRunner.h"
#endif
#ifdef NS_PRINTING
# include "nsIPrintSession.h"
# include "nsIPrintSettings.h"
@ -320,7 +314,6 @@ BrowserChild::BrowserChild(ContentChild* aManager, const TabId& aTabId,
mDidFakeShow(false),
mTriedBrowserInit(false),
mOrientation(hal::eScreenOrientation_PortraitPrimary),
mVsyncChild(nullptr),
mIgnoreKeyPressEvent(false),
mHasValidInnerSize(false),
mDestroyed(false),
@ -557,8 +550,6 @@ 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();
@ -566,20 +557,6 @@ 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);
@ -2166,23 +2143,6 @@ 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());

View File

@ -29,7 +29,6 @@
#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"
@ -437,12 +436,6 @@ 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; }
@ -754,8 +747,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
const mozilla::layers::CompositorOptions& aCompositorOptions);
void InitAPZState();
void InitVsyncChild();
void DestroyWindow();
void ApplyParentShowInfo(const ParentShowInfo&);
@ -823,8 +814,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
bool mTriedBrowserInit;
hal::ScreenOrientation mOrientation;
RefPtr<VsyncChild> mVsyncChild;
bool mIgnoreKeyPressEvent;
RefPtr<APZEventState> mAPZEventState;
SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback;

View File

@ -129,7 +129,6 @@
#include "mozilla/dom/CrashReport.h"
#include "nsISecureBrowserUI.h"
#include "nsIXULRuntime.h"
#include "VsyncSource.h"
#ifdef XP_WIN
# include "mozilla/plugins/PluginWidgetParent.h"
@ -225,7 +224,6 @@ BrowserParent::BrowserParent(ContentParent* aManager, const TabId& aTabId,
mCustomCursorHotspotX(0),
mCustomCursorHotspotY(0),
mVerifyDropLinks{},
mVsyncParent(nullptr),
mDocShellIsActive(false),
mMarkedDestroying(false),
mIsDestroyed(false),
@ -565,8 +563,6 @@ void BrowserParent::SetOwnerElement(Element* aElement) {
mBrowsingContext->SetEmbedderElement(mFrameElement);
}
UpdateVsyncParentVsyncSource();
VisitChildren([aElement](BrowserBridgeParent* aBrowser) {
if (auto* browserParent = aBrowser->GetBrowserParent()) {
browserParent->SetOwnerElement(aElement);
@ -1350,28 +1346,6 @@ IPCResult BrowserParent::RecvNewWindowGlobal(
return IPC_OK();
}
PVsyncParent* BrowserParent::AllocPVsyncParent() {
MOZ_ASSERT(!mVsyncParent);
mVsyncParent = new VsyncParent();
UpdateVsyncParentVsyncSource();
return mVsyncParent.get();
}
bool BrowserParent::DeallocPVsyncParent(PVsyncParent* 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) {

View File

@ -18,7 +18,6 @@
#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"
@ -461,10 +460,6 @@ class BrowserParent final : public PBrowserParent,
bool DeallocPColorPickerParent(PColorPickerParent* aColorPicker);
PVsyncParent* AllocPVsyncParent();
bool DeallocPVsyncParent(PVsyncParent* aActor);
#ifdef ACCESSIBILITY
PDocAccessibleParent* AllocPDocAccessibleParent(PDocAccessibleParent*,
const uint64_t&,
@ -877,8 +872,6 @@ 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();
@ -964,8 +957,6 @@ class BrowserParent final : public PBrowserParent,
nsTArray<nsString> mVerifyDropLinks;
RefPtr<VsyncParent> mVsyncParent;
#ifdef DEBUG
int32_t mActiveSupressDisplayportCount = 0;
#endif

View File

@ -20,7 +20,6 @@ include protocol PRemoteLazyInputStream;
include protocol PPaymentRequest;
include protocol PWindowGlobal;
include protocol PBrowserBridge;
include protocol PVsync;
include DOMTypes;
include NeckoChannelParams;
@ -191,7 +190,6 @@ nested(upto inside_cpow) sync refcounted protocol PBrowser
manages PPaymentRequest;
manages PWindowGlobal;
manages PBrowserBridge;
manages PVsync;
both:
async AsyncMessage(nsString aMessage, ClonedMessageData aData);
@ -219,11 +217,6 @@ 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.

View File

@ -71,8 +71,6 @@ EXPORTS.mozilla.dom += [
"URLClassifierChild.h",
"URLClassifierParent.h",
"UserActivationIPCUtils.h",
"VsyncChild.h",
"VsyncParent.h",
"WindowGlobalActor.h",
"WindowGlobalChild.h",
"WindowGlobalParent.h",
@ -132,8 +130,6 @@ UNIFIED_SOURCES += [
SOURCES += [
"ContentChild.cpp",
"ProcessHangMonitor.cpp",
"VsyncChild.cpp",
"VsyncParent.cpp",
]
PREPROCESSED_IPDL_SOURCES += [
@ -159,7 +155,6 @@ IPDL_SOURCES += [
"PURLClassifier.ipdl",
"PURLClassifierInfo.ipdlh",
"PURLClassifierLocal.ipdl",
"PVsync.ipdl",
"PWindowGlobal.ipdl",
"ServiceWorkerConfiguration.ipdlh",
"WindowGlobalTypes.ipdlh",

View File

@ -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;
}
dom::PVsyncChild* BackgroundChildImpl::AllocPVsyncChild() {
RefPtr<dom::VsyncChild> actor = new dom::VsyncChild();
BackgroundChildImpl::PVsyncChild* BackgroundChildImpl::AllocPVsyncChild() {
RefPtr<mozilla::layout::VsyncChild> actor = new mozilla::layout::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<dom::VsyncChild> actor =
dont_AddRef(static_cast<dom::VsyncChild*>(aActor));
RefPtr<mozilla::layout::VsyncChild> actor =
dont_AddRef(static_cast<mozilla::layout::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() == dom::PVsync::MessageType::Msg_Notify__ID) {
if (aMsg.type() == layout::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();

View File

@ -55,7 +55,6 @@
#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"
@ -65,6 +64,7 @@
#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::dom::VsyncParent> actor = new mozilla::dom::VsyncParent();
actor->UpdateVsyncSource(nullptr);
RefPtr<mozilla::layout::VsyncParent> actor =
mozilla::layout::VsyncParent::Create();
// 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::dom::VsyncParent> actor =
dont_AddRef(static_cast<mozilla::dom::VsyncParent*>(aActor));
RefPtr<mozilla::layout::VsyncParent> actor =
dont_AddRef(static_cast<mozilla::layout::VsyncParent*>(aActor));
return true;
}

View File

@ -12,6 +12,11 @@
#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

View File

@ -692,6 +692,9 @@ nsresult nsPresContext::Init(nsDeviceContext* aDeviceContext) {
if (!mRefreshDriver) {
mRefreshDriver = new nsRefreshDriver(this);
if (XRE_IsContentProcess()) {
mRefreshDriver->InitializeTimer();
}
}
}

View File

@ -59,12 +59,10 @@
#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"
@ -77,6 +75,7 @@
#include "BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/layout/VsyncChild.h"
#include "VsyncSource.h"
#include "mozilla/VsyncDispatcher.h"
#include "mozilla/Unused.h"
@ -247,6 +246,26 @@ 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) {
@ -427,45 +446,56 @@ class SimpleTimerBasedRefreshDriverTimer : public RefreshDriverTimer {
*/
class VsyncRefreshDriverTimer : public RefreshDriverTimer {
public:
VsyncRefreshDriverTimer()
: mVsyncChild(nullptr), mVsyncRate(TimeDuration::Forever()) {
VsyncRefreshDriverTimer() : mVsyncChild(nullptr) {
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 =
mVsyncSource->GetRefreshTimerVsyncDispatcher());
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();
}
// 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)
: mVsyncSource(aVsyncSource),
mVsyncChild(nullptr),
mVsyncRate(TimeDuration::Forever()) {
: mVsyncChild(nullptr) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
mVsyncSource = aVsyncSource;
mVsyncObserver = new RefreshDriverVsyncObserver(this);
MOZ_ALWAYS_TRUE(mVsyncDispatcher =
aVsyncSource->GetRefreshTimerVsyncDispatcher());
}
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);
mVsyncDispatcher->AddChildRefreshTimer(mVsyncObserver);
mVsyncRate = aVsyncSource->GetGlobalDisplay().GetVsyncRate();
}
TimeDuration GetTimerRate() override {
if (mVsyncSource) {
mVsyncRate = mVsyncSource->GetGlobalDisplay().GetVsyncRate();
} else if (mVsyncChild) {
mVsyncRate = mVsyncChild->GetVsyncRate();
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 hardware queries fail / are unsupported, we have to just guess.
@ -742,11 +772,16 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer {
}; // RefreshDriverVsyncObserver
~VsyncRefreshDriverTimer() override {
if (mVsyncDispatcher) {
if (XRE_IsParentProcess()) {
mVsyncDispatcher->RemoveChildRefreshTimer(mVsyncObserver);
mVsyncDispatcher = nullptr;
} else if (mVsyncChild) {
mVsyncChild->RemoveChildRefreshTimer(mVsyncObserver);
} 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);
mVsyncChild = nullptr;
}
@ -762,10 +797,10 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer {
mLastFireTime = TimeStamp::Now();
if (mVsyncDispatcher) {
if (XRE_IsParentProcess()) {
mVsyncDispatcher->AddChildRefreshTimer(mVsyncObserver);
} else if (mVsyncChild) {
mVsyncChild->AddChildRefreshTimer(mVsyncObserver);
} else {
Unused << mVsyncChild->SendObserve();
mVsyncObserver->OnTimerStart();
}
@ -776,10 +811,10 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer {
// Protect updates to `sActiveVsyncTimers`.
MOZ_ASSERT(NS_IsMainThread());
if (mVsyncDispatcher) {
if (XRE_IsParentProcess()) {
mVsyncDispatcher->RemoveChildRefreshTimer(mVsyncObserver);
} else if (mVsyncChild) {
mVsyncChild->RemoveChildRefreshTimer(mVsyncObserver);
} else {
Unused << mVsyncChild->SendUnobserve();
}
MOZ_ASSERT(sActiveVsyncTimers > 0);
@ -971,12 +1006,34 @@ class InactiveRefreshDriverTimer final
} // namespace mozilla
static nsTArray<RefreshDriverTimer*>* sRegularRateTimers;
static StaticRefPtr<RefreshDriverTimer> sRegularRateTimer;
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);
@ -985,25 +1042,32 @@ 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;
if (widget) {
if (RefPtr<gfx::VsyncSource> localVsyncSource = widget->GetVsyncSource()) {
RefPtr<gfx::VsyncSource> localVsyncSource = widget->GetVsyncSource();
if (localVsyncSource) {
mOwnTimer = new VsyncRefreshDriverTimer(localVsyncSource);
} else if (BrowserChild* browserChild = widget->GetOwningBrowserChild()) {
if (RefPtr<VsyncChild> localVsyncSource = browserChild->GetVsyncChild()) {
mOwnTimer = new VsyncRefreshDriverTimer(localVsyncSource);
}
return;
}
}
if (!mOwnTimer) {
mOwnTimer = new StartupRefreshDriverTimer(GetRegularTimerInterval());
if (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.
sRegularRateTimer = new VsyncRefreshDriverTimer();
return;
}
if (!sRegularRateTimers) {
sRegularRateTimers = new nsTArray<RefreshDriverTimer*>();
}
sRegularRateTimers->AppendElement(mOwnTimer.get());
// If this process is not created by NUWA, just create the vsync timer here.
CreateContentVsyncRefreshTimer(nullptr);
}
static uint32_t GetFirstFrameDelay(imgIRequest* req) {
@ -1021,10 +1085,8 @@ static uint32_t GetFirstFrameDelay(imgIRequest* req) {
/* static */
void nsRefreshDriver::Shutdown() {
MOZ_ASSERT(NS_IsMainThread());
// clean up our timers
delete sRegularRateTimers;
sRegularRateTimers = nullptr;
sRegularRateTimer = nullptr;
sThrottledRateTimer = nullptr;
}
@ -1080,10 +1142,26 @@ RefreshDriverTimer* nsRefreshDriver::ChooseTimer() {
return sThrottledRateTimer;
}
if (!mOwnTimer) {
if (!sRegularRateTimer && !mOwnTimer) {
double rate = GetRegularTimerInterval();
// Try to use vsync-base refresh timer first for sRegularRateTimer.
CreateVsyncRefreshTimer();
if (mOwnTimer) {
return mOwnTimer.get();
}
if (!sRegularRateTimer) {
sRegularRateTimer = new StartupRefreshDriverTimer(rate);
}
}
return mOwnTimer.get();
if (mOwnTimer) {
return mOwnTimer.get();
}
return sRegularRateTimer;
}
nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext)
@ -1135,9 +1213,6 @@ nsRefreshDriver::~nsRefreshDriver() {
mRootRefresh->RemoveRefreshObserver(this, FlushType::Style);
mRootRefresh = nullptr;
}
if (mOwnTimer && sRegularRateTimers) {
sRegularRateTimers->RemoveElement(mOwnTimer.get());
}
}
// Method for testing. See nsIDOMWindowUtils.advanceTimeAndRefresh
@ -2600,6 +2675,21 @@ 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) {
@ -2676,34 +2766,27 @@ TimeStamp nsRefreshDriver::GetIdleDeadlineHint(TimeStamp aDefault) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aDefault.IsNull());
if (!sRegularRateTimers || sRegularRateTimers->IsEmpty()) {
if (!sRegularRateTimer) {
return aDefault;
}
// For computing idleness of refresh drivers we only care about
// sRegularRateTimers, since we consider refresh drivers attached to
// sRegularRateTimer, 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 sRegularRateTimers->ElementAt(0)->GetIdleDeadlineHint(aDefault);
return sRegularRateTimer->GetIdleDeadlineHint(aDefault);
}
/* static */
Maybe<TimeStamp> nsRefreshDriver::GetNextTickHint() {
MOZ_ASSERT(NS_IsMainThread());
if (!sRegularRateTimers) {
if (!sRegularRateTimer) {
return Nothing();
}
for (RefreshDriverTimer* timer : *sRegularRateTimers) {
Maybe<TimeStamp> tickHint = timer->GetNextTickHint();
if (tickHint.isSome()) {
return tickHint;
}
}
return Nothing();
return sRegularRateTimer->GetNextTickHint();
}
void nsRefreshDriver::Disconnect() {

View File

@ -43,6 +43,10 @@ class PresShell;
class RefreshDriverTimer;
class Runnable;
namespace layout {
class VsyncChild;
} // namespace layout
} // namespace mozilla
class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
@ -294,6 +298,14 @@ 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

View File

@ -23,6 +23,9 @@ class AnimationEventDispatcher;
class PendingFullscreenEvent;
class PresShell;
class RefreshDriverTimer;
namespace layout {
class VsyncChild;
}
} // namespace mozilla
/**

View File

@ -4,23 +4,22 @@
* 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 dom {
namespace layout {
/*
* 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
* 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
* interfaces for content to observe/unobserve vsync event notifications.
*/
async protocol PVsync
{
manager PBackground or PBrowser;
manager PBackground;
child:
// Send vsync event from chrome to content process.
@ -36,9 +35,10 @@ parent:
async RequestVsyncRate();
// This message is never sent. Each PVsync actor will stay alive as long as
// its PBackground or PBrowser manager.
// its PBackground manager.
async __delete__();
};
} // namespace dom
} // namespace layout
} // namespace mozilla

View File

@ -10,18 +10,17 @@
#include "mozilla/VsyncDispatcher.h"
#include "nsThreadUtils.h"
namespace mozilla::dom {
namespace mozilla::layout {
VsyncChild::VsyncChild()
: mIsShutdown(false),
mVsyncRate(TimeDuration::Forever()),
lastVsyncRateTime(TimeStamp()) {
: mObservingVsync(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) {
@ -39,42 +38,12 @@ 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;
if (!mObservers.IsEmpty()) {
Unused << PVsyncChild::SendUnobserve();
}
mObservers.Clear();
mObserver = nullptr;
}
mozilla::ipc::IPCResult VsyncChild::RecvNotify(const VsyncEvent& aVsync) {
@ -82,26 +51,30 @@ mozilla::ipc::IPCResult VsyncChild::RecvNotify(const VsyncEvent& aVsync) {
MOZ_ASSERT(!mIsShutdown);
SchedulerGroup::MarkVsyncRan();
for (VsyncObserver* observer : mObservers.ForwardRange()) {
observer->NotifyVsync(aVsync);
if (mObservingVsync && mObserver) {
mObserver->NotifyVsync(aVsync);
}
return IPC_OK();
}
void VsyncChild::SetVsyncObserver(VsyncObserver* aVsyncObserver) {
MOZ_ASSERT(NS_IsMainThread());
mObserver = aVsyncObserver;
}
TimeDuration VsyncChild::GetVsyncRate() {
// Throttle vsync rate requests to avoid unnecessary IPC
if (lastVsyncRateTime.IsNull() ||
(TimeStamp::Now() - lastVsyncRateTime).ToMilliseconds() > 250) {
if (mVsyncRate == TimeDuration::Forever()) {
PVsyncChild::SendRequestVsyncRate();
lastVsyncRateTime = TimeStamp::Now();
}
return mVsyncRate;
}
TimeDuration VsyncChild::VsyncRate() { return mVsyncRate; }
mozilla::ipc::IPCResult VsyncChild::RecvVsyncRate(const float& aVsyncRate) {
mVsyncRate = TimeDuration::FromMilliseconds(aVsyncRate);
return IPC_OK();
}
} // namespace mozilla::dom
} // namespace mozilla::layout

View File

@ -4,19 +4,22 @@
* 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_dom_ipc_VsyncChild_h
#define mozilla_dom_ipc_VsyncChild_h
#ifndef mozilla_layout_ipc_VsyncChild_h
#define mozilla_layout_ipc_VsyncChild_h
#include "mozilla/dom/PVsyncChild.h"
#include "mozilla/RefPtr.h"
#include "mozilla/layout/PVsyncChild.h"
#include "nsISupportsImpl.h"
#include "nsTObserverArray.h"
#include "mozilla/RefPtr.h"
namespace mozilla {
class VsyncObserver;
namespace dom {
namespace ipc {
class BackgroundChildImpl;
} // namespace ipc
namespace layout {
// 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
@ -25,30 +28,44 @@ namespace dom {
class VsyncChild final : public PVsyncChild {
NS_INLINE_DECL_REFCOUNTING(VsyncChild)
friend class mozilla::ipc::BackgroundChildImpl;
friend class PVsyncChild;
public:
VsyncChild();
void AddChildRefreshTimer(VsyncObserver* aVsyncObserver);
void RemoveChildRefreshTimer(VsyncObserver* aVsyncObserver);
// Hide the SendObserve/SendUnobserve in PVsyncChild. We add an flag
// mObservingVsync to handle the race problem of unobserving vsync event.
bool SendObserve();
bool SendUnobserve();
// Bind a VsyncObserver into VsyncChild after ipc channel connected.
void SetVsyncObserver(VsyncObserver* aVsyncObserver);
// GetVsyncRate is a getter for mVsyncRate which sends a requests to
// VsyncParent to retreive the hardware vsync rate if mVsyncRate
// hasn't already been set.
TimeDuration GetVsyncRate();
// VsyncRate is a getter for mVsyncRate which always returns
// mVsyncRate directly, potentially returning
// 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);
virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
bool mObservingVsync;
bool mIsShutdown;
// The content side vsync observer.
RefPtr<VsyncObserver> mObserver;
TimeDuration mVsyncRate;
TimeStamp lastVsyncRateTime;
nsTObserverArray<VsyncObserver*> mObservers;
};
} // namespace dom
} // namespace layout
} // namespace mozilla
#endif // mozilla_dom_ipc_VsyncChild_h
#endif // mozilla_layout_ipc_VsyncChild_h

View File

@ -10,49 +10,51 @@
#include "BackgroundParentImpl.h"
#include "gfxPlatform.h"
#include "mozilla/Unused.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"
#include "VsyncSource.h"
namespace mozilla::dom {
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();
}
VsyncParent::VsyncParent()
: mObservingVsync(false),
mDestroyed(false),
mInitialThread(NS_GetCurrentThread()) {}
mBackgroundThread(NS_GetCurrentThread()) {
MOZ_ASSERT(mBackgroundThread);
AssertIsOnBackgroundThread();
}
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);
}
VsyncParent::~VsyncParent() {
// Since we use NS_INLINE_DECL_THREADSAFE_REFCOUNTING, we can't make sure
// VsyncParent is always released on the background thread.
}
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>(
"dom::VsyncParent::DispatchVsyncEvent", this,
"layout::VsyncParent::DispatchVsyncEvent", this,
&VsyncParent::DispatchVsyncEvent, aVsync);
MOZ_ALWAYS_SUCCEEDS(mInitialThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL));
MOZ_ALWAYS_SUCCEEDS(
mBackgroundThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL));
return true;
}
void VsyncParent::DispatchVsyncEvent(const VsyncEvent& aVsync) {
AssertIsOnInitialThread();
AssertIsOnBackgroundThread();
// If we call NotifyVsync() when we handle ActorDestroy() message, we might
// still call DispatchVsyncEvent().
@ -65,14 +67,17 @@ void VsyncParent::DispatchVsyncEvent(const VsyncEvent& aVsync) {
}
mozilla::ipc::IPCResult VsyncParent::RecvRequestVsyncRate() {
AssertIsOnInitialThread();
TimeDuration vsyncRate = mVsyncSource->GetGlobalDisplay().GetVsyncRate();
AssertIsOnBackgroundThread();
TimeDuration vsyncRate = gfxPlatform::GetPlatform()
->GetHardwareVsync()
->GetGlobalDisplay()
.GetVsyncRate();
Unused << SendVsyncRate(vsyncRate.ToMilliseconds());
return IPC_OK();
}
mozilla::ipc::IPCResult VsyncParent::RecvObserve() {
AssertIsOnInitialThread();
AssertIsOnBackgroundThread();
if (!mObservingVsync) {
mVsyncDispatcher->AddChildRefreshTimer(this);
mObservingVsync = true;
@ -82,7 +87,7 @@ mozilla::ipc::IPCResult VsyncParent::RecvObserve() {
}
mozilla::ipc::IPCResult VsyncParent::RecvUnobserve() {
AssertIsOnInitialThread();
AssertIsOnBackgroundThread();
if (mObservingVsync) {
mVsyncDispatcher->RemoveChildRefreshTimer(this);
mObservingVsync = false;
@ -91,9 +96,9 @@ mozilla::ipc::IPCResult VsyncParent::RecvUnobserve() {
return IPC_FAIL_NO_REASON(this);
}
void VsyncParent::ActorDestroy(ActorDestroyReason aActorDestroyReason) {
void VsyncParent::ActorDestroy(ActorDestroyReason aReason) {
MOZ_ASSERT(!mDestroyed);
AssertIsOnInitialThread();
AssertIsOnBackgroundThread();
if (mObservingVsync) {
mVsyncDispatcher->RemoveChildRefreshTimer(this);
}
@ -101,10 +106,5 @@ void VsyncParent::ActorDestroy(ActorDestroyReason aActorDestroyReason) {
mDestroyed = true;
}
bool VsyncParent::IsOnInitialThread() {
return NS_GetCurrentThread() == mInitialThread;
}
void VsyncParent::AssertIsOnInitialThread() { MOZ_ASSERT(IsOnInitialThread()); }
} // namespace mozilla::dom
} // namespace layout
} // namespace mozilla

View File

@ -4,31 +4,36 @@
* 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_dom_ipc_VsyncParent_h
#define mozilla_dom_ipc_VsyncParent_h
#ifndef mozilla_layout_ipc_VsyncParent_h
#define mozilla_layout_ipc_VsyncParent_h
#include "mozilla/dom/PVsyncParent.h"
#include "mozilla/layout/PVsyncParent.h"
#include "mozilla/VsyncDispatcher.h"
#include "nsCOMPtr.h"
#include "mozilla/RefPtr.h"
#include "VsyncSource.h"
class nsIThread;
namespace mozilla::dom {
namespace mozilla {
namespace ipc {
class BackgroundParentImpl;
} // namespace ipc
namespace layout {
// 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;
public:
VsyncParent();
void UpdateVsyncSource(const RefPtr<gfx::VsyncSource>& aVsyncSource);
private:
virtual ~VsyncParent() = default;
static already_AddRefed<VsyncParent> Create();
VsyncParent();
virtual ~VsyncParent();
virtual bool NotifyVsync(const VsyncEvent& aVsync) override;
mozilla::ipc::IPCResult RecvRequestVsyncRate();
@ -39,16 +44,13 @@ class VsyncParent final : public PVsyncParent, public VsyncObserver {
void DispatchVsyncEvent(const VsyncEvent& aVsync);
bool IsOnInitialThread();
void AssertIsOnInitialThread();
bool mObservingVsync;
bool mDestroyed;
nsCOMPtr<nsIThread> mInitialThread;
RefPtr<gfx::VsyncSource> mVsyncSource;
nsCOMPtr<nsIThread> mBackgroundThread;
RefPtr<RefreshTimerVsyncDispatcher> mVsyncDispatcher;
};
} // namespace mozilla::dom
} // namespace layout
} // namespace mozilla
#endif // mozilla_dom_ipc_VsyncParent_h
#endif // mozilla_layout_ipc_VsyncParent_h

View File

@ -9,12 +9,23 @@ 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"