summaryrefslogtreecommitdiffstats
path: root/src/detection/gpu/gpu_windows.cpp
blob: ae6f00ef972363d38e68580ec3d8ec786faf9c3b (plain) (blame)
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
extern "C" {
#include "gpu.h"
#include "common/library.h"
#include "common/debug.h"
}

#if __has_include(<directx/dxcore.h>) && __has_include(<dxguids/dxguids.h>)

    #include <directx/dxcore.h>
    #include <dxguids/dxguids.h>
    #include "common/windows/util.hpp"

static IDXCoreAdapterFactory* loadDxCoreFactory() {
    static bool initialized = false;
    static IDXCoreAdapterFactory* factory = nullptr;
    if (initialized) {
        return factory; // Already loaded
    }

    initialized = true;
    FF_LIBRARY_LOAD(dxcore, NULL, "dxcore" FF_LIBRARY_EXTENSION, 1)

    // DXCoreCreateAdapterFactory is a reloaded function, so we can't use FF_LIBRARY_LOAD_SYMBOL_MESSAGE here
    typedef HRESULT (*DXCoreCreateAdapterFactory_t)(REFIID riid, void** ppvFactory);

    #ifndef FF_DISABLE_DLOPEN
    auto ffDXCoreCreateAdapterFactory = (DXCoreCreateAdapterFactory_t) dlsym(dxcore, "DXCoreCreateAdapterFactory");
    if (ffDXCoreCreateAdapterFactory == nullptr) {
        return NULL;
    }
    #else
    auto ffDXCoreCreateAdapterFactory = (DXCoreCreateAdapterFactory_t) DXCoreCreateAdapterFactory;
    #endif

    HRESULT hr = ffDXCoreCreateAdapterFactory(IID_PPV_ARGS(&factory));
    if (FAILED(hr)) {
        FF_DEBUG("DXCoreCreateAdapterFactory failed with HRESULT: 0x%08lX (%s)", hr, ffDebugHResult(hr));
        return NULL;
    }

    dxcore = NULL; // Don't unload
    return factory;
}

extern "C" const char* ffGPUDetectTypeWithDXCore(LUID adapterLuid, FFGPUResult* gpu) {
    auto* factory = loadDxCoreFactory();
    if (!factory) {
        return "Failed to load DXCore library or create adapter factory";
    }

    IDXCoreAdapter* adapter = nullptr;
    HRESULT hr = factory->GetAdapterByLuid(adapterLuid, IID_PPV_ARGS(&adapter));
    if (FAILED(hr)) {
        FF_DEBUG("GetAdapterByLuid failed with HRESULT: 0x%08lX (%s)", hr, ffDebugHResult(hr));
        return "Failed to get adapter by LUID";
    }

    on_scope_exit releaseAdapter{ [adapter] { adapter->Release(); } };

    bool isIntegrated = false;
    hr = adapter->GetProperty(DXCoreAdapterProperty::IsIntegrated, sizeof(isIntegrated), &isIntegrated);
    if (FAILED(hr)) {
        FF_DEBUG("GetProperty(IsIntegrated) failed with HRESULT: 0x%08lX (%s)", hr, ffDebugHResult(hr));
        return "Failed to get adapter properties";
    }

    gpu->type = isIntegrated ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
    FF_DEBUG("GPU type determined using DXCore: %s", isIntegrated ? "Integrated" : "Discrete");

    return nullptr;
}

#else

    #warning "DXCore headers not available, GPU type detection may be less accurate"

extern "C" const char* ffGPUDetectTypeWithDXCore(LUID adapterLuid, FFGPUResult* gpu) {
    FF_UNUSED(adapterLuid, gpu);
    FF_DEBUG("DXCore not available, skipping GPU type detection with DXCore");
    return "DXCore not available";
}

#endif