DirectX 未检测到所有显卡

问题描述

我在使用 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,// 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,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,&pclsObj,&uReturn);

        if (0 == uReturn)
        {
            break;
        }

        VARIANT vtProp;

        // Get the value of the Name property
        hr = pclsObj->Get(L"Name",&vtProp,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的SLI plus标准,集成-总共3个)

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

Press any key...

我很难找出为什么我没有收到所有卡片。而且,我不知道我可以进行什么样的调试才能找出问题的原因。

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

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)