| Index: ui/gl/gl_surface_win.cc
|
| diff --git a/ui/gl/gl_surface_win.cc b/ui/gl/gl_surface_win.cc
|
| index 3cde3ea9c7645ffd1dd9d20cf5ae19f603ccd9be..a3142ef219d0b35dd78fac7986bde6c51696fe86 100644
|
| --- a/ui/gl/gl_surface_win.cc
|
| +++ b/ui/gl/gl_surface_win.cc
|
| @@ -59,43 +59,88 @@ class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
|
| DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
|
| };
|
|
|
| -class DWMVSyncProvider : public VSyncProvider {
|
| +class WinVSyncProvider : public VSyncProvider {
|
| public:
|
| - explicit DWMVSyncProvider() {}
|
| + explicit WinVSyncProvider(gfx::AcceleratedWidget window) :
|
| + window_(window)
|
| + {
|
| + use_dwm_ = (base::win::GetVersion() >= base::win::VERSION_VISTA);
|
| + }
|
|
|
| - virtual ~DWMVSyncProvider() {}
|
| + virtual ~WinVSyncProvider() {}
|
|
|
| virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) {
|
| - TRACE_EVENT0("gpu", "DWMVSyncProvider::GetVSyncParameters");
|
| - DWM_TIMING_INFO timing_info;
|
| - timing_info.cbSize = sizeof(timing_info);
|
| - HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
|
| - if (result != S_OK)
|
| - return;
|
| + TRACE_EVENT0("gpu", "WinVSyncProvider::GetVSyncParameters");
|
|
|
| base::TimeTicks timebase;
|
| - // If FrameTime is not high resolution, we do not want to translate the
|
| - // QPC value provided by DWM into the low-resolution timebase, which
|
| - // would be error prone and jittery. As a fallback, we assume the timebase
|
| - // is zero.
|
| - if (gfx::FrameTime::TimestampsAreHighRes()) {
|
| - timebase = gfx::FrameTime::FromQPCValue(
|
| - static_cast<LONGLONG>(timing_info.qpcVBlank));
|
| + base::TimeDelta interval;
|
| + bool dwm_active = false;
|
| +
|
| + // Query the DWM timing info first if available. This will provide the most
|
| + // precise values.
|
| + if (use_dwm_) {
|
| + DWM_TIMING_INFO timing_info;
|
| + timing_info.cbSize = sizeof(timing_info);
|
| + HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
|
| + if (result == S_OK) {
|
| + dwm_active = true;
|
| + // If FrameTime is not high resolution, we do not want to translate the
|
| + // QPC value provided by DWM into the low-resolution timebase, which
|
| + // would be error prone and jittery. As a fallback, we assume the
|
| + // timebase is zero.
|
| + if (gfx::FrameTime::TimestampsAreHighRes()) {
|
| + timebase = gfx::FrameTime::FromQPCValue(
|
| + static_cast<LONGLONG>(timing_info.qpcVBlank));
|
| + }
|
| +
|
| + // Swap the numerator/denominator to convert frequency to period.
|
| + if (timing_info.rateRefresh.uiDenominator > 0 &&
|
| + timing_info.rateRefresh.uiNumerator > 0) {
|
| + interval = base::TimeDelta::FromMicroseconds(
|
| + timing_info.rateRefresh.uiDenominator *
|
| + base::Time::kMicrosecondsPerSecond /
|
| + timing_info.rateRefresh.uiNumerator);
|
| + }
|
| + }
|
| }
|
|
|
| - // Swap the numerator/denominator to convert frequency to period.
|
| - if (timing_info.rateRefresh.uiDenominator > 0 &&
|
| - timing_info.rateRefresh.uiNumerator > 0) {
|
| - base::TimeDelta interval = base::TimeDelta::FromMicroseconds(
|
| - timing_info.rateRefresh.uiDenominator *
|
| - base::Time::kMicrosecondsPerSecond /
|
| - timing_info.rateRefresh.uiNumerator);
|
| + // Double check DWM values against per-display refresh rates.
|
| + // When DWM compositing is active all displays are normalized to the
|
| + // refresh rate of the primary display, and won't composite any faster.
|
| + // If the display refresh rate is higher than the DWM reported value we will
|
| + // favor the DWM value because any additional frames produced will be
|
| + // discarded by the OS. If the display refresh rate is lower, however, we
|
| + // can use that to limit the frames we produce more intelligently.
|
| + // If DWM compositing is not active we will always use the display refresh.
|
| + HMONITOR monitor = MonitorFromWindow(window_, MONITOR_DEFAULTTONEAREST);
|
| + MONITORINFOEX monitor_info;
|
| + monitor_info.cbSize = sizeof(MONITORINFOEX);
|
| + BOOL result = GetMonitorInfo(monitor, &monitor_info);
|
| + if (result) {
|
| + DEVMODE display_info;
|
| + result = EnumDisplaySettings(monitor_info.szDevice, ENUM_CURRENT_SETTINGS,
|
| + &display_info);
|
| + if (result && display_info.dmDisplayFrequency > 1) {
|
| + base::TimeDelta display_interval = base::TimeDelta::FromMicroseconds(
|
| + (1.0 / static_cast<double>(display_info.dmDisplayFrequency)) *
|
| + base::Time::kMicrosecondsPerSecond);
|
| +
|
| + if (!dwm_active || display_interval > interval) {
|
| + interval = display_interval;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (interval.ToInternalValue() != 0) {
|
| callback.Run(timebase, interval);
|
| }
|
| }
|
|
|
| private:
|
| - DISALLOW_COPY_AND_ASSIGN(DWMVSyncProvider);
|
| + DISALLOW_COPY_AND_ASSIGN(WinVSyncProvider);
|
| +
|
| + gfx::AcceleratedWidget window_;
|
| + bool use_dwm_;
|
| };
|
|
|
| // Helper routine that does one-off initialization like determining the
|
| @@ -245,8 +290,7 @@ scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
|
| scoped_refptr<NativeViewGLSurfaceEGL> surface(
|
| new NativeViewGLSurfaceEGL(window));
|
| scoped_ptr<VSyncProvider> sync_provider;
|
| - if (base::win::GetVersion() >= base::win::VERSION_VISTA)
|
| - sync_provider.reset(new DWMVSyncProvider);
|
| + sync_provider.reset(new WinVSyncProvider(window));
|
| if (!surface->Initialize(sync_provider.Pass()))
|
| return NULL;
|
|
|
|
|