Backed out changeset 82e94c16732d (bug 1101974)

This commit is contained in:
Wes Kocher 2014-11-21 10:52:24 -08:00
parent b50fb9c8e1
commit e2965993d9
6 changed files with 254 additions and 72 deletions

View File

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

View File

@ -35,6 +35,7 @@
#include "nsISupportsImpl.h"
#include "nsSize.h" // for nsIntSize
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
#include "mozilla/VsyncDispatcher.h"
class CancelableTask;
class MessageLoop;
@ -88,53 +89,35 @@ 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 VsyncDispatcher MOZ_FINAL
class CompositorVsyncObserver MOZ_FINAL : public VsyncObserver
{
// 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:
VsyncDispatcher(CompositorParent* aCompositorParent, VsyncSource* aVsyncSource);
static void NotifyVsync(TimeStamp aVsyncTimestamp);
void RunVsync(TimeStamp aVsyncTimestamp);
CompositorVsyncObserver(CompositorParent* aCompositorParent);
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) MOZ_OVERRIDE;
void SetNeedsComposite(bool aSchedule);
bool NeedsComposite();
void CancelCurrentCompositeTask();
private:
virtual ~VsyncDispatcher();
virtual ~CompositorVsyncObserver();
void Composite(TimeStamp aVsyncTimestamp);
void NotifyCompositeTaskExecuted();
void EnableVsync();
void DisableVsync();
void ObserveVsync();
void UnobserveVsync();
void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
bool mNeedsComposite;
bool mIsObservingVsync;
nsRefPtr<CompositorParent> mCompositorParent;
nsRefPtr<VsyncSource> mVsyncSource;
mozilla::Monitor mCurrentCompositeTaskMonitor;
CancelableTask* mCurrentCompositeTask;
@ -144,7 +127,7 @@ class CompositorParent MOZ_FINAL : public PCompositorParent,
public ShadowLayersManager
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorParent)
friend class VsyncDispatcher;
friend class CompositorVsyncObserver;
public:
explicit CompositorParent(nsIWidget* aWidget,
@ -405,7 +388,7 @@ protected:
nsRefPtr<APZCTreeManager> mApzcTreeManager;
nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
nsRefPtr<VsyncDispatcher> mVsyncDispatcher;
nsRefPtr<CompositorVsyncObserver> mCompositorVsyncObserver;
DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
};

117
widget/VsyncDispatcher.cpp Normal file
View File

@ -0,0 +1,117 @@
/* -*- 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

88
widget/VsyncDispatcher.h Normal file
View File

@ -0,0 +1,88 @@
/* -*- 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;
mozilla::layers::VsyncDispatcher::NotifyVsync(vsyncTime);
VsyncDispatcher::GetInstance()->NotifyVsync(vsyncTime);
}
// Called on the "invalidator" thread (run from HAL).

View File

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