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

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

Issue 2626413002: Route D3D VSync signal to Compositor (Closed)
Patch Set: Implement GPU VSync provider as gl::VSyncProvider Created 3 years, 10 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
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.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/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
11 #include "base/threading/thread.h" 11 #include "base/threading/thread.h"
12 #include "base/trace_event/trace_event.h" 12 #include "base/trace_event/trace_event.h"
13 #include "gpu/ipc/common/gpu_messages.h"
14 #include "ipc/ipc_message_macros.h"
15 #include "ipc/message_filter.h"
16 #include "ui/gl/vsync_provider_win.h"
13 17
14 #include <windows.h> 18 #include <windows.h>
15 19
16 namespace gpu { 20 namespace gpu {
17 21
18 namespace { 22 namespace {
19 // from <D3dkmthk.h> 23 // from <D3dkmthk.h>
20 typedef LONG NTSTATUS; 24 typedef LONG NTSTATUS;
21 typedef UINT D3DKMT_HANDLE; 25 typedef UINT D3DKMT_HANDLE;
22 typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID; 26 typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;
(...skipping 19 matching lines...) Expand all
42 46
43 typedef NTSTATUS(APIENTRY* PFND3DKMTOPENADAPTERFROMHDC)( 47 typedef NTSTATUS(APIENTRY* PFND3DKMTOPENADAPTERFROMHDC)(
44 D3DKMT_OPENADAPTERFROMHDC*); 48 D3DKMT_OPENADAPTERFROMHDC*);
45 typedef NTSTATUS(APIENTRY* PFND3DKMTCLOSEADAPTER)(D3DKMT_CLOSEADAPTER*); 49 typedef NTSTATUS(APIENTRY* PFND3DKMTCLOSEADAPTER)(D3DKMT_CLOSEADAPTER*);
46 typedef NTSTATUS(APIENTRY* PFND3DKMTWAITFORVERTICALBLANKEVENT)( 50 typedef NTSTATUS(APIENTRY* PFND3DKMTWAITFORVERTICALBLANKEVENT)(
47 D3DKMT_WAITFORVERTICALBLANKEVENT*); 51 D3DKMT_WAITFORVERTICALBLANKEVENT*);
48 } // namespace 52 } // namespace
49 53
50 // The actual implementation of background tasks plus any state that might be 54 // The actual implementation of background tasks plus any state that might be
51 // needed on the worker thread. 55 // needed on the worker thread.
52 class GpuVSyncWorker : public base::Thread { 56 class GpuVSyncWorker : public base::Thread,
57 public base::RefCountedThreadSafe<GpuVSyncWorker> {
53 public: 58 public:
54 GpuVSyncWorker(const GpuVSyncProvider::VSyncCallback& callback, 59 GpuVSyncWorker(const VSyncCallback& callback, SurfaceHandle surface_handle);
55 SurfaceHandle surface_handle);
56 ~GpuVSyncWorker() override;
57 60
61 void CleanupAndStop();
58 void Enable(bool enabled); 62 void Enable(bool enabled);
59 void StartRunningVSyncOnThread(); 63 void StartRunningVSyncOnThread();
60 void WaitForVSyncOnThread(); 64 void WaitForVSyncOnThread();
61 void SendVSyncUpdate(base::TimeTicks timestamp); 65 void SendVSyncUpdate(base::TimeTicks timestamp);
66 bool BelongsToWorkerThread();
62 67
63 private: 68 private:
69 friend class base::RefCountedThreadSafe<GpuVSyncWorker>;
70 ~GpuVSyncWorker() override;
71
64 void Reschedule(); 72 void Reschedule();
65 void OpenAdapter(const wchar_t* device_name); 73 void OpenAdapter(const wchar_t* device_name);
66 void CloseAdapter(); 74 void CloseAdapter();
67 bool WaitForVBlankEvent(); 75 bool WaitForVBlankEvent();
68 76
69 // Specifies whether background tasks are running. 77 // Specifies whether background tasks are running.
70 // This can be set on background thread only. 78 // This can be set on background thread only.
71 bool running_ = false; 79 bool running_ = false;
72 80
73 // Specified whether the worker is enabled. This is accessed from both 81 // Specified whether the worker is enabled. This is accessed from both
74 // threads but can be changed on the main thread only. 82 // threads but can be changed on the main thread only.
75 base::subtle::AtomicWord enabled_ = false; 83 base::subtle::AtomicWord enabled_ = false;
76 84
77 const GpuVSyncProvider::VSyncCallback callback_; 85 const VSyncCallback callback_;
78 const SurfaceHandle surface_handle_; 86 const SurfaceHandle surface_handle_;
79 87
80 PFND3DKMTOPENADAPTERFROMHDC open_adapter_from_hdc_ptr_; 88 PFND3DKMTOPENADAPTERFROMHDC open_adapter_from_hdc_ptr_;
81 PFND3DKMTCLOSEADAPTER close_adapter_ptr_; 89 PFND3DKMTCLOSEADAPTER close_adapter_ptr_;
82 PFND3DKMTWAITFORVERTICALBLANKEVENT wait_for_vertical_blank_event_ptr_; 90 PFND3DKMTWAITFORVERTICALBLANKEVENT wait_for_vertical_blank_event_ptr_;
83 91
84 std::wstring current_device_name_; 92 std::wstring current_device_name_;
85 D3DKMT_HANDLE current_adapter_handle_ = 0; 93 D3DKMT_HANDLE current_adapter_handle_ = 0;
86 D3DDDI_VIDEO_PRESENT_SOURCE_ID current_source_id_ = 0; 94 D3DDDI_VIDEO_PRESENT_SOURCE_ID current_source_id_ = 0;
87 }; 95 };
88 96
89 GpuVSyncWorker::GpuVSyncWorker(const GpuVSyncProvider::VSyncCallback& callback, 97 GpuVSyncWorker::GpuVSyncWorker(const VSyncCallback& callback,
90 SurfaceHandle surface_handle) 98 SurfaceHandle surface_handle)
91 : base::Thread(base::StringPrintf("VSync-%d", surface_handle)), 99 : base::Thread(base::StringPrintf("VSync-%d", surface_handle)),
92 callback_(callback), 100 callback_(callback),
93 surface_handle_(surface_handle) { 101 surface_handle_(surface_handle) {
94 HMODULE gdi32 = GetModuleHandle(L"gdi32"); 102 HMODULE gdi32 = GetModuleHandle(L"gdi32");
95 if (!gdi32) { 103 if (!gdi32) {
96 NOTREACHED() << "Can't open gdi32.dll"; 104 NOTREACHED() << "Can't open gdi32.dll";
97 return; 105 return;
98 } 106 }
99 107
(...skipping 13 matching lines...) Expand all
113 121
114 wait_for_vertical_blank_event_ptr_ = 122 wait_for_vertical_blank_event_ptr_ =
115 reinterpret_cast<PFND3DKMTWAITFORVERTICALBLANKEVENT>( 123 reinterpret_cast<PFND3DKMTWAITFORVERTICALBLANKEVENT>(
116 ::GetProcAddress(gdi32, "D3DKMTWaitForVerticalBlankEvent")); 124 ::GetProcAddress(gdi32, "D3DKMTWaitForVerticalBlankEvent"));
117 if (!wait_for_vertical_blank_event_ptr_) { 125 if (!wait_for_vertical_blank_event_ptr_) {
118 NOTREACHED() << "Can't find D3DKMTWaitForVerticalBlankEvent in gdi32.dll"; 126 NOTREACHED() << "Can't find D3DKMTWaitForVerticalBlankEvent in gdi32.dll";
119 return; 127 return;
120 } 128 }
121 } 129 }
122 130
123 GpuVSyncWorker::~GpuVSyncWorker() { 131 GpuVSyncWorker::~GpuVSyncWorker() = default;
132
133 void GpuVSyncWorker::CleanupAndStop() {
124 // Thread::Close() call below will block until this task has finished running 134 // Thread::Close() call below will block until this task has finished running
125 // so it is safe to post it here and pass unretained pointer. 135 // so it is safe to post it here and pass unretained pointer.
126 task_runner()->PostTask(FROM_HERE, base::Bind(&GpuVSyncWorker::CloseAdapter, 136 task_runner()->PostTask(FROM_HERE, base::Bind(&GpuVSyncWorker::CloseAdapter,
127 base::Unretained(this))); 137 base::Unretained(this)));
128 Stop(); 138 Stop();
129 139
130 DCHECK_EQ(0u, current_adapter_handle_); 140 DCHECK_EQ(0u, current_adapter_handle_);
131 DCHECK(current_device_name_.empty()); 141 DCHECK(current_device_name_.empty());
132 } 142 }
133 143
134 void GpuVSyncWorker::Enable(bool enabled) { 144 void GpuVSyncWorker::Enable(bool enabled) {
135 auto was_enabled = base::subtle::NoBarrier_AtomicExchange(&enabled_, enabled); 145 auto was_enabled = base::subtle::NoBarrier_AtomicExchange(&enabled_, enabled);
136 146
137 if (enabled && !was_enabled) 147 if (enabled && !was_enabled)
138 task_runner()->PostTask( 148 task_runner()->PostTask(
139 FROM_HERE, base::Bind(&GpuVSyncWorker::StartRunningVSyncOnThread, 149 FROM_HERE, base::Bind(&GpuVSyncWorker::StartRunningVSyncOnThread,
140 base::Unretained(this))); 150 base::Unretained(this)));
141 } 151 }
142 152
153 bool GpuVSyncWorker::BelongsToWorkerThread() {
154 return base::PlatformThread::CurrentId() == GetThreadId();
155 }
156
143 void GpuVSyncWorker::StartRunningVSyncOnThread() { 157 void GpuVSyncWorker::StartRunningVSyncOnThread() {
144 DCHECK(base::PlatformThread::CurrentId() == GetThreadId()); 158 DCHECK(BelongsToWorkerThread());
145 159
146 if (!running_) { 160 if (!running_) {
147 running_ = true; 161 running_ = true;
148 WaitForVSyncOnThread(); 162 WaitForVSyncOnThread();
149 } 163 }
150 } 164 }
151 165
152 void GpuVSyncWorker::WaitForVSyncOnThread() { 166 void GpuVSyncWorker::WaitForVSyncOnThread() {
153 DCHECK(base::PlatformThread::CurrentId() == GetThreadId()); 167 DCHECK(BelongsToWorkerThread());
154 168
155 TRACE_EVENT0("gpu", "GpuVSyncWorker::WaitForVSyncOnThread"); 169 TRACE_EVENT0("gpu", "GpuVSyncWorker::WaitForVSyncOnThread");
156 170
157 HMONITOR monitor = 171 HMONITOR monitor =
158 MonitorFromWindow(surface_handle_, MONITOR_DEFAULTTONEAREST); 172 MonitorFromWindow(surface_handle_, MONITOR_DEFAULTTONEAREST);
159 MONITORINFOEX monitor_info; 173 MONITORINFOEX monitor_info;
160 monitor_info.cbSize = sizeof(MONITORINFOEX); 174 monitor_info.cbSize = sizeof(MONITORINFOEX);
161 BOOL success = GetMonitorInfo(monitor, &monitor_info); 175 BOOL success = GetMonitorInfo(monitor, &monitor_info);
162 CHECK(success); 176 CHECK(success);
163 177
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 wait_for_vertical_blank_event_data.hAdapter = current_adapter_handle_; 244 wait_for_vertical_blank_event_data.hAdapter = current_adapter_handle_;
231 wait_for_vertical_blank_event_data.hDevice = 0; 245 wait_for_vertical_blank_event_data.hDevice = 0;
232 wait_for_vertical_blank_event_data.VidPnSourceId = current_source_id_; 246 wait_for_vertical_blank_event_data.VidPnSourceId = current_source_id_;
233 247
234 NTSTATUS result = 248 NTSTATUS result =
235 wait_for_vertical_blank_event_ptr_(&wait_for_vertical_blank_event_data); 249 wait_for_vertical_blank_event_ptr_(&wait_for_vertical_blank_event_data);
236 250
237 return result == STATUS_SUCCESS; 251 return result == STATUS_SUCCESS;
238 } 252 }
239 253
240 /* static */ 254 // MessageFilter class for sending and receiving IPC messages
241 std::unique_ptr<GpuVSyncProvider> GpuVSyncProvider::Create( 255 // directly, avoiding routing them through the main GPU thread.
242 const VSyncCallback& callback, 256 class GpuVSyncMessageFilter : public IPC::MessageFilter {
243 SurfaceHandle surface_handle) { 257 public:
244 return std::unique_ptr<GpuVSyncProvider>( 258 explicit GpuVSyncMessageFilter(
245 new GpuVSyncProvider(callback, surface_handle)); 259 const scoped_refptr<GpuVSyncWorker>& vsync_worker,
260 int32_t route_id)
261 : vsync_worker_(vsync_worker), route_id_(route_id) {}
262
263 // IPC::MessageFilter overrides.
264 void OnChannelError() override { Reset(); }
265 void OnChannelClosing() override { Reset(); }
266 void OnFilterAdded(IPC::Channel* channel) override;
267 void OnFilterRemoved() override { Reset(); }
268 bool OnMessageReceived(const IPC::Message& msg) override;
269
270 // Send can be called from GpuVSyncWorker thread.
271 void Send(std::unique_ptr<IPC::Message> message);
272
273 int32_t route_id() const { return route_id_; }
274
275 private:
276 ~GpuVSyncMessageFilter() = default;
277 void SendOnIOThread(std::unique_ptr<IPC::Message> message);
278 void Reset();
279
280 scoped_refptr<GpuVSyncWorker> vsync_worker_;
281 // The sender to which this filter was added.
282 IPC::Sender* sender_ = nullptr;
283 // The sender must be invoked on IO thread.
284 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
285 int32_t route_id_;
286 };
287
288 void GpuVSyncMessageFilter::OnFilterAdded(IPC::Channel* channel) {
289 io_task_runner_ = base::ThreadTaskRunnerHandle::Get();
290 sender_ = channel;
246 } 291 }
247 292
248 GpuVSyncProvider::GpuVSyncProvider(const VSyncCallback& callback, 293 void GpuVSyncMessageFilter::Reset() {
249 SurfaceHandle surface_handle) 294 sender_ = nullptr;
295 vsync_worker_->Enable(false);
296 }
297
298 bool GpuVSyncMessageFilter::OnMessageReceived(const IPC::Message& msg) {
299 if (msg.routing_id() != route_id_)
300 return false;
301
302 IPC_BEGIN_MESSAGE_MAP(GpuVSyncMessageFilter, msg)
303 IPC_MESSAGE_FORWARD(GpuCommandBufferMsg_SetNeedsVSync,
304 vsync_worker_.get(),
305 GpuVSyncWorker::Enable);
306 IPC_MESSAGE_UNHANDLED(return false)
307 IPC_END_MESSAGE_MAP()
308 return true;
309 }
310
311 void GpuVSyncMessageFilter::Send(std::unique_ptr<IPC::Message> message) {
312 CHECK(io_task_runner_->PostTask(
313 FROM_HERE, base::Bind(&GpuVSyncMessageFilter::SendOnIOThread, this,
314 base::Passed(&message))));
315 }
316
317 void GpuVSyncMessageFilter::SendOnIOThread(
318 std::unique_ptr<IPC::Message> message) {
319 DCHECK(io_task_runner_->BelongsToCurrentThread());
320 if (!sender_ || message->is_sync()) {
321 DCHECK(!message->is_sync());
322 return;
323 }
324 sender_->Send(message.release());
325 }
326
327 GpuVSyncProviderWin::GpuVSyncProviderWin(
328 base::WeakPtr<ImageTransportSurfaceDelegate> delegate,
329 SurfaceHandle surface_handle)
330 : vsync_interval_provider_(new gl::VSyncProviderWin(surface_handle)) {
331 vsync_worker_ = new GpuVSyncWorker(
332 base::Bind(&GpuVSyncProviderWin::OnVSync, base::Unretained(this)),
333 surface_handle);
334 message_filter_ = new GpuVSyncMessageFilter(
335 vsync_worker_, delegate->GetRouteID());
336 delegate->AddFilter(message_filter_.get());
337
338 // Start the thread.
339 base::Thread::Options options;
340 // TODO(stanisc): might consider even higher priority - REALTIME_AUDIO.
341 options.priority = base::ThreadPriority::DISPLAY;
342 vsync_worker_->StartWithOptions(options);
343 }
344
345 GpuVSyncProviderWin::~GpuVSyncProviderWin() {
346 vsync_worker_->CleanupAndStop();
347 }
348
349 void GpuVSyncProviderWin::GetVSyncParameters(
350 const UpdateVSyncCallback& callback) {
351 // Note that |callback| is never called back. Instead GetVSyncParameters is
352 // routed to an internal handler where VSync interval is stored and used later
353 // with GpuCommandBufferMsg_UpdateVSyncParameters message posted from the
354 // worker thread.
355 vsync_interval_provider_->GetVSyncParameters(
356 base::Bind(&GpuVSyncProviderWin::OnVSyncParametersUpdated,
357 base::Unretained(this)));
358 }
359
360 void GpuVSyncProviderWin::OnVSync(base::TimeTicks timestamp) {
361 DCHECK(vsync_worker_->BelongsToWorkerThread());
362 base::TimeDelta interval;
363
364 {
365 base::AutoLock lock(vsync_interval_lock_);
366 interval = vsync_interval_;
367 }
368
369 message_filter_->Send(
370 std::unique_ptr<IPC::Message>(
371 new GpuCommandBufferMsg_UpdateVSyncParameters(
372 message_filter_->route_id(), timestamp, interval)));
373 }
374
375 void GpuVSyncProviderWin::OnVSyncParametersUpdated(base::TimeTicks timestamp,
376 base::TimeDelta interval) {
377 base::AutoLock lock(vsync_interval_lock_);
378 vsync_interval_ = interval;
379 }
380
381 GpuVSyncProviderForTest::GpuVSyncProviderForTest(const VSyncCallback& callback,
382 SurfaceHandle surface_handle)
250 : vsync_worker_(new GpuVSyncWorker(callback, surface_handle)) { 383 : vsync_worker_(new GpuVSyncWorker(callback, surface_handle)) {
251 // Start the thread. 384 // Start the thread.
252 base::Thread::Options options; 385 base::Thread::Options options;
253 // TODO(stanisc): might consider even higher priority - REALTIME_AUDIO. 386 // TODO(stanisc): might consider even higher priority - REALTIME_AUDIO.
254 options.priority = base::ThreadPriority::DISPLAY; 387 options.priority = base::ThreadPriority::DISPLAY;
255 vsync_worker_->StartWithOptions(options); 388 vsync_worker_->StartWithOptions(options);
256 } 389 }
257 390
258 GpuVSyncProvider::~GpuVSyncProvider() = default; 391 GpuVSyncProviderForTest::~GpuVSyncProviderForTest() {
392 vsync_worker_->CleanupAndStop();
393 }
259 394
260 void GpuVSyncProvider::EnableVSync(bool enabled) { 395 void GpuVSyncProviderForTest::SetNeedsVSync(bool needs_vsync) {
261 vsync_worker_->Enable(enabled); 396 vsync_worker_->Enable(needs_vsync);
262 } 397 }
263 398
264 } // namespace gpu 399 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698