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

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

Issue 2596123002: GpuVSyncProvider with unit test (Closed)
Patch Set: Fixed win_clang build error Created 3 years, 11 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 | « gpu/ipc/service/gpu_vsync_provider_unittest_win.cc ('k') | 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "gpu/ipc/service/gpu_vsync_provider.h"
6
7 #include "base/atomicops.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/threading/thread.h"
10 #include "base/trace_event/trace_event.h"
11
12 #include <windows.h>
13
14 namespace gpu {
15
16 namespace {
17 // from <D3dkmthk.h>
18 typedef LONG NTSTATUS;
19 typedef UINT D3DKMT_HANDLE;
20 typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;
21
22 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
23
24 typedef struct _D3DKMT_OPENADAPTERFROMHDC {
25 HDC hDc;
26 D3DKMT_HANDLE hAdapter;
27 LUID AdapterLuid;
28 D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
29 } D3DKMT_OPENADAPTERFROMHDC;
30
31 typedef struct _D3DKMT_CLOSEADAPTER {
32 D3DKMT_HANDLE hAdapter;
33 } D3DKMT_CLOSEADAPTER;
34
35 typedef struct _D3DKMT_WAITFORVERTICALBLANKEVENT {
36 D3DKMT_HANDLE hAdapter;
37 D3DKMT_HANDLE hDevice;
38 D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
39 } D3DKMT_WAITFORVERTICALBLANKEVENT;
40
41 typedef NTSTATUS(APIENTRY* PFND3DKMTOPENADAPTERFROMHDC)(
42 D3DKMT_OPENADAPTERFROMHDC*);
43 typedef NTSTATUS(APIENTRY* PFND3DKMTCLOSEADAPTER)(D3DKMT_CLOSEADAPTER*);
44 typedef NTSTATUS(APIENTRY* PFND3DKMTWAITFORVERTICALBLANKEVENT)(
45 D3DKMT_WAITFORVERTICALBLANKEVENT*);
46 } // namespace
47
48 // The actual implementation of background tasks plus any state that might be
49 // needed on the worker thread.
50 class GpuVSyncWorker : public base::Thread {
51 public:
52 GpuVSyncWorker(const GpuVSyncProvider::VSyncCallback& callback,
53 SurfaceHandle surface_handle);
54 ~GpuVSyncWorker() override;
55
56 void Enable(bool enabled);
57 void StartRunningVSyncOnThread();
58 void WaitForVSyncOnThread();
59 void SendVSyncUpdate(base::TimeTicks timestamp);
60 void Reschedule();
61
62 private:
63 // Specifies whether background tasks are running.
64 // This can be set on background thread only.
65 bool running_ = false;
66
67 // Specified whether the worker is enabled. This is accessed from both
68 // threads but can be changed on the main thread only.
69 base::subtle::AtomicWord enabled_ = false;
70
71 const GpuVSyncProvider::VSyncCallback callback_;
72 const SurfaceHandle surface_handle_;
73
74 PFND3DKMTOPENADAPTERFROMHDC open_adapter_from_hdc_ptr_;
75 PFND3DKMTCLOSEADAPTER close_adapter_ptr_;
76 PFND3DKMTWAITFORVERTICALBLANKEVENT wait_for_vertical_blank_event_ptr_;
77 };
78
79 GpuVSyncWorker::GpuVSyncWorker(const GpuVSyncProvider::VSyncCallback& callback,
80 SurfaceHandle surface_handle)
81 : base::Thread(base::StringPrintf("VSync-%d", surface_handle)),
82 callback_(callback),
83 surface_handle_(surface_handle) {
84 HMODULE gdi32 = GetModuleHandle(L"gdi32");
85 if (!gdi32) {
86 NOTREACHED() << "Can't open gdi32.dll";
87 return;
88 }
89
90 open_adapter_from_hdc_ptr_ = reinterpret_cast<PFND3DKMTOPENADAPTERFROMHDC>(
91 ::GetProcAddress(gdi32, "D3DKMTOpenAdapterFromHdc"));
92 if (!open_adapter_from_hdc_ptr_) {
93 NOTREACHED() << "Can't find D3DKMTOpenAdapterFromHdc in gdi32.dll";
94 return;
95 }
96
97 close_adapter_ptr_ = reinterpret_cast<PFND3DKMTCLOSEADAPTER>(
98 ::GetProcAddress(gdi32, "D3DKMTCloseAdapter"));
99 if (!close_adapter_ptr_) {
100 NOTREACHED() << "Can't find D3DKMTCloseAdapter in gdi32.dll";
101 return;
102 }
103
104 wait_for_vertical_blank_event_ptr_ =
105 reinterpret_cast<PFND3DKMTWAITFORVERTICALBLANKEVENT>(
106 ::GetProcAddress(gdi32, "D3DKMTWaitForVerticalBlankEvent"));
107 if (!wait_for_vertical_blank_event_ptr_) {
108 NOTREACHED() << "Can't find D3DKMTWaitForVerticalBlankEvent in gdi32.dll";
109 return;
110 }
111 }
112
113 GpuVSyncWorker::~GpuVSyncWorker() {
114 Stop();
115 }
116
117 void GpuVSyncWorker::Enable(bool enabled) {
118 auto was_enabled = base::subtle::NoBarrier_AtomicExchange(&enabled_, enabled);
119
120 if (enabled && !was_enabled)
121 task_runner()->PostTask(
122 FROM_HERE, base::Bind(&GpuVSyncWorker::StartRunningVSyncOnThread,
123 base::Unretained(this)));
124 }
125
126 void GpuVSyncWorker::StartRunningVSyncOnThread() {
127 DCHECK(base::PlatformThread::CurrentId() == GetThreadId());
128
129 if (!running_) {
130 running_ = true;
131 WaitForVSyncOnThread();
132 }
133 }
134
135 void GpuVSyncWorker::WaitForVSyncOnThread() {
136 DCHECK(base::PlatformThread::CurrentId() == GetThreadId());
137
138 TRACE_EVENT0("gpu", "GpuVSyncWorker::WaitForVSyncOnThread");
139
140 HMONITOR monitor =
141 MonitorFromWindow(surface_handle_, MONITOR_DEFAULTTONEAREST);
142 MONITORINFOEX monitor_info;
143 monitor_info.cbSize = sizeof(MONITORINFOEX);
144 BOOL success = GetMonitorInfo(monitor, &monitor_info);
145 CHECK(success);
146
147 HDC hdc = CreateDC(NULL, monitor_info.szDevice, NULL, NULL);
148
149 D3DKMT_OPENADAPTERFROMHDC open_adapter_data;
150 open_adapter_data.hDc = hdc;
151
152 NTSTATUS result = open_adapter_from_hdc_ptr_(&open_adapter_data);
jbauman 2017/01/06 03:25:50 I guess we'll see how the performance of this look
stanisc 2017/01/06 21:35:51 I did some tracing and this didn't look like a not
brucedawson 2017/01/06 21:43:52 Maybe do some timing measurements on a few machine
153 DeleteDC(hdc);
154
155 CHECK(result == STATUS_SUCCESS);
156
157 D3DKMT_WAITFORVERTICALBLANKEVENT wait_for_vertical_blank_event_data;
158 wait_for_vertical_blank_event_data.hAdapter = open_adapter_data.hAdapter;
159 wait_for_vertical_blank_event_data.hDevice = 0;
160 wait_for_vertical_blank_event_data.VidPnSourceId =
161 open_adapter_data.VidPnSourceId;
162
163 result =
164 wait_for_vertical_blank_event_ptr_(&wait_for_vertical_blank_event_data);
165 if (result == STATUS_SUCCESS) {
166 // Note: this sends update on background thread which the callback is
167 // expected to handle.
168 SendVSyncUpdate(base::TimeTicks::Now());
169 }
170
171 D3DKMT_CLOSEADAPTER close_adapter_data;
172 close_adapter_data.hAdapter = open_adapter_data.hAdapter;
173
174 result = close_adapter_ptr_(&close_adapter_data);
175 CHECK(result == STATUS_SUCCESS);
176
177 Reschedule();
178 }
179
180 void GpuVSyncWorker::SendVSyncUpdate(base::TimeTicks timestamp) {
181 if (base::subtle::NoBarrier_Load(&enabled_)) {
182 TRACE_EVENT0("gpu", "GpuVSyncWorker::SendVSyncUpdate");
183 callback_.Run(timestamp);
184 }
185 }
186
187 void GpuVSyncWorker::Reschedule() {
188 // Restart the task if still enabled.
189 if (base::subtle::NoBarrier_Load(&enabled_)) {
190 task_runner()->PostTask(FROM_HERE,
191 base::Bind(&GpuVSyncWorker::WaitForVSyncOnThread,
192 base::Unretained(this)));
193 } else {
194 running_ = false;
195 }
196 }
197
198 /* static */
199 std::unique_ptr<GpuVSyncProvider> GpuVSyncProvider::Create(
200 const VSyncCallback& callback,
201 SurfaceHandle surface_handle) {
202 return std::unique_ptr<GpuVSyncProvider>(
203 new GpuVSyncProvider(callback, surface_handle));
204 }
205
206 GpuVSyncProvider::GpuVSyncProvider(const VSyncCallback& callback,
207 SurfaceHandle surface_handle)
208 : vsync_worker_(new GpuVSyncWorker(callback, surface_handle)) {
209 // Start the thread.
210 base::Thread::Options options;
211 // TODO(stanisc): might consider even higher priority - REALTIME_AUDIO.
212 options.priority = base::ThreadPriority::DISPLAY;
213 vsync_worker_->StartWithOptions(options);
214 }
215
216 GpuVSyncProvider::~GpuVSyncProvider() = default;
217
218 void GpuVSyncProvider::EnableVSync(bool enabled) {
219 vsync_worker_->Enable(enabled);
220 }
221
222 } // namespace gpu
OLDNEW
« no previous file with comments | « gpu/ipc/service/gpu_vsync_provider_unittest_win.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698