mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1102631 - Create a software vsync timer. r=kats
This commit is contained in:
parent
483f9be18f
commit
4b9c7c9fe3
116
gfx/thebes/SoftwareVsyncSource.cpp
Normal file
116
gfx/thebes/SoftwareVsyncSource.cpp
Normal 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;
|
||||||
|
}
|
64
gfx/thebes/SoftwareVsyncSource.h
Normal file
64
gfx/thebes/SoftwareVsyncSource.h
Normal 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 */
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 */
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user