如何确保 DirectX 11 应用程序在带有 C++ 的双 GPU 笔记本电脑上使用独立 GPU?
How to ensure DirectX 11 app use the discrete GPU on a dual-gpu laptop with C++?
我目前正在开发一个使用 DirectX 11 的游戏引擎项目,它将被编译成一个动态链接库,并被一个 exe 文件调用。我的引擎工作得很好。但是,我发现了一个奇怪的问题。
我有三个游戏项目使用了这个引擎。它们以相同的方式创建和设置,linker/compiler 选项完全相同,并且它们与相同的库链接。但是,当我打开可执行文件时,只有其中一个会使用笔记本电脑上的 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。
对于这些 'hybrid' 系统,主要取决于供应商的驱动程序 'pick the right GPU' 以及用户通过其专有设置 UI.
进行管理
在 Windows 10 (17134) 之前,您可以提供的唯一编程提示是通过在源代码中使用这些 'known' 导出的 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;
}
当 运行 on Windows 10 (17134) 或更高版本时,使用 DXGI 1.6,您可以使用 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 的游戏引擎项目,它将被编译成一个动态链接库,并被一个 exe 文件调用。我的引擎工作得很好。但是,我发现了一个奇怪的问题。
我有三个游戏项目使用了这个引擎。它们以相同的方式创建和设置,linker/compiler 选项完全相同,并且它们与相同的库链接。但是,当我打开可执行文件时,只有其中一个会使用笔记本电脑上的 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。
对于这些 'hybrid' 系统,主要取决于供应商的驱动程序 'pick the right GPU' 以及用户通过其专有设置 UI.
进行管理在 Windows 10 (17134) 之前,您可以提供的唯一编程提示是通过在源代码中使用这些 'known' 导出的 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;
}
当 运行 on Windows 10 (17134) 或更高版本时,使用 DXGI 1.6,您可以使用 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++)
{
…
}