author | Mason Chang <mchang@mozilla.com> |
Fri, 13 Feb 2015 17:17:26 +0800 | |
changeset 229112 | 6b41f4a594473ffcabf7d7885d166a7d9648fae6 |
parent 229111 | 9b1c4da648cabaefc13638f720408dee3d3ea33a |
child 229113 | f0649ab1c75fbe9a865a7d375c5ca2b8a31982da |
push id | 28282 |
push user | cbook@mozilla.com |
push date | Mon, 16 Feb 2015 15:06:35 +0000 |
treeherder | mozilla-central@09f4968d5f42 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jrmuizel |
bugs | 1127151 |
milestone | 38.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1908,29 +1908,40 @@ gfxWindowsPlatform::InitD3D11Devices() Factory::SetDirect3D11Device(mD3D11ContentDevice); } // We leak these everywhere and we need them our entire runtime anyway, let's // leak it here as well. d3d11Module.disown(); } +static bool +DwmCompositionEnabled() +{ + MOZ_ASSERT(WinUtils::dwmIsCompositionEnabledPtr); + BOOL dwmEnabled = false; + WinUtils::dwmIsCompositionEnabledPtr(&dwmEnabled); + return dwmEnabled; +} + class D3DVsyncSource MOZ_FINAL : public VsyncSource { public: class D3DVsyncDisplay MOZ_FINAL : public VsyncSource::Display { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(D3DVsyncDisplay) public: D3DVsyncDisplay() : mVsyncEnabledLock("D3DVsyncEnabledLock") , mVsyncEnabled(false) { mVsyncThread = new base::Thread("WindowsVsyncThread"); + const double rate = 1000 / 60.0; + mSoftwareVsyncRate = TimeDuration::FromMilliseconds(rate); } virtual ~D3DVsyncDisplay() { MOZ_ASSERT(NS_IsMainThread()); DisableVsync(); delete mVsyncThread; } @@ -1968,22 +1979,86 @@ public: virtual bool IsVsyncEnabled() MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); MonitorAutoLock lock(mVsyncEnabledLock); return mVsyncEnabled; } + void ScheduleSoftwareVsync(TimeStamp aVsyncTimestamp) + { + MOZ_ASSERT(IsInVsyncThread()); + NS_WARNING("DwmComposition dynamically disabled, falling back to software timers\n"); + + TimeStamp nextVsync = aVsyncTimestamp + mSoftwareVsyncRate; + TimeDuration delay = nextVsync - TimeStamp::Now(); + if (delay.ToMilliseconds() < 0) { + delay = mozilla::TimeDuration::FromMilliseconds(0); + } + + mVsyncThread->message_loop()->PostDelayedTask(FROM_HERE, + NewRunnableMethod(this, &D3DVsyncDisplay::VBlankLoop), + delay.ToMilliseconds()); + } + + void VBlankLoop() + { + MOZ_ASSERT(IsInVsyncThread()); + + DWM_TIMING_INFO vblankTime; + // Make sure to init the cbSize, otherwise GetCompositionTiming will fail + vblankTime.cbSize = sizeof(DWM_TIMING_INFO); + + LARGE_INTEGER qpcNow; + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + TimeStamp vsync = TimeStamp::Now(); + const int microseconds = 1000000; + + for (;;) { + { // scope lock + MonitorAutoLock lock(mVsyncEnabledLock); + if (!mVsyncEnabled) return; + } + + Display::NotifyVsync(vsync); + + // DwmComposition can be dynamically enabled/disabled + // so we have to check every time that it's available. + // When it is unavailable, we fallback to software but will try + // to get back to dwm rendering once it's re-enabled + if (!DwmCompositionEnabled()) { + ScheduleSoftwareVsync(vsync); + return; + } + + // Use a combination of DwmFlush + DwmGetCompositionTimingInfoPtr + // The qpcVBlank is always AFTER Now(), so it behaves like b2g + // Using WaitForVBlank, the whole system dies :/ + WinUtils::dwmFlushProcPtr(); + HRESULT hr = WinUtils::dwmGetCompositionTimingInfoPtr(0, &vblankTime); + vsync = TimeStamp::Now(); + if (SUCCEEDED(hr)) { + QueryPerformanceCounter(&qpcNow); + QPC_TIME adjust = qpcNow.QuadPart - vblankTime.qpcVBlank; + MOZ_ASSERT(adjust > 0); + uint64_t usAdjust = (adjust * microseconds) / frequency.QuadPart; + vsync -= TimeDuration::FromMicroseconds((double) usAdjust); + } + } // end for + } + private: bool IsInVsyncThread() { return mVsyncThread->thread_id() == PlatformThread::CurrentId(); } + TimeDuration mSoftwareVsyncRate; Monitor mVsyncEnabledLock; base::Thread* mVsyncThread; bool mVsyncEnabled; }; // end d3dvsyncdisplay D3DVsyncSource() { mPrimaryDisplay = new D3DVsyncDisplay();