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
17namespace gpu {
18
19namespace {
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.
24void 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
94bool 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