如何确保 DirectX 11 应用程序在带有 C++ 的双 GPU 笔记本电脑上使用独立 GPU?

Posted

技术标签:

【中文标题】如何确保 DirectX 11 应用程序在带有 C++ 的双 GPU 笔记本电脑上使用独立 GPU?【英文标题】:How to ensure DirectX 11 app use the discrete GPU on a dual-gpu laptop with C++? 【发布时间】:2019-08-21 10:41:21 【问题描述】:

我目前正在使用 DirectX 11 开发游戏引擎项目,该项目将被编译为动态链接库,并由 exe 文件调用。我的引擎工作正常。但是,我注意到一个奇怪的问题。

我有三个使用这个引擎的游戏项目。它们以相同的方式创建和设置,链接器/编译器选项完全相同,并且它们与相同的库链接。但是,当我打开可执行文件时,其中只有一个会使用我笔记本电脑上的 dGPU,而另外两个会使用 Intel GPU。

我正在使用 Visual Studio 2017 和 Windows 10 SDK 17763。我没有遍历代码中的所有 GPU 设备,而是使用默认视频适配器。而且由于他们使用相同的代码,我认为行为应该是相同的。

这是我创建 ID3D11Device 的方法。

    DXGI_SWAP_CHAIN_DESC swapDesc = ;
    swapDesc.BufferCount = 2;
    swapDesc.BufferDesc.Width = width;
    swapDesc.BufferDesc.Height = height;
    swapDesc.BufferDesc.RefreshRate.Numerator = 0;
    swapDesc.BufferDesc.RefreshRate.Denominator = 1;
    swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    swapDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    swapDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapDesc.Flags = 0;
    swapDesc.OutputWindow = hWnd;
    swapDesc.SampleDesc.Count = 1;
    swapDesc.SampleDesc.Quality = 0;
    swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
    swapDesc.Windowed = true;

    // Attempt to initialize DirectX
    return D3D11CreateDeviceAndSwapChain(
        nullptr,                // Video adapter (physical GPU) to use, or null for default
        D3D_DRIVER_TYPE_HARDWARE,   // We want to use the hardware (GPU)
        nullptr,                // Used when doing software rendering
        deviceFlags,                // Any special options
        nullptr,        // Optional array of possible versions we want as fallback
        0,              // The number of fallback in the above param
        D3D11_SDK_VERSION,          // Current version of the SDK
        &swapDesc,                  // Address of swap chain options
        &swapChain,                 // Pointer to our Swap Chain pointer
        &device,                    // Pointer to our Device pointer
        &dxFeatureLevel,            // This will hold the actual feature level the app will use
        &context);                  // Pointer to our Device Context pointer

这是两个 EXE 的结果。

使用 NVIDIA GPU 的应用的屏幕截图

未使用 NVIDIA GPU 的应用的屏幕截图

从截图中可以看到,在第一张截图的左上角有一个由 NVIDIA GeForce Experience 生成的 FPS 计数器,而在右边有一个通知,指示 GeForce Overlay 已打开,这意味着该应用程序正在使用 NVIDIA GPU。但是,这两个都没有显示在第二张图片中,这意味着该应用程序正在使用英特尔 GPU。

【问题讨论】:

您的视频卡/系统可能附带一个工具/应用程序来控制使用哪些 GPU 应用程序以及在哪些条件下(插入与电池)。那里的设置可能会导致程序在不同的 GPU 上运行。 Nvidia 驱动程序有一个启发式方法来确定它应该使用哪个 GPU (en.wikipedia.org/wiki/Nvidia_Optimus)。如果您要确保始终使用独立 GPU,则必须枚举您的适配器。 【参考方案1】:

对于这些“混合”系统,很大程度上取决于供应商的驱动程序来“选择正确的 GPU”,而用户则通过其专有设置 UI 对其进行管理。

在 Windows 10 (17134) 之前,您可以提供的唯一编程提示是通过在源代码中使用这些“已知”导出来为 Win32 桌面应用程序提供:

// Indicates to hybrid graphics systems to prefer the discrete part by default
extern "C" 

    __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
    __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;

使用 DXGI 1.6 在 Windows 10 (17134) 或更高版本上运行时,您可以使用 IDXGIFactory6 通过 EnumAdapterByGpuPreference 进行适配器枚举。

ComPtr<IDXGIFactory6> factory6;
HRESULT hr = m_dxgiFactory.As(&factory6);
if (SUCCEEDED(hr))

    for (UINT adapterIndex = 0;
        DXGI_ERROR_NOT_FOUND != factory6->EnumAdapterByGpuPreference(
            adapterIndex,
            DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
            IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf()));
        adapterIndex++)
    
…
    

else for (UINT adapterIndex = 0;
    DXGI_ERROR_NOT_FOUND != m_dxgiFactory->EnumAdapters1(
        adapterIndex,
        adapter.ReleaseAndGetAddressOf());
    adapterIndex++)

…

【讨论】:

以上是关于如何确保 DirectX 11 应用程序在带有 C++ 的双 GPU 笔记本电脑上使用独立 GPU?的主要内容,如果未能解决你的问题,请参考以下文章

基于 DirectX11 的 MMDViewer 03-渲染管线

DirectX 11能解释下是啥意思?

如何在透明窗口中绘制透明 DirectX 内容?

DirectX11 C++ 着色器缓冲区在多边形布局描述中变为空

C++ DirectX11 窗口颜色不变

DirectX 12 中 Assimp 的骨骼动画错误