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

Unified Diff: gpu/ipc/service/gpu_vsync_provider_win.cc

Issue 2596123002: GpuVSyncProvider with unit test (Closed)
Patch Set: Fixed build failure on posix. Created 4 years 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 side-by-side diff with in-line comments
Download patch
Index: gpu/ipc/service/gpu_vsync_provider_win.cc
diff --git a/gpu/ipc/service/gpu_vsync_provider_win.cc b/gpu/ipc/service/gpu_vsync_provider_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..973ae9cf1f29614887e4b9578f9007752879a155
--- /dev/null
+++ b/gpu/ipc/service/gpu_vsync_provider_win.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/ipc/service/gpu_vsync_provider.h"
+
+#include "base/bind.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+
+#include <windows.h>
+
+namespace gpu {
+
+namespace {
+// from <D3dkmthk.h>
+typedef LONG NTSTATUS;
+typedef UINT D3DKMT_HANDLE;
+typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;
+
+#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
+
+typedef struct _D3DKMT_OPENADAPTERFROMHDC {
+ HDC hDc;
+ D3DKMT_HANDLE hAdapter;
+ LUID AdapterLuid;
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
+} D3DKMT_OPENADAPTERFROMHDC;
+
+typedef struct _D3DKMT_CLOSEADAPTER {
+ D3DKMT_HANDLE hAdapter;
+} D3DKMT_CLOSEADAPTER;
+
+typedef struct _D3DKMT_WAITFORVERTICALBLANKEVENT {
+ D3DKMT_HANDLE hAdapter;
+ D3DKMT_HANDLE hDevice;
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
+} D3DKMT_WAITFORVERTICALBLANKEVENT;
+
+typedef NTSTATUS(APIENTRY* PFND3DKMTOPENADAPTERFROMHDC)(
+ D3DKMT_OPENADAPTERFROMHDC*);
+typedef NTSTATUS(APIENTRY* PFND3DKMTCLOSEADAPTER)(D3DKMT_CLOSEADAPTER*);
+typedef NTSTATUS(APIENTRY* PFND3DKMTWAITFORVERTICALBLANKEVENT)(
+ D3DKMT_WAITFORVERTICALBLANKEVENT*);
+} // namespace
+
+/* static */
+std::unique_ptr<GpuVSyncProvider> GpuVSyncProvider::Create(
+ const VSyncCallback& callback,
+ SurfaceHandle surface_handle) {
+ std::unique_ptr<GpuVSyncProvider> provider(
+ new GpuVSyncProvider(callback, surface_handle));
+ // Start the thread.
+ base::Thread::Options options;
+ // TODO(stanisc): might consider even higher priority - REALTIME_AUDIO.
+ options.priority = base::ThreadPriority::DISPLAY;
+ provider->StartWithOptions(options);
+ return provider;
+}
+
+GpuVSyncProvider::GpuVSyncProvider(const VSyncCallback& callback,
+ SurfaceHandle surface_handle)
+ : base::Thread(base::StringPrintf("VSync-%d", surface_handle)),
+ callback_(callback),
+ surface_handle_(surface_handle) {}
+
+GpuVSyncProvider::~GpuVSyncProvider() {
+ Stop();
+}
+
+void GpuVSyncProvider::EnableVSync(bool enabled) {
+ if (enabled_ == enabled)
+ return;
+
+ enabled_ = enabled;
+
+ if (enabled_)
+ task_runner()->PostTask(
+ FROM_HERE, base::Bind(&GpuVSyncProvider::StartRunningVSyncOnThread,
+ base::Unretained(this)));
+}
+
+void GpuVSyncProvider::StartRunningVSyncOnThread() {
+ DCHECK(base::PlatformThread::CurrentId() == GetThreadId());
+
+ if (!running_) {
+ running_ = true;
+ WaitForVSyncOnThread();
+ }
+}
+
+void GpuVSyncProvider::WaitForVSyncOnThread() {
brucedawson 2016/12/22 21:49:16 Do we really want this to do the whole init/de-ini
stanisc 2016/12/22 22:59:31 One reason I've done it this way is because I want
stanisc 2017/01/04 22:33:04 OK. Cached function pointers, but keep opening/clo
+ DCHECK(base::PlatformThread::CurrentId() == GetThreadId());
+
+ TRACE_EVENT0("gpu", "GpuVSyncProvider::WaitForVSyncOnThread");
+
+ // TODO: implement this
brucedawson 2016/12/22 21:49:16 I don't understand this comment.
stanisc 2016/12/22 22:59:31 Forgot to remove this one. Will remove it in the n
stanisc 2017/01/04 22:33:04 Done.
+ HMODULE gdi32 = GetModuleHandle(L"gdi32");
+ if (!gdi32) {
+ NOTREACHED() << "Can't open gdi32.dll";
+ return;
+ }
+
+ auto open_adapter_from_hdc_ptr =
+ reinterpret_cast<PFND3DKMTOPENADAPTERFROMHDC>(
+ ::GetProcAddress(gdi32, "D3DKMTOpenAdapterFromHdc"));
+ if (!open_adapter_from_hdc_ptr) {
+ NOTREACHED() << "Can't find D3DKMTOpenAdapterFromHdc in gdi32.dll";
+ return;
+ }
+
+ auto close_adapter_ptr = reinterpret_cast<PFND3DKMTCLOSEADAPTER>(
+ ::GetProcAddress(gdi32, "D3DKMTCloseAdapter"));
+ if (!close_adapter_ptr) {
+ NOTREACHED() << "Can't find D3DKMTCloseAdapter in gdi32.dll";
+ return;
+ }
+
+ auto wait_for_vertical_blank_event_ptr =
+ reinterpret_cast<PFND3DKMTWAITFORVERTICALBLANKEVENT>(
+ ::GetProcAddress(gdi32, "D3DKMTWaitForVerticalBlankEvent"));
+ if (!wait_for_vertical_blank_event_ptr) {
+ NOTREACHED() << "Can't find D3DKMTWaitForVerticalBlankEvent in gdi32.dll";
+ return;
+ }
+
+ HMONITOR monitor =
+ MonitorFromWindow(surface_handle_, MONITOR_DEFAULTTONEAREST);
+ MONITORINFOEX monitor_info;
+ monitor_info.cbSize = sizeof(MONITORINFOEX);
+ BOOL success = GetMonitorInfo(monitor, &monitor_info);
+ CHECK(success);
+
+ HDC hdc = CreateDC(NULL, monitor_info.szDevice, NULL, NULL);
+
+ D3DKMT_OPENADAPTERFROMHDC open_adapter_data;
+ open_adapter_data.hDc = hdc;
+
+ NTSTATUS result = open_adapter_from_hdc_ptr(&open_adapter_data);
+ DeleteDC(hdc);
+
+ CHECK(result == STATUS_SUCCESS);
+
+ D3DKMT_WAITFORVERTICALBLANKEVENT wait_for_vertical_blank_event_data;
+ wait_for_vertical_blank_event_data.hAdapter = open_adapter_data.hAdapter;
+ wait_for_vertical_blank_event_data.hDevice = 0;
+ wait_for_vertical_blank_event_data.VidPnSourceId =
+ open_adapter_data.VidPnSourceId;
+
+ result =
+ wait_for_vertical_blank_event_ptr(&wait_for_vertical_blank_event_data);
+ if (result == STATUS_SUCCESS) {
+ // Note: this sends update from the background thread.
+ SendVSyncUpdate(base::TimeTicks::Now());
+ }
+
+ D3DKMT_CLOSEADAPTER close_adapter_data;
+ close_adapter_data.hAdapter = open_adapter_data.hAdapter;
+
+ result = close_adapter_ptr(&close_adapter_data);
+ CHECK(result == STATUS_SUCCESS);
+
+ // Restart the task if still enabled.
+ if (enabled_) {
+ task_runner()->PostTask(FROM_HERE,
+ base::Bind(&GpuVSyncProvider::WaitForVSyncOnThread,
+ base::Unretained(this)));
+ } else {
+ running_ = false;
+ }
+}
+
+void GpuVSyncProvider::SendVSyncUpdate(base::TimeTicks now) {
+ TRACE_EVENT0("gpu", "GpuVSyncProvider::SendVSync");
stanisc 2016/12/22 21:35:08 Need to change this to SendVSyncUpdate
+ if (enabled_) {
+ callback_.Run(now);
+ }
+}
+
+} // namespace gpu

Powered by Google App Engine
This is Rietveld 408576698