1 // Copyright 2017 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 "remoting/host/win/evaluate_d3d.h"
6 
7 #include <D3DCommon.h>
8 
9 #include <iostream>
10 
11 #include "base/logging.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "remoting/host/evaluate_capability.h"
15 #include "remoting/host/host_exit_codes.h"
16 #include "remoting/host/switches.h"
17 #include "remoting/host/win/evaluate_3d_display_mode.h"
18 #include "third_party/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h"
19 #include "third_party/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h"
20 
21 namespace remoting {
22 
23 namespace {
24 
25 constexpr char kNoDirectXCapturer[] = "No-DirectX-Capturer";
26 
27 }  // namespace
28 
EvaluateD3D()29 int EvaluateD3D() {
30   // Creates a capturer instance to avoid the DxgiDuplicatorController to be
31   // initialized and deinitialized for each static call to
32   // webrtc::ScreenCapturerWinDirectx below.
33   webrtc::ScreenCapturerWinDirectx capturer;
34 
35   if (webrtc::ScreenCapturerWinDirectx::IsSupported()) {
36     // Guaranteed to work.
37     // This string is also hard-coded in host_attributes_unittests.cc.
38     std::cout << "DirectX-Capturer" << std::endl;
39   } else if (webrtc::ScreenCapturerWinDirectx::IsCurrentSessionSupported()) {
40     // If we are in a supported session, but DirectX capturer is not able to be
41     // initialized. Something must be wrong, we should actively disable it.
42     std::cout << kNoDirectXCapturer << std::endl;
43   }
44 
45   webrtc::DxgiDuplicatorController::D3dInfo info;
46   webrtc::ScreenCapturerWinDirectx::RetrieveD3dInfo(&info);
47   if (info.min_feature_level < D3D_FEATURE_LEVEL_10_0) {
48     std::cout << "MinD3DLT10" << std::endl;
49   } else {
50     std::cout << "MinD3DGE10" << std::endl;
51   }
52   if (info.min_feature_level >= D3D_FEATURE_LEVEL_11_0) {
53     std::cout << "MinD3DGE11" << std::endl;
54   }
55   if (info.min_feature_level >= D3D_FEATURE_LEVEL_12_0) {
56     std::cout << "MinD3DGE12" << std::endl;
57   }
58 
59   return kSuccessExitCode;
60 }
61 
BlockD3DCheck()62 bool BlockD3DCheck() {
63   DWORD console_session = WTSGetActiveConsoleSessionId();
64   DWORD current_session = 0;
65   if (!ProcessIdToSessionId(GetCurrentProcessId(), &current_session)) {
66     PLOG(WARNING) << "ProcessIdToSessionId failed: ";
67   }
68 
69   // Session 0 is not curtained as it does not have an interactive desktop.
70   bool is_curtained_session =
71       current_session != 0 && current_session != console_session;
72 
73   // Skip D3D checks if we are in a curtained session and 3D Display mode is
74   // enabled.  Attempting to create a D3D device in this scenario takes a long
75   // time which often results in the user being disconnected due to timeouts.
76   // After digging in, it looks like the call to D3D11CreateDevice() is spinning
77   // while enumerating the display drivers.  There isn't a simple fix for this
78   // so instead we should skip the D3D caps check and any other D3D related
79   // calls.  This will mean falling back to the GDI capturer.
80   return is_curtained_session && Get3dDisplayModeEnabled();
81 }
82 
GetD3DCapabilities(std::vector<std::string> * result)83 bool GetD3DCapabilities(std::vector<std::string>* result) {
84   if (BlockD3DCheck()) {
85     result->push_back(kNoDirectXCapturer);
86     return false;
87   }
88 
89   std::string d3d_info;
90   if (EvaluateCapability(kEvaluateD3D, &d3d_info) != kSuccessExitCode) {
91     result->push_back(kNoDirectXCapturer);
92     return false;
93   }
94 
95   auto capabilities =
96       base::SplitString(d3d_info, base::kWhitespaceASCII, base::TRIM_WHITESPACE,
97                         base::SPLIT_WANT_NONEMPTY);
98   for (const auto& capability : capabilities) {
99     result->push_back(capability);
100   }
101 
102   return true;
103 }
104 
IsD3DAvailable()105 bool IsD3DAvailable() {
106   if (BlockD3DCheck())
107     return false;
108 
109   std::string unused;
110   return (EvaluateCapability(kEvaluateD3D, &unused) == kSuccessExitCode);
111 }
112 
113 }  // namespace remoting
114