0

我在使用 DirectX API 检测某些显卡时遇到问题。我编写的代码如下所示:

#define _WIN32_DCOM

#include <iostream>
#include <Windows.h>
#include <d3d11.h>
#include <Dxgi1_6.h>
#include <atlbase.h>
#include <string>
#include <vector>
#include <comdef.h>
#include <Wbemidl.h>

struct AdapterInfo
{
    std::wstring description;
    size_t vRam;
    D3D_FEATURE_LEVEL maxFeatureLevel;
};

void getGPUDescriptionVideoRam(IUnknown* pDevice, AdapterInfo & adapterInfo)
{
    CComPtr<IDXGIDevice> pDXGIDevice;
    pDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDXGIDevice);

    if (pDXGIDevice)
    {
        CComPtr<IDXGIAdapter> pDXGIAdapter;
        pDXGIDevice->GetAdapter(&pDXGIAdapter);

        if (pDXGIAdapter != nullptr)
        {
            DXGI_ADAPTER_DESC adapterDesc;
            pDXGIAdapter->GetDesc(&adapterDesc);

            adapterInfo.description = std::wstring(adapterDesc.Description);
            adapterInfo.vRam = adapterDesc.DedicatedVideoMemory;
        }
    }
}

std::vector<AdapterInfo> GetDescriptionVRamDirectx()
{
    std::vector<AdapterInfo> result;

    D3D_FEATURE_LEVEL featureLevels[10] = { D3D_FEATURE_LEVEL_12_1,
        D3D_FEATURE_LEVEL_12_0,
        D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_3,
        D3D_FEATURE_LEVEL_9_2,
        D3D_FEATURE_LEVEL_9_1,
        D3D_FEATURE_LEVEL_1_0_CORE
    };

    CComPtr<IDXGIAdapter> higher_performance_adapter;
    CComPtr<IDXGIFactory> pFactory;
    HRESULT createDXGIFactoryResult = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&pFactory));

    if (createDXGIFactoryResult != S_OK)
    {
        printf("Failed to create DXGI factory!\n");
        return result;
    }

    printf("Trying to enumerate graphics adapters...\n");

    int i = 0;
    while (pFactory->EnumAdapters(i, &higher_performance_adapter) == S_OK)
    /*
    while (pFactory->EnumAdapterByGpuPreference(i,
        DXGI_GPU_PREFERENCE_UNSPECIFIED,
        __uuidof(IDXGIAdapter),
        (void**)&higher_performance_adapter) == S_OK)
    */
    {
        i++;

        CComPtr<ID3D11Device> device = nullptr;
        D3D_FEATURE_LEVEL receivedFeatureLevel;
        CComPtr<ID3D11DeviceContext> context = nullptr;

        const HRESULT err = D3D11CreateDevice(
            higher_performance_adapter,
            D3D_DRIVER_TYPE_UNKNOWN,
            nullptr,
            0, // D3D11_CREATE_DEVICE_DEBUG
            featureLevels,
            1,
            D3D11_SDK_VERSION,
            &device,
            &receivedFeatureLevel,
            &context);

        if (err != S_OK)
        {
            higher_performance_adapter = nullptr;
            continue;
        }

        AdapterInfo info;
        getGPUDescriptionVideoRam(device, info);
        info.maxFeatureLevel = receivedFeatureLevel;

        result.push_back(info);       

        higher_performance_adapter = CComPtr<IDXGIAdapter>();
    }

    return result;
}

void displayWMIAdapters()
{
    HRESULT hres;

    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------

    hres = CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres))
    {
        std::cout << "Failed to initialize COM library. Error code = 0x"
            << std::hex << hres << std::endl;
        return;                  // Program has failed.
    }

    // Step 2: --------------------------------------------------
    // Set general COM security levels --------------------------

    hres = CoInitializeSecurity(
        NULL,
        -1,                          // COM authentication
        NULL,                        // Authentication services
        NULL,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
        NULL,                        // Authentication info
        EOAC_NONE,                   // Additional capabilities 
        NULL                         // Reserved
    );


    if (FAILED(hres))
    {
        std::cout << "Failed to initialize security. Error code = 0x"
            << std::hex << hres << std::endl;
        CoUninitialize();
        return;                    // Program has failed.
    }

    // Step 3: ---------------------------------------------------
    // Obtain the initial locator to WMI -------------------------

    IWbemLocator* pLoc = NULL;

    hres = CoCreateInstance(
        CLSID_WbemLocator,
        0,
        CLSCTX_INPROC_SERVER,
        IID_IWbemLocator, (LPVOID*)&pLoc);

    if (FAILED(hres))
    {
        std::cout << "Failed to create IWbemLocator object."
            << " Err code = 0x"
            << std::hex << hres << std::endl;
        CoUninitialize();
        return;                 // Program has failed.
    }

    // Step 4: -----------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method

    IWbemServices* pSvc = NULL;

    // Connect to the root\cimv2 namespace with
    // the current user and obtain pointer pSvc
    // to make IWbemServices calls.
    hres = pLoc->ConnectServer(
        _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
        NULL,                    // User name. NULL = current user
        NULL,                    // User password. NULL = current
        0,                       // Locale. NULL indicates current
        NULL,                    // Security flags.
        0,                       // Authority (for example, Kerberos)
        0,                       // Context object 
        &pSvc                    // pointer to IWbemServices proxy
    );

    if (FAILED(hres))
    {
        std::cout << "Could not connect. Error code = 0x"
            << std::hex << hres << std::endl;
        pLoc->Release();
        CoUninitialize();
        return;                // Program has failed.
    }

    std::cout << "Connected to ROOT\\CIMV2 WMI namespace" << std::endl;


    // Step 5: --------------------------------------------------
    // Set security levels on the proxy -------------------------

    hres = CoSetProxyBlanket(
        pSvc,                        // Indicates the proxy to set
        RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
        RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
        NULL,                        // Server principal name 
        RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
        RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
        NULL,                        // client identity
        EOAC_NONE                    // proxy capabilities 
    );

    if (FAILED(hres))
    {
        std::cout << "Could not set proxy blanket. Error code = 0x"
            << std::hex << hres << std::endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return;               // Program has failed.
    }

    // Step 6: --------------------------------------------------
    // Use the IWbemServices pointer to make requests of WMI ----

    // For example, get the name of the operating system
    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(
        bstr_t("WQL"),
        bstr_t("SELECT * FROM Win32_VideoController"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
        NULL,
        &pEnumerator);

    if (FAILED(hres))
    {
        std::cout << "Query for operating system name failed."
            << " Error code = 0x"
            << std::hex << hres << std::endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return;               // Program has failed.
    }

    // Step 7: -------------------------------------------------
    // Get the data from the query in step 6 -------------------

    IWbemClassObject* pclsObj = NULL;
    ULONG uReturn = 0;

    while (pEnumerator)
    {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
            &pclsObj, &uReturn);

        if (0 == uReturn)
        {
            break;
        }

        VARIANT vtProp;

        // Get the value of the Name property
        hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
        std::wcout << " OS Name : " << vtProp.bstrVal << std::endl;
        VariantClear(&vtProp);

        pclsObj->Release();
    }

    // Cleanup
    // ========

    pSvc->Release();
    pLoc->Release();
    pEnumerator->Release();
    CoUninitialize();
}

int main(int argc, char* argv[])
{
    auto adapters = GetDescriptionVRamDirectx();

    int i = 1;
    for (AdapterInfo adapter : adapters)
    {
        printf("Adapter %d:\n", i);
        printf("-----------\n");
        printf("Description      :");
        wprintf(adapter.description.c_str());
        printf("\n");
        printf("Video RAM        :");
        wprintf(L"%d", adapter.vRam);
        printf("\n");
        printf("Feature level    :");

        if (adapter.maxFeatureLevel == D3D_FEATURE_LEVEL_12_1)
            printf("12_1\n");
        else if (adapter.maxFeatureLevel == D3D_FEATURE_LEVEL_12_0)
            printf("12_0\n");
        else if (adapter.maxFeatureLevel == D3D_FEATURE_LEVEL_11_1)
            printf("11_1\n");
        else if (adapter.maxFeatureLevel == D3D_FEATURE_LEVEL_11_0)
            printf("11_0\n");
        else if (adapter.maxFeatureLevel == D3D_FEATURE_LEVEL_10_1)
            printf("10_1\n");
        else if (adapter.maxFeatureLevel == D3D_FEATURE_LEVEL_10_0)
            printf("10_0\n");
        else if (adapter.maxFeatureLevel == D3D_FEATURE_LEVEL_9_3)
            printf("9_3\n");
        else if (adapter.maxFeatureLevel == D3D_FEATURE_LEVEL_9_2)
            printf("9_2\n");
        else if (adapter.maxFeatureLevel == D3D_FEATURE_LEVEL_9_1)
            printf("9_1\n");
        else if (adapter.maxFeatureLevel == D3D_FEATURE_LEVEL_1_0_CORE)
            printf("1_0_CORE\n");
        printf("\n");      

        i++;
    }

    displayWMIAdapters();

    printf("Press any key...\n");
    getchar();
}

请注意,我还使用 WMI 来枚举显卡。所以在大多数设备上这都能正常工作,即:

Trying to enumerate graphics adapters...
Adapter 1:
-----------
Description      :NVIDIA GeForce MX250
Video RAM        :2080038912
Feature level    :12_1

Adapter 2:
-----------
Description      :Intel(R) UHD Graphics 620
Video RAM        :134217728
Feature level    :12_1

Adapter 3:
-----------
Description      :Microsoft Basic Render Driver
Video RAM        :0
Feature level    :12_1

Connected to ROOT\CIMV2 WMI namespace
 OS Name : Intel(R) UHD Graphics 620
 OS Name : NVIDIA GeForce MX250
Press any key...

但是,我得到的信息是,在特定设置上,没有返回任何结果。比如我朋友说,

我的笔记本(资料不全,安装的显卡是2xGT755m in SLI plus standard,集成——一共3个)

Adapter 1:
-----------
Description      :Microsoft Basic Render Driver
Video RAM        :0
Feature level    :12_1

Press any key...

我很难找出为什么我没有拿到所有卡片。此外,我不知道我可以执行什么样的调试来找出我的问题的原因。

为什么我在使用 DirectX API 时没有在所有机器上获得所有已安装的显卡?

4

0 回答 0