Bug 1102631 - Create a software vsync timer. r=kats

This commit is contained in:
Mason Chang 2015-01-08 15:12:47 -08:00
parent 483f9be18f
commit 4b9c7c9fe3
7 changed files with 200 additions and 7 deletions

View File

@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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 "SoftwareVsyncSource.h"
#include "base/task.h"
#include "nsThreadUtils.h"
SoftwareVsyncSource::SoftwareVsyncSource()
{
mGlobalDisplay = new SoftwareDisplay();
}
SoftwareVsyncSource::~SoftwareVsyncSource()
{
MOZ_ASSERT(NS_IsMainThread());
// Ensure we disable vsync on the main thread here
mGlobalDisplay->DisableVsync();
mGlobalDisplay = nullptr;
}
SoftwareDisplay::SoftwareDisplay()
: mCurrentTaskMonitor("SoftwareVsyncCurrentTaskMonitor")
{
// Mimic 60 fps
MOZ_ASSERT(NS_IsMainThread());
const double rate = 1000 / 60.0;
mVsyncRate = mozilla::TimeDuration::FromMilliseconds(rate);
mVsyncThread = new base::Thread("SoftwareVsyncThread");
EnableVsync();
}
void
SoftwareDisplay::EnableVsync()
{
MOZ_ASSERT(NS_IsMainThread());
mozilla::MonitorAutoLock lock(mCurrentTaskMonitor);
mVsyncEnabled = true;
MOZ_ASSERT(!mVsyncThread->IsRunning());
MOZ_RELEASE_ASSERT(mVsyncThread->Start(), "Could not start software vsync thread");
mCurrentVsyncTask = NewRunnableMethod(this,
&SoftwareDisplay::NotifyVsync,
mozilla::TimeStamp::Now());
mVsyncThread->message_loop()->PostTask(FROM_HERE, mCurrentVsyncTask);
}
void
SoftwareDisplay::DisableVsync()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mVsyncThread->IsRunning());
{ // Scope lock
mozilla::MonitorAutoLock lock(mCurrentTaskMonitor);
mVsyncEnabled = false;
if (mCurrentVsyncTask) {
mCurrentVsyncTask->Cancel();
mCurrentVsyncTask = nullptr;
}
}
mVsyncThread->Stop();
}
bool
SoftwareDisplay::IsVsyncEnabled()
{
MOZ_ASSERT(NS_IsMainThread());
mozilla::MonitorAutoLock lock(mCurrentTaskMonitor);
return mVsyncEnabled;
}
bool
SoftwareDisplay::IsInSoftwareVsyncThread()
{
return mVsyncThread->thread_id() == PlatformThread::CurrentId();
}
void
SoftwareDisplay::NotifyVsync(mozilla::TimeStamp aVsyncTimestamp)
{
MOZ_ASSERT(IsInSoftwareVsyncThread());
Display::NotifyVsync(aVsyncTimestamp);
ScheduleNextVsync(aVsyncTimestamp);
}
void
SoftwareDisplay::ScheduleNextVsync(mozilla::TimeStamp aVsyncTimestamp)
{
MOZ_ASSERT(IsInSoftwareVsyncThread());
mozilla::TimeStamp nextVsync = aVsyncTimestamp + mVsyncRate;
mozilla::TimeDuration delay = nextVsync - mozilla::TimeStamp::Now();
if (delay.ToMilliseconds() < 0) {
delay = mozilla::TimeDuration::FromMilliseconds(0);
}
mozilla::MonitorAutoLock lock(mCurrentTaskMonitor);
// We could've disabled vsync between this posted task and when it actually
// executes
if (!mVsyncEnabled) {
return;
}
mCurrentVsyncTask = NewRunnableMethod(this,
&SoftwareDisplay::NotifyVsync,
nextVsync);
mVsyncThread->message_loop()->PostDelayedTask(FROM_HERE,
mCurrentVsyncTask,
delay.ToMilliseconds());
}
SoftwareDisplay::~SoftwareDisplay()
{
MOZ_ASSERT(NS_IsMainThread());
delete mVsyncThread;
}

View File

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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 GFX_SOFTWARE_VSYNC_SOURCE_H
#define GFX_SOFTWARE_VSYNC_SOURCE_H
#include "mozilla/Monitor.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "base/thread.h"
#include "nsISupportsImpl.h"
#include "VsyncSource.h"
class CancelableTask;
class SoftwareDisplay MOZ_FINAL : public mozilla::gfx::VsyncSource::Display
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SoftwareDisplay)
public:
SoftwareDisplay();
virtual void EnableVsync() MOZ_OVERRIDE;
virtual void DisableVsync() MOZ_OVERRIDE;
virtual bool IsVsyncEnabled() MOZ_OVERRIDE;
bool IsInSoftwareVsyncThread();
virtual void NotifyVsync(mozilla::TimeStamp aVsyncTimestamp) MOZ_OVERRIDE;
void ScheduleNextVsync(mozilla::TimeStamp aVsyncTimestamp);
protected:
~SoftwareDisplay();
private:
mozilla::TimeDuration mVsyncRate;
// Use a chromium thread because nsITimers* fire on the main thread
base::Thread* mVsyncThread;
bool mVsyncEnabled;
CancelableTask* mCurrentVsyncTask;
// Locks against both mCurrentVsyncTask and mVsyncEnabled
mozilla::Monitor mCurrentTaskMonitor;
}; // SoftwareDisplay
// Fallback option to use a software timer to mimic vsync. Useful for gtests
// To mimic a hardware vsync thread, we create a dedicated software timer
// vsync thread.
class SoftwareVsyncSource : public mozilla::gfx::VsyncSource
{
public:
SoftwareVsyncSource();
~SoftwareVsyncSource();
virtual Display& GetGlobalDisplay() MOZ_OVERRIDE
{
MOZ_ASSERT(mGlobalDisplay != nullptr);
return *mGlobalDisplay;
}
private:
nsRefPtr<SoftwareDisplay> mGlobalDisplay;
};
#endif /* GFX_SOFTWARE_VSYNC_SOURCE_H */

View File

@ -35,7 +35,7 @@ VsyncSource::FindDisplay(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
void void
VsyncSource::Display::NotifyVsync(TimeStamp aVsyncTimestamp) VsyncSource::Display::NotifyVsync(TimeStamp aVsyncTimestamp)
{ {
// Called on the hardware vsync thread // Called on the vsync thread
for (size_t i = 0; i < mCompositorVsyncDispatchers.Length(); i++) { for (size_t i = 0; i < mCompositorVsyncDispatchers.Length(); i++) {
mCompositorVsyncDispatchers[i]->NotifyVsync(aVsyncTimestamp); mCompositorVsyncDispatchers[i]->NotifyVsync(aVsyncTimestamp);
} }

View File

@ -3,6 +3,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFX_VSYNCSOURCE_H
#define GFX_VSYNCSOURCE_H
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
@ -26,8 +29,8 @@ public:
virtual ~Display(); virtual ~Display();
void AddCompositorVsyncDispatcher(mozilla::CompositorVsyncDispatcher* aCompositorVsyncDispatcher); void AddCompositorVsyncDispatcher(mozilla::CompositorVsyncDispatcher* aCompositorVsyncDispatcher);
void RemoveCompositorVsyncDispatcher(mozilla::CompositorVsyncDispatcher* aCompositorVsyncDispatcher); void RemoveCompositorVsyncDispatcher(mozilla::CompositorVsyncDispatcher* aCompositorVsyncDispatcher);
// Notified when this display's vsync occurs, on the hardware vsync thread // Notified when this display's vsync occurs, on the vsync thread
void NotifyVsync(mozilla::TimeStamp aVsyncTimestamp); virtual void NotifyVsync(mozilla::TimeStamp aVsyncTimestamp);
// These should all only be called on the main thread // These should all only be called on the main thread
virtual void EnableVsync() = 0; virtual void EnableVsync() = 0;
@ -48,3 +51,5 @@ protected:
}; // VsyncSource }; // VsyncSource
} // gfx } // gfx
} // mozilla } // mozilla
#endif /* GFX_VSYNCSOURCE_H */

View File

@ -105,6 +105,7 @@ class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
#include "nsIGfxInfo.h" #include "nsIGfxInfo.h"
#include "nsIXULRuntime.h" #include "nsIXULRuntime.h"
#include "VsyncSource.h" #include "VsyncSource.h"
#include "SoftwareVsyncSource.h"
namespace mozilla { namespace mozilla {
namespace layers { namespace layers {
@ -2283,3 +2284,11 @@ gfxPlatform::UsesOffMainThreadCompositing()
return result; return result;
} }
already_AddRefed<mozilla::gfx::VsyncSource>
gfxPlatform::CreateHardwareVsyncSource()
{
NS_WARNING("Hardware Vsync support not yet implemented. Falling back to software timers\n");
nsRefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource();
return softwareVsync.forget();
}

View File

@ -604,10 +604,7 @@ protected:
/** /**
* Initialized hardware vsync based on each platform. * Initialized hardware vsync based on each platform.
*/ */
virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() { virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource();
NS_WARNING("Hardware vsync not supported on platform yet");
return nullptr;
}
/** /**
* Helper method, creates a draw target for a specific Azure backend. * Helper method, creates a draw target for a specific Azure backend.

View File

@ -52,6 +52,7 @@ EXPORTS += [
'gfxVR.h', 'gfxVR.h',
'GraphicsFilter.h', 'GraphicsFilter.h',
'RoundedRect.h', 'RoundedRect.h',
'SoftwareVsyncSource.h',
'VsyncSource.h', 'VsyncSource.h',
] ]
@ -245,6 +246,7 @@ UNIFIED_SOURCES += [
'gfxUtils.cpp', 'gfxUtils.cpp',
'gfxVR.cpp', 'gfxVR.cpp',
'nsUnicodeRange.cpp', 'nsUnicodeRange.cpp',
'SoftwareVsyncSource.cpp',
'VsyncSource.cpp', 'VsyncSource.cpp',
] ]