Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(547)

Side by Side Diff: gpu/ipc/service/gpu_vsync_provider_win.cc

Issue 2722073002: GPU VSync: add timer based v-sync as a backup mechanism for when display goes to sleep. (Closed)
Patch Set: Removed empty line Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "gpu/ipc/service/gpu_vsync_provider_win.h" 5 #include "gpu/ipc/service/gpu_vsync_provider_win.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/atomicops.h" 9 #include "base/atomicops.h"
10 #include "base/debug/alias.h"
10 #include "base/strings/stringprintf.h" 11 #include "base/strings/stringprintf.h"
11 #include "base/threading/thread.h" 12 #include "base/threading/thread.h"
12 #include "base/trace_event/trace_event.h" 13 #include "base/trace_event/trace_event.h"
13 #include "gpu/ipc/common/gpu_messages.h" 14 #include "gpu/ipc/common/gpu_messages.h"
14 #include "ipc/ipc_message_macros.h" 15 #include "ipc/ipc_message_macros.h"
15 #include "ipc/message_filter.h" 16 #include "ipc/message_filter.h"
16 #include "ui/gl/vsync_provider_win.h" 17 #include "ui/gl/vsync_provider_win.h"
17 18
18 #include <windows.h> 19 #include <windows.h>
19 20
20 namespace gpu { 21 namespace gpu {
21 22
22 namespace { 23 namespace {
24 // Default interval used when no v-sync interval comes from DWM.
25 const int kDefaultTimerBasedInterval = 16666;
26
23 // from <D3dkmthk.h> 27 // from <D3dkmthk.h>
24 typedef LONG NTSTATUS; 28 typedef LONG NTSTATUS;
25 typedef UINT D3DKMT_HANDLE; 29 typedef UINT D3DKMT_HANDLE;
26 typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID; 30 typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;
27 31
28 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) 32 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
33 #define STATUS_GRAPHICS_PRESENT_OCCLUDED ((NTSTATUS)0xC01E0006L)
29 34
30 typedef struct _D3DKMT_OPENADAPTERFROMHDC { 35 typedef struct _D3DKMT_OPENADAPTERFROMHDC {
31 HDC hDc; 36 HDC hDc;
32 D3DKMT_HANDLE hAdapter; 37 D3DKMT_HANDLE hAdapter;
33 LUID AdapterLuid; 38 LUID AdapterLuid;
34 D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId; 39 D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
35 } D3DKMT_OPENADAPTERFROMHDC; 40 } D3DKMT_OPENADAPTERFROMHDC;
36 41
37 typedef struct _D3DKMT_CLOSEADAPTER { 42 typedef struct _D3DKMT_CLOSEADAPTER {
38 D3DKMT_HANDLE hAdapter; 43 D3DKMT_HANDLE hAdapter;
(...skipping 17 matching lines...) Expand all
56 class GpuVSyncWorker : public base::Thread, 61 class GpuVSyncWorker : public base::Thread,
57 public base::RefCountedThreadSafe<GpuVSyncWorker> { 62 public base::RefCountedThreadSafe<GpuVSyncWorker> {
58 public: 63 public:
59 GpuVSyncWorker(const gfx::VSyncProvider::UpdateVSyncCallback& callback, 64 GpuVSyncWorker(const gfx::VSyncProvider::UpdateVSyncCallback& callback,
60 SurfaceHandle surface_handle); 65 SurfaceHandle surface_handle);
61 66
62 void CleanupAndStop(); 67 void CleanupAndStop();
63 void Enable(bool enabled); 68 void Enable(bool enabled);
64 void StartRunningVSyncOnThread(); 69 void StartRunningVSyncOnThread();
65 void WaitForVSyncOnThread(); 70 void WaitForVSyncOnThread();
66 void SendVSyncUpdate(base::TimeTicks now,
67 base::TimeTicks timestamp,
68 base::TimeDelta interval);
69 bool BelongsToWorkerThread(); 71 bool BelongsToWorkerThread();
70 72
71 private: 73 private:
72 friend class base::RefCountedThreadSafe<GpuVSyncWorker>; 74 friend class base::RefCountedThreadSafe<GpuVSyncWorker>;
73 ~GpuVSyncWorker() override; 75 ~GpuVSyncWorker() override;
74 76
75 void Reschedule(); 77 void Reschedule();
76 void OpenAdapter(const wchar_t* device_name); 78 void OpenAdapter(const wchar_t* device_name);
77 void CloseAdapter(); 79 void CloseAdapter();
78 bool WaitForVBlankEvent(); 80 NTSTATUS WaitForVBlankEvent();
81
82 void SendGpuVSyncUpdate(base::TimeTicks now,
83 base::TimeTicks timestamp,
84 base::TimeDelta interval);
85 void InvokeCallbackAndReschedule(base::TimeTicks timestamp,
86 base::TimeDelta interval);
87 void ScheduleDelayBasedVSync(base::TimeTicks timebase,
88 base::TimeDelta interval);
79 89
80 // Specifies whether background tasks are running. 90 // Specifies whether background tasks are running.
81 // This can be set on background thread only. 91 // This can be set on background thread only.
82 bool running_ = false; 92 bool running_ = false;
83 93
84 // Specified whether the worker is enabled. This is accessed from both 94 // Specified whether the worker is enabled. This is accessed from both
85 // threads but can be changed on the main thread only. 95 // threads but can be changed on the main thread only.
86 base::subtle::AtomicWord enabled_ = false; 96 base::subtle::AtomicWord enabled_ = false;
87 97
88 const gfx::VSyncProvider::UpdateVSyncCallback callback_; 98 const gfx::VSyncProvider::UpdateVSyncCallback callback_;
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 monitor_info.cbSize = sizeof(MONITORINFOEX); 193 monitor_info.cbSize = sizeof(MONITORINFOEX);
184 BOOL success = GetMonitorInfo(monitor, &monitor_info); 194 BOOL success = GetMonitorInfo(monitor, &monitor_info);
185 CHECK(success); 195 CHECK(success);
186 196
187 if (current_device_name_.compare(monitor_info.szDevice) != 0) { 197 if (current_device_name_.compare(monitor_info.szDevice) != 0) {
188 // Monitor changed. Close the current adapter handle and open a new one. 198 // Monitor changed. Close the current adapter handle and open a new one.
189 CloseAdapter(); 199 CloseAdapter();
190 OpenAdapter(monitor_info.szDevice); 200 OpenAdapter(monitor_info.szDevice);
191 } 201 }
192 202
193 // Crash if WaitForVBlankEvent fails to avoid spinning the loop. 203 NTSTATUS wait_result = WaitForVBlankEvent();
194 CHECK(WaitForVBlankEvent()); 204 if (wait_result != STATUS_SUCCESS) {
205 if (wait_result == STATUS_GRAPHICS_PRESENT_OCCLUDED) {
206 // This may be triggered by the monitor going into sleep.
207 // Use timer based mechanism as a backup, start with getting VSync
208 // parameters to determine timebase and interval.
209 // TODO(stanisc): Consider a slower v-sync rate in this particular case.
210 vsync_provider_->GetVSyncParameters(base::Bind(
211 &GpuVSyncWorker::ScheduleDelayBasedVSync, base::Unretained(this)));
212 return;
213 } else {
214 base::debug::Alias(&wait_result);
215 CHECK(false);
216 }
217 }
195 218
196 vsync_provider_->GetVSyncParameters( 219 vsync_provider_->GetVSyncParameters(
197 base::Bind(&GpuVSyncWorker::SendVSyncUpdate, base::Unretained(this), 220 base::Bind(&GpuVSyncWorker::SendGpuVSyncUpdate, base::Unretained(this),
198 base::TimeTicks::Now())); 221 base::TimeTicks::Now()));
199
200 Reschedule();
201 } 222 }
202 223
203 void GpuVSyncWorker::SendVSyncUpdate(base::TimeTicks now, 224 void GpuVSyncWorker::SendGpuVSyncUpdate(base::TimeTicks now,
204 base::TimeTicks timestamp, 225 base::TimeTicks timestamp,
205 base::TimeDelta interval) { 226 base::TimeDelta interval) {
206 base::TimeDelta adjustment; 227 base::TimeDelta adjustment;
207 228
208 if (!(timestamp.is_null() || interval.is_zero())) { 229 if (!(timestamp.is_null() || interval.is_zero())) {
209 // Timestamp comes from DwmGetCompositionTimingInfo and apparently it might 230 // Timestamp comes from DwmGetCompositionTimingInfo and apparently it might
210 // be up to 2-3 vsync cycles in the past or in the future. 231 // be up to 2-3 vsync cycles in the past or in the future.
211 // The adjustment formula was suggested here: 232 // The adjustment formula was suggested here:
212 // http://www.vsynctester.com/firefoxisbroken.html 233 // http://www.vsynctester.com/firefoxisbroken.html
213 adjustment = 234 adjustment =
214 ((now - timestamp + interval / 8) % interval + interval) % interval - 235 ((now - timestamp + interval / 8) % interval + interval) % interval -
215 interval / 8; 236 interval / 8;
216 timestamp = now - adjustment; 237 timestamp = now - adjustment;
217 } else { 238 } else {
218 // DWM must be disabled. 239 // DWM must be disabled.
219 timestamp = now; 240 timestamp = now;
220 } 241 }
221 242
222 TRACE_EVENT1("gpu", "GpuVSyncWorker::SendVSyncUpdate", "adjustment", 243 TRACE_EVENT1("gpu", "GpuVSyncWorker::SendGpuVSyncUpdate", "adjustment",
223 adjustment.ToInternalValue()); 244 adjustment.ToInternalValue());
224 245
246 InvokeCallbackAndReschedule(timestamp, interval);
247 }
248
249 void GpuVSyncWorker::InvokeCallbackAndReschedule(base::TimeTicks timestamp,
250 base::TimeDelta interval) {
251 // Send update and restart the task if still enabled.
225 if (base::subtle::NoBarrier_Load(&enabled_)) { 252 if (base::subtle::NoBarrier_Load(&enabled_)) {
226 callback_.Run(timestamp, interval); 253 callback_.Run(timestamp, interval);
227 }
228 }
229
230 void GpuVSyncWorker::Reschedule() {
231 // Restart the task if still enabled.
232 if (base::subtle::NoBarrier_Load(&enabled_)) {
233 task_runner()->PostTask(FROM_HERE, 254 task_runner()->PostTask(FROM_HERE,
234 base::Bind(&GpuVSyncWorker::WaitForVSyncOnThread, 255 base::Bind(&GpuVSyncWorker::WaitForVSyncOnThread,
235 base::Unretained(this))); 256 base::Unretained(this)));
236 } else { 257 } else {
237 running_ = false; 258 running_ = false;
238 } 259 }
239 } 260 }
240 261
262 void GpuVSyncWorker::ScheduleDelayBasedVSync(base::TimeTicks timebase,
263 base::TimeDelta interval) {
264 // This is called only when WaitForVBlankEvent fails due to monitor going to
265 // sleep. Use a delay based v-sync as a back-up.
266 if (interval.is_zero()) {
267 interval = base::TimeDelta::FromMicroseconds(kDefaultTimerBasedInterval);
268 }
269
270 base::TimeTicks now = base::TimeTicks::Now();
271 base::TimeTicks next_vsync = now.SnappedToNextTick(timebase, interval);
272
273 task_runner()->PostDelayedTask(
274 FROM_HERE,
275 base::Bind(&GpuVSyncWorker::InvokeCallbackAndReschedule,
276 base::Unretained(this), next_vsync, interval),
277 next_vsync - now);
278 }
279
241 void GpuVSyncWorker::OpenAdapter(const wchar_t* device_name) { 280 void GpuVSyncWorker::OpenAdapter(const wchar_t* device_name) {
242 DCHECK_EQ(0u, current_adapter_handle_); 281 DCHECK_EQ(0u, current_adapter_handle_);
243 282
244 HDC hdc = CreateDC(NULL, device_name, NULL, NULL); 283 HDC hdc = CreateDC(NULL, device_name, NULL, NULL);
245 284
246 D3DKMT_OPENADAPTERFROMHDC open_adapter_data; 285 D3DKMT_OPENADAPTERFROMHDC open_adapter_data;
247 open_adapter_data.hDc = hdc; 286 open_adapter_data.hDc = hdc;
248 287
249 NTSTATUS result = open_adapter_from_hdc_ptr_(&open_adapter_data); 288 NTSTATUS result = open_adapter_from_hdc_ptr_(&open_adapter_data);
250 DeleteDC(hdc); 289 DeleteDC(hdc);
(...skipping 11 matching lines...) Expand all
262 close_adapter_data.hAdapter = current_adapter_handle_; 301 close_adapter_data.hAdapter = current_adapter_handle_;
263 302
264 NTSTATUS result = close_adapter_ptr_(&close_adapter_data); 303 NTSTATUS result = close_adapter_ptr_(&close_adapter_data);
265 CHECK(result == STATUS_SUCCESS); 304 CHECK(result == STATUS_SUCCESS);
266 305
267 current_adapter_handle_ = 0; 306 current_adapter_handle_ = 0;
268 current_device_name_.clear(); 307 current_device_name_.clear();
269 } 308 }
270 } 309 }
271 310
272 bool GpuVSyncWorker::WaitForVBlankEvent() { 311 NTSTATUS GpuVSyncWorker::WaitForVBlankEvent() {
273 D3DKMT_WAITFORVERTICALBLANKEVENT wait_for_vertical_blank_event_data; 312 D3DKMT_WAITFORVERTICALBLANKEVENT wait_for_vertical_blank_event_data;
274 wait_for_vertical_blank_event_data.hAdapter = current_adapter_handle_; 313 wait_for_vertical_blank_event_data.hAdapter = current_adapter_handle_;
275 wait_for_vertical_blank_event_data.hDevice = 0; 314 wait_for_vertical_blank_event_data.hDevice = 0;
276 wait_for_vertical_blank_event_data.VidPnSourceId = current_source_id_; 315 wait_for_vertical_blank_event_data.VidPnSourceId = current_source_id_;
277 316
278 NTSTATUS result = 317 return wait_for_vertical_blank_event_ptr_(
279 wait_for_vertical_blank_event_ptr_(&wait_for_vertical_blank_event_data); 318 &wait_for_vertical_blank_event_data);
280
281 return result == STATUS_SUCCESS;
282 } 319 }
283 320
284 // MessageFilter class for sending and receiving IPC messages 321 // MessageFilter class for sending and receiving IPC messages
285 // directly, avoiding routing them through the main GPU thread. 322 // directly, avoiding routing them through the main GPU thread.
286 class GpuVSyncMessageFilter : public IPC::MessageFilter { 323 class GpuVSyncMessageFilter : public IPC::MessageFilter {
287 public: 324 public:
288 explicit GpuVSyncMessageFilter( 325 explicit GpuVSyncMessageFilter(
289 const scoped_refptr<GpuVSyncWorker>& vsync_worker, 326 const scoped_refptr<GpuVSyncWorker>& vsync_worker,
290 int32_t route_id) 327 int32_t route_id)
291 : vsync_worker_(vsync_worker), route_id_(route_id) {} 328 : vsync_worker_(vsync_worker), route_id_(route_id) {}
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 void GpuVSyncProviderWin::OnVSync(base::TimeTicks timestamp, 422 void GpuVSyncProviderWin::OnVSync(base::TimeTicks timestamp,
386 base::TimeDelta interval) { 423 base::TimeDelta interval) {
387 DCHECK(vsync_worker_->BelongsToWorkerThread()); 424 DCHECK(vsync_worker_->BelongsToWorkerThread());
388 425
389 message_filter_->Send( 426 message_filter_->Send(
390 base::MakeUnique<GpuCommandBufferMsg_UpdateVSyncParameters>( 427 base::MakeUnique<GpuCommandBufferMsg_UpdateVSyncParameters>(
391 message_filter_->route_id(), timestamp, interval)); 428 message_filter_->route_id(), timestamp, interval));
392 } 429 }
393 430
394 } // namespace gpu 431 } // namespace gpu
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698