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..c1e07b2911fa0997a3b9590518491362b05f01ad 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 != 0) { |
jbauman
2014/09/29 19:37:07
if (result) {
|
+ DEVMODE display_info; |
+ result = EnumDisplaySettings(monitor_info.szDevice, ENUM_CURRENT_SETTINGS, |
+ &display_info); |
+ if (result != 0 && display_info.dmDisplayFrequency > 0) { |
jbauman
2014/09/29 19:37:07
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; |