summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/gpu_info_util/SystemInfo_win.cpp
blob: 291acc1ef0a8c52a99915b925c3e19785550d5bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//
// Copyright 2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// SystemInfo_win.cpp: implementation of the Windows-specific parts of SystemInfo.h

#include "gpu_info_util/SystemInfo_internal.h"

#include "common/debug.h"
#include "common/string_utils.h"

// Windows.h needs to be included first
#include <windows.h>

#include <dxgi.h>

#include <array>
#include <sstream>

namespace angle
{

namespace
{

bool GetDevicesFromDXGI(std::vector<GPUDeviceInfo> *devices)
{
#if defined(ANGLE_ENABLE_WINDOWS_UWP)
    IDXGIFactory1 *factory;
    if (!SUCCEEDED(
            CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void **>(&factory))))
    {
        return false;
    }
#else
    IDXGIFactory *factory;
    if (!SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&factory))))
    {
        return false;
    }
#endif

    UINT i                = 0;
    IDXGIAdapter *adapter = nullptr;
    while (factory->EnumAdapters(i++, &adapter) != DXGI_ERROR_NOT_FOUND)
    {
        DXGI_ADAPTER_DESC desc;
        adapter->GetDesc(&desc);

        LARGE_INTEGER umdVersion;
        if (adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &umdVersion) ==
            DXGI_ERROR_UNSUPPORTED)
        {
            adapter->Release();
            continue;
        }

        // The UMD driver version here is the same as in the registry except for the last number.
        uint64_t intVersion = umdVersion.QuadPart;
        std::ostringstream o;

        constexpr uint64_t kMask16 = std::numeric_limits<uint16_t>::max();
        o << ((intVersion >> 48) & kMask16) << ".";
        o << ((intVersion >> 32) & kMask16) << ".";
        o << ((intVersion >> 16) & kMask16) << ".";
        o << (intVersion & kMask16);

        GPUDeviceInfo device;
        device.vendorId      = desc.VendorId;
        device.deviceId      = desc.DeviceId;
        device.driverVersion = o.str();
        device.systemDeviceId =
            GetSystemDeviceIdFromParts(desc.AdapterLuid.HighPart, desc.AdapterLuid.LowPart);

        devices->push_back(device);

        adapter->Release();
    }

    factory->Release();

    return (i > 0);
}

}  // anonymous namespace

bool GetSystemInfo(SystemInfo *info)
{
    if (!GetDevicesFromDXGI(&info->gpus))
    {
        return false;
    }

    if (info->gpus.size() == 0)
    {
        return false;
    }

    // Call GetDualGPUInfo to populate activeGPUIndex, isOptimus, and isAMDSwitchable.
    GetDualGPUInfo(info);

    // Override activeGPUIndex. The first index returned by EnumAdapters is the active GPU. We
    // can override the heuristic to find the active GPU
    info->activeGPUIndex = 0;

#if !defined(ANGLE_ENABLE_WINDOWS_UWP)
    // Override isOptimus. nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
    HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
    info->isOptimus    = nvd3d9wrap != nullptr;
#endif

    return true;
}

}  // namespace angle