• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 // Functions to enumerate the Dx Diagnostic Tool hierarchy and build up
6 // a tree of nodes with name / value properties.
7 
8 #define INITGUID
9 #include <dxdiag.h>
10 #include <windows.h>
11 
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/win/scoped_com_initializer.h"
15 #include "gpu/config/gpu_info_collector.h"
16 
17 namespace gpu {
18 
19 namespace {
20 
21 // Traverses the IDxDiagContainer tree and populates a tree of DxDiagNode
22 // structures that contains property name / value pairs and subtrees of DirectX
23 // diagnostic information.
RecurseDiagnosticTree(DxDiagNode * output,IDxDiagContainer * container,int depth)24 void RecurseDiagnosticTree(DxDiagNode* output,
25                            IDxDiagContainer* container,
26                            int depth) {
27   HRESULT hr;
28 
29   VARIANT variant;
30   VariantInit(&variant);
31 
32   DWORD prop_count;
33   hr = container->GetNumberOfProps(&prop_count);
34   if (SUCCEEDED(hr)) {
35     for (DWORD i = 0; i < prop_count; i++) {
36       WCHAR prop_name16[256];
37       hr = container->EnumPropNames(i, prop_name16, arraysize(prop_name16));
38       if (SUCCEEDED(hr)) {
39         std::string prop_name8 = base::WideToUTF8(prop_name16);
40 
41         hr = container->GetProp(prop_name16, &variant);
42         if (SUCCEEDED(hr)) {
43           switch (variant.vt) {
44             case VT_UI4:
45               output->values[prop_name8] = base::UintToString(variant.ulVal);
46               break;
47             case VT_I4:
48               output->values[prop_name8] = base::IntToString(variant.lVal);
49               break;
50             case VT_BOOL:
51               output->values[prop_name8] = variant.boolVal ? "true" : "false";
52               break;
53             case VT_BSTR:
54               output->values[prop_name8] = base::WideToUTF8(variant.bstrVal);
55               break;
56             default:
57               break;
58           }
59 
60           // Clear the variant (this is needed to free BSTR memory).
61           VariantClear(&variant);
62         }
63       }
64     }
65   }
66 
67   if (depth > 0) {
68     DWORD child_count;
69     hr = container->GetNumberOfChildContainers(&child_count);
70     if (SUCCEEDED(hr)) {
71       for (DWORD i = 0; i < child_count; i++) {
72         WCHAR child_name16[256];
73         hr = container->EnumChildContainerNames(i,
74                                                 child_name16,
75                                                 arraysize(child_name16));
76         if (SUCCEEDED(hr)) {
77           std::string child_name8 = base::WideToUTF8(child_name16);
78           DxDiagNode* output_child = &output->children[child_name8];
79 
80           IDxDiagContainer* child_container = NULL;
81           hr = container->GetChildContainer(child_name16, &child_container);
82           if (SUCCEEDED(hr)) {
83             RecurseDiagnosticTree(output_child, child_container, depth - 1);
84 
85             child_container->Release();
86           }
87         }
88       }
89     }
90   }
91 }
92 }  // namespace anonymous
93 
GetDxDiagnostics(DxDiagNode * output)94 bool GetDxDiagnostics(DxDiagNode* output) {
95   HRESULT hr;
96   bool success = false;
97   base::win::ScopedCOMInitializer com_initializer;
98 
99   IDxDiagProvider* provider = NULL;
100   hr = CoCreateInstance(CLSID_DxDiagProvider,
101                          NULL,
102                          CLSCTX_INPROC_SERVER,
103                          IID_IDxDiagProvider,
104                          reinterpret_cast<void**>(&provider));
105   if (SUCCEEDED(hr)) {
106     DXDIAG_INIT_PARAMS params = { sizeof(params) };
107     params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
108     params.bAllowWHQLChecks = FALSE;
109     params.pReserved = NULL;
110 
111     hr = provider->Initialize(&params);
112     if (SUCCEEDED(hr)) {
113       IDxDiagContainer* root = NULL;
114       hr = provider->GetRootContainer(&root);
115       if (SUCCEEDED(hr)) {
116         // Limit to the DisplayDevices subtree. The tree in its entirity is
117         // enormous and only this branch contains useful information.
118         IDxDiagContainer* display_devices = NULL;
119         hr = root->GetChildContainer(L"DxDiag_DisplayDevices",
120                                      &display_devices);
121         if (SUCCEEDED(hr)) {
122           RecurseDiagnosticTree(output, display_devices, 1);
123           success = true;
124           display_devices->Release();
125         }
126 
127         root->Release();
128       }
129     }
130     provider->Release();
131   }
132 
133   return success;
134 }
135 }  // namespace gpu
136