Bug 1101974. Part 1. Move VsyncDispatcher to CompositorParent. r=roc

This commit is contained in:
Mason Chang 2014-11-21 09:16:19 -08:00
parent 4e999354bb
commit e110f5c4a0
6 changed files with 73 additions and 255 deletions

View File

@ -63,7 +63,6 @@
#ifdef MOZ_ENABLE_PROFILER_SPS
#include "ProfilerMarkers.h"
#endif
#include "mozilla/VsyncDispatcher.h"
#ifdef MOZ_WIDGET_GONK
#include "GeckoTouchDispatcher.h"
@ -195,20 +194,23 @@ static void SetThreadPriority()
hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
}
CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent* aCompositorParent)
StaticRefPtr<VsyncDispatcher> sVsyncDispatcher;
VsyncDispatcher::VsyncDispatcher(CompositorParent* aCompositorParent, VsyncSource* aVsyncSource)
: mNeedsComposite(false)
, mIsObservingVsync(false)
, mCompositorParent(aCompositorParent)
, mVsyncSource(aVsyncSource)
, mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
, mCurrentCompositeTask(nullptr)
{
sVsyncDispatcher = this;
}
CompositorVsyncObserver::~CompositorVsyncObserver()
VsyncDispatcher::~VsyncDispatcher()
{
MOZ_ASSERT(NS_IsMainThread());
UnobserveVsync();
sVsyncDispatcher = nullptr;
DisableVsync();
mCompositorParent = nullptr;
mNeedsComposite = false;
CancelCurrentCompositeTask();
@ -222,18 +224,30 @@ CompositorVsyncObserver::~CompositorVsyncObserver()
* How many skipped vsync events until we stop listening to vsync events?
*/
void
CompositorVsyncObserver::SetNeedsComposite(bool aNeedsComposite)
VsyncDispatcher::SetNeedsComposite(bool aNeedsComposite)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
mNeedsComposite = aNeedsComposite;
if (!mIsObservingVsync && mNeedsComposite) {
ObserveVsync();
EnableVsync();
}
}
bool
CompositorVsyncObserver::NotifyVsync(TimeStamp aVsyncTimestamp)
/* static*/ void
VsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
{
// Called from the vsync dispatch thread
MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
MOZ_ASSERT(!NS_IsMainThread());
if (sVsyncDispatcher) {
sVsyncDispatcher->RunVsync(aVsyncTimestamp);
}
}
void
VsyncDispatcher::RunVsync(TimeStamp aVsyncTimestamp)
{
// Called from the vsync dispatch thread
MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
@ -242,15 +256,14 @@ CompositorVsyncObserver::NotifyVsync(TimeStamp aVsyncTimestamp)
MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
if (mCurrentCompositeTask == nullptr) {
mCurrentCompositeTask = NewRunnableMethod(this,
&CompositorVsyncObserver::Composite,
&VsyncDispatcher::Composite,
aVsyncTimestamp);
CompositorParent::CompositorLoop()->PostTask(FROM_HERE, mCurrentCompositeTask);
}
return true;
}
void
CompositorVsyncObserver::CancelCurrentCompositeTask()
VsyncDispatcher::CancelCurrentCompositeTask()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
@ -261,7 +274,7 @@ CompositorVsyncObserver::CancelCurrentCompositeTask()
}
void
CompositorVsyncObserver::Composite(TimeStamp aVsyncTimestamp)
VsyncDispatcher::Composite(TimeStamp aVsyncTimestamp)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
{
@ -273,43 +286,37 @@ CompositorVsyncObserver::Composite(TimeStamp aVsyncTimestamp)
mNeedsComposite = false;
mCompositorParent->CompositeCallback(aVsyncTimestamp);
} else {
// We're getting vsync notifications but we don't need to composite so
// unregister the vsync.
UnobserveVsync();
DisableVsync();
}
DispatchTouchEvents(aVsyncTimestamp);
}
bool
CompositorVsyncObserver::NeedsComposite()
VsyncDispatcher::NeedsComposite()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
return mNeedsComposite;
}
/**
* Since the vsync thread has its own locks before notifying us of vsync
* we can't register/unregister from the vsync thread. Any other thread is fine
*/
void
CompositorVsyncObserver::ObserveVsync()
VsyncDispatcher::EnableVsync()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
VsyncDispatcher::GetInstance()->AddCompositorVsyncObserver(this);
mIsObservingVsync = true;
mVsyncSource->EnableVsync();
}
void
CompositorVsyncObserver::UnobserveVsync()
VsyncDispatcher::DisableVsync()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
VsyncDispatcher::GetInstance()->RemoveCompositorVsyncObserver(this);
mIsObservingVsync = false;
mVsyncSource->DisableVsync();
}
void
CompositorVsyncObserver::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
VsyncDispatcher::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
{
#ifdef MOZ_WIDGET_GONK
if (gfxPrefs::TouchResampling()) {
@ -383,11 +390,12 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
mApzcTreeManager = new APZCTreeManager();
}
if (gfxPrefs::VsyncAlignedCompositor()) {
mCompositorVsyncObserver = new CompositorVsyncObserver(this);
}
gfxPlatform::GetPlatform()->ComputeTileSize();
if (gfxPrefs::VsyncAlignedCompositor()) {
nsRefPtr<VsyncSource> platformVsyncSource = gfxPlatform::GetPlatform()->GetVsyncSource();
mVsyncDispatcher = new VsyncDispatcher(this, platformVsyncSource.get());
}
}
bool
@ -427,7 +435,7 @@ CompositorParent::Destroy()
mApzcTreeManager = nullptr;
}
sIndirectLayerTrees.erase(mRootLayerTreeID);
mCompositorVsyncObserver = nullptr;
mVsyncDispatcher = nullptr;
}
void
@ -509,8 +517,8 @@ CompositorParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
bool
CompositorParent::RecvFlushRendering()
{
if (gfxPrefs::VsyncAlignedCompositor() && mCompositorVsyncObserver->NeedsComposite()) {
mCompositorVsyncObserver->SetNeedsComposite(false);
if (gfxPrefs::VsyncAlignedCompositor() && mVsyncDispatcher->NeedsComposite()) {
mVsyncDispatcher->SetNeedsComposite(false);
CancelCurrentCompositeTask();
ForceComposeToTarget(nullptr);
} else if (mCurrentCompositeTask) {
@ -647,7 +655,7 @@ void
CompositorParent::CancelCurrentCompositeTask()
{
if (gfxPrefs::VsyncAlignedCompositor()) {
mCompositorVsyncObserver->CancelCurrentCompositeTask();
mVsyncDispatcher->CancelCurrentCompositeTask();
} else if (mCurrentCompositeTask) {
mCurrentCompositeTask->Cancel();
mCurrentCompositeTask = nullptr;
@ -797,7 +805,7 @@ CompositorParent::ScheduleComposition()
{
MOZ_ASSERT(IsInCompositorThread());
if (gfxPrefs::VsyncAlignedCompositor()) {
mCompositorVsyncObserver->SetNeedsComposite(true);
mVsyncDispatcher->SetNeedsComposite(true);
} else {
ScheduleSoftwareTimerComposition();
}
@ -1018,7 +1026,7 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
bool needTestComposite = mIsTesting && root &&
(mCurrentCompositeTask ||
(gfxPrefs::VsyncAlignedCompositor() &&
mCompositorVsyncObserver->NeedsComposite()));
mVsyncDispatcher->NeedsComposite()));
if (needTestComposite) {
AutoResolveRefLayers resolve(mCompositionManager);
bool requestNextFrame =
@ -1052,7 +1060,7 @@ CompositorParent::SetTestSampleTime(LayerTransactionParent* aLayerTree,
bool testComposite = mCompositionManager && (mCurrentCompositeTask ||
(gfxPrefs::VsyncAlignedCompositor()
&& mCompositorVsyncObserver->NeedsComposite()));
&& mVsyncDispatcher->NeedsComposite()));
// Update but only if we were already scheduled to animate
if (testComposite) {

View File

@ -35,7 +35,6 @@
#include "nsISupportsImpl.h"
#include "nsSize.h" // for nsIntSize
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
#include "mozilla/VsyncDispatcher.h"
class CancelableTask;
class MessageLoop;
@ -89,35 +88,53 @@ private:
friend class CompositorParent;
};
// Controls how and when to enable/disable vsync.
class VsyncSource
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncSource)
virtual void EnableVsync() = 0;
virtual void DisableVsync() = 0;
virtual bool IsVsyncEnabled() = 0;
protected:
virtual ~VsyncSource() {}
}; // VsyncSource
/**
* Manages the vsync (de)registration and tracking on behalf of the
* compositor when it need to paint.
* Turns vsync notifications into scheduled composites.
**/
class CompositorVsyncObserver MOZ_FINAL : public VsyncObserver
class VsyncDispatcher MOZ_FINAL
{
// Cleaned up on main thread along with the compositor. This has the same lifetime
// as the CompositorParent
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(VsyncDispatcher)
friend class CompositorParent;
public:
CompositorVsyncObserver(CompositorParent* aCompositorParent);
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) MOZ_OVERRIDE;
VsyncDispatcher(CompositorParent* aCompositorParent, VsyncSource* aVsyncSource);
static void NotifyVsync(TimeStamp aVsyncTimestamp);
void RunVsync(TimeStamp aVsyncTimestamp);
void SetNeedsComposite(bool aSchedule);
bool NeedsComposite();
void CancelCurrentCompositeTask();
private:
virtual ~CompositorVsyncObserver();
virtual ~VsyncDispatcher();
void Composite(TimeStamp aVsyncTimestamp);
void NotifyCompositeTaskExecuted();
void ObserveVsync();
void UnobserveVsync();
void EnableVsync();
void DisableVsync();
void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
bool mNeedsComposite;
bool mIsObservingVsync;
nsRefPtr<CompositorParent> mCompositorParent;
nsRefPtr<VsyncSource> mVsyncSource;
mozilla::Monitor mCurrentCompositeTaskMonitor;
CancelableTask* mCurrentCompositeTask;
@ -127,7 +144,7 @@ class CompositorParent MOZ_FINAL : public PCompositorParent,
public ShadowLayersManager
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorParent)
friend class CompositorVsyncObserver;
friend class VsyncDispatcher;
public:
explicit CompositorParent(nsIWidget* aWidget,
@ -388,7 +405,7 @@ protected:
nsRefPtr<APZCTreeManager> mApzcTreeManager;
nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
nsRefPtr<CompositorVsyncObserver> mCompositorVsyncObserver;
nsRefPtr<VsyncDispatcher> mVsyncDispatcher;
DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
};

View File

@ -1,117 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
#include "VsyncDispatcher.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/layers/CompositorParent.h"
#include "gfxPrefs.h"
#ifdef MOZ_ENABLE_PROFILER_SPS
#include "GeckoProfiler.h"
#include "ProfilerMarkers.h"
#endif
#ifdef MOZ_WIDGET_GONK
#include "GeckoTouchDispatcher.h"
#endif
using namespace mozilla::layers;
namespace mozilla {
StaticRefPtr<VsyncDispatcher> sVsyncDispatcher;
/*static*/ VsyncDispatcher*
VsyncDispatcher::GetInstance()
{
if (!sVsyncDispatcher) {
sVsyncDispatcher = new VsyncDispatcher();
ClearOnShutdown(&sVsyncDispatcher);
}
return sVsyncDispatcher;
}
VsyncDispatcher::VsyncDispatcher()
: mCompositorObserverLock("CompositorObserverLock")
{
}
VsyncDispatcher::~VsyncDispatcher()
{
MutexAutoLock lock(mCompositorObserverLock);
mCompositorObservers.Clear();
}
void
VsyncDispatcher::SetVsyncSource(VsyncSource* aVsyncSource)
{
mVsyncSource = aVsyncSource;
}
void
VsyncDispatcher::DispatchTouchEvents(bool aNotifiedCompositors, TimeStamp aVsyncTime)
{
// Touch events can sometimes start a composite, so make sure we dispatch touches
// even if we don't composite
#ifdef MOZ_WIDGET_GONK
if (!aNotifiedCompositors && gfxPrefs::TouchResampling()) {
GeckoTouchDispatcher::NotifyVsync(aVsyncTime);
}
#endif
}
void
VsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
{
bool notifiedCompositors = false;
#ifdef MOZ_ENABLE_PROFILER_SPS
if (profiler_is_active()) {
CompositorParent::PostInsertVsyncProfilerMarker(aVsyncTimestamp);
}
#endif
if (gfxPrefs::VsyncAlignedCompositor()) {
MutexAutoLock lock(mCompositorObserverLock);
notifiedCompositors = NotifyVsyncObservers(aVsyncTimestamp, mCompositorObservers);
}
DispatchTouchEvents(notifiedCompositors, aVsyncTimestamp);
}
bool
VsyncDispatcher::NotifyVsyncObservers(TimeStamp aVsyncTimestamp, nsTArray<nsRefPtr<VsyncObserver>>& aObservers)
{
// Callers should lock the respective lock for the aObservers before calling this function
for (size_t i = 0; i < aObservers.Length(); i++) {
aObservers[i]->NotifyVsync(aVsyncTimestamp);
}
return !aObservers.IsEmpty();
}
void
VsyncDispatcher::AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MutexAutoLock lock(mCompositorObserverLock);
if (!mCompositorObservers.Contains(aVsyncObserver)) {
mCompositorObservers.AppendElement(aVsyncObserver);
}
}
void
VsyncDispatcher::RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
MutexAutoLock lock(mCompositorObserverLock);
if (mCompositorObservers.Contains(aVsyncObserver)) {
mCompositorObservers.RemoveElement(aVsyncObserver);
} else {
NS_WARNING("Could not delete a compositor vsync observer\n");
}
}
} // namespace mozilla

View File

@ -1,88 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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_widget_VsyncDispatcher_h
#define mozilla_widget_VsyncDispatcher_h
#include "base/message_loop.h"
#include "mozilla/Mutex.h"
#include "nsISupportsImpl.h"
#include "nsTArray.h"
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
class MessageLoop;
namespace mozilla {
class TimeStamp;
namespace layers {
class CompositorVsyncObserver;
}
// Controls how and when to enable/disable vsync.
class VsyncSource
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncSource)
virtual void EnableVsync() = 0;
virtual void DisableVsync() = 0;
virtual bool IsVsyncEnabled() = 0;
protected:
virtual ~VsyncSource() {}
}; // VsyncSource
class VsyncObserver
{
// Must be destroyed on main thread since the compositor is as well
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(VsyncObserver)
public:
// The method called when a vsync occurs. Return true if some work was done.
// Vsync notifications will occur on the hardware vsync thread
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) = 0;
protected:
VsyncObserver() {}
virtual ~VsyncObserver() {}
}; // VsyncObserver
// VsyncDispatcher is used to dispatch vsync events to the registered observers.
class VsyncDispatcher
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncDispatcher)
public:
static VsyncDispatcher* GetInstance();
// Called on the vsync thread when a hardware vsync occurs
// The aVsyncTimestamp can mean different things depending on the platform:
// b2g - The vsync timestamp of the previous frame that was just displayed
// OSX - The vsync timestamp of the upcoming frame
// TODO: Windows / Linux. DOCUMENT THIS WHEN IMPLEMENTING ON THOSE PLATFORMS
// Android: TODO
void NotifyVsync(TimeStamp aVsyncTimestamp);
void SetVsyncSource(VsyncSource* aVsyncSource);
// Compositor vsync observers must be added/removed on the compositor thread
void AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
void RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
private:
VsyncDispatcher();
virtual ~VsyncDispatcher();
void DispatchTouchEvents(bool aNotifiedCompositors, TimeStamp aVsyncTime);
// Called on the vsync thread. Returns true if observers were notified
bool NotifyVsyncObservers(TimeStamp aVsyncTimestamp, nsTArray<nsRefPtr<VsyncObserver>>& aObservers);
// Can have multiple compositors. On desktop, this is 1 compositor per window
Mutex mCompositorObserverLock;
nsTArray<nsRefPtr<VsyncObserver>> mCompositorObservers;
nsRefPtr<VsyncSource> mVsyncSource;
}; // VsyncDispatcher
} // namespace mozilla
#endif // __mozilla_widget_VsyncDispatcher_h

View File

@ -237,7 +237,7 @@ HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp)
LOGE("Non-uniform vsync interval: %lld\n", vsyncInterval);
}
mLastVsyncTime = aVsyncTimestamp;
VsyncDispatcher::GetInstance()->NotifyVsync(vsyncTime);
mozilla::layers::VsyncDispatcher::NotifyVsync(vsyncTime);
}
// Called on the "invalidator" thread (run from HAL).

View File

@ -123,7 +123,6 @@ EXPORTS.mozilla += [
'TextEvents.h',
'TextRange.h',
'TouchEvents.h',
'VsyncDispatcher.h',
'WidgetUtils.h',
]
@ -157,7 +156,6 @@ UNIFIED_SOURCES += [
'PuppetWidget.cpp',
'ScreenProxy.cpp',
'SharedWidgetUtils.cpp',
'VsyncDispatcher.cpp',
'WidgetEventImpl.cpp',
'WidgetUtils.cpp',
]