c++ - 如何检查是否使用了真正的硬件视频适配器

标签 c++ windows directx directx-11 dxgi

我开发了一个应用程序,它在窗口中显示类似视频的内容。我使用此处描述的技术 Introducing Direct2D 1.1 .在我的例子中,唯一的区别是最终我使用

创建了一个位图
ID2D1DeviceContext::CreateBitmap

然后我用

ID2D1Bitmap::CopyFromMemory

将原始 RGB 数据复制到它,然后我调用

ID2D1DeviceContext::DrawBitmap

绘制位图。我使用高质量三次插值模式 D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC 进行缩放以获得最佳图片,但在某些情况下(RDP、Citrix、虚拟机等)它非常慢并且 CPU 消耗非常高。发生这种情况是因为在这些情况下使用了非硬件视频适配器。因此,对于非硬件适配器,我试图关闭插值并使用更快的方法。问题是我无法准确检查系统是否具有真正的硬件适配器。

当我调用 D3D11CreateDevice 时,我将它与 D3D_DRIVER_TYPE_HARDWARE 一起使用,但在虚拟机上它通常返回“Microsoft Basic Render Driver”,这是一个软件驱动程序,不使用 GPU(它消耗 CPU)。所以目前我检查供应商 ID。如果供应商是 AMD (ATI)、NVIDIA 或 Intel,那么我使用三次插值。在另一种情况下,我使用不会大量消耗 CPU 的最快方法。

Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
if (SUCCEEDED(m_pD3dDevice->QueryInterface(...)))
{
    Microsoft::WRL::ComPtr<IDXGIAdapter> adapter;
    if (SUCCEEDED(dxgiDevice->GetAdapter(&adapter)))
    {
        DXGI_ADAPTER_DESC desc;
        if (SUCCEEDED(adapter->GetDesc(&desc)))
        {
            // NVIDIA
            if (desc.VendorId == 0x10DE ||
                // AMD
                desc.VendorId == 0x1002 || // 0x1022 ?
                // Intel
                desc.VendorId == 0x8086) // 0x163C, 0x8087 ?
            {
                bSupported = true;
            }
        }
     }
 }

即使在虚拟机中,它也适用于物理(控制台)Windows session 。但是对于 RDP session ,IDXGIAdapter 在真机的情况下仍然返回供应商,但它不使用 GPU(我可以通过 Process Hacker 2 和 AMD System Monitor(在 ATI Radeon 的情况下)看到它)所以我仍然有很高的 CPU 消耗三次插值。如果使用 ATI Radeon 与 Windows 7 进行 RDP session ,则它比通过物理控制台大 10%。

还是我弄错了,RDP 以某种方式使用 GPU 资源,这就是它通过 IDXGIAdapter::GetDesc 返回真实硬件适配器的原因?

DirectDraw

我还查看了 DirectX 诊断工具。看起来“DirectDraw Acceleration”信息字段返回的正是我所需要的。如果是物理(控制台) session ,它会显示“已启用”。在 RDP 和虚拟机(没有硬件视频加速) session 的情况下,它显示“不可用”。我查看了来源,理论上我可以使用验证算法。但它实际上适用于我在我的应用程序中不使用的 DirectDraw。我想使用直接链接到 ID3D11Device、IDXGIDevice、IDXGIAdapter 等的东西。

IDXGIAdapter1::GetDesc1 和 DXGI_ADAPTER_FLAG

我还尝试使用 IDXGIAdapter1::GetDesc1 并检查标志。

Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
if (SUCCEEDED(m_pD3dDevice->QueryInterface(...)))
{
    Microsoft::WRL::ComPtr<IDXGIAdapter> adapter;
    if (SUCCEEDED(dxgiDevice->GetAdapter(&adapter)))
    {
         Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter1;
         if (SUCCEEDED(adapter->QueryInterface(__uuidof(IDXGIAdapter1), reinterpret_cast<void**>(adapter1.GetAddressOf()))))
         {
             DXGI_ADAPTER_DESC1 desc;
             if (SUCCEEDED(adapter1->GetDesc1(&desc)))
             {
                    // desc.Flags
                    // DXGI_ADAPTER_FLAG_NONE         = 0,
                    // DXGI_ADAPTER_FLAG_REMOTE       = 1,
                    // DXGI_ADAPTER_FLAG_SOFTWARE     = 2,
                    // DXGI_ADAPTER_FLAG_FORCE_DWORD  = 0xffffffff
             }
         }
     }
 }

Information about the DXGI_ADAPTER_FLAG_SOFTWARE flag

 Virtual Machine RDP Win Serv 2012 (Microsoft Basic Render Driver) -> (0x02) DXGI_ADAPTER_FLAG_SOFTWARE
 Physical Win 10 (Intel Video) -> (0x00) DXGI_ADAPTER_FLAG_NONE
 Physical Win 7 (ATI Radeon) - > (0x00) DXGI_ADAPTER_FLAG_NONE
 RDP Win 10 (Intel Video) -> (0x00) DXGI_ADAPTER_FLAG_NONE
 RDP Win 7 (ATI Radeon) -> (0x00) DXGI_ADAPTER_FLAG_NONE

如果在带有硬件适配器的真实机器上进行 RDP session ,Flags == 0 但正如我通过 Process Hacker 2 看到的那样,GPU 未被使用。至少在带有 ATI Radeon 的 Windows 7 上,我可以看到在 RDP session 的情况下更大的 CPU 使用率。所以看起来 DXGI_ADAPTER_FLAG_SOFTWARE 仅适用于 Microsoft Basic Render Driver。所以问题没有解决。

问题

是否有正确的方法来检查当前 Windows session 是否使用了真实的硬件视频卡 (GPU)?或者也许可以检查 ID2D1DeviceContext::DrawBitmap 的特定插值模式是否具有硬件实现并在当前 session 中使用 GPU?

UPD

主题与检测 RDP 或 Citrix session 无关。它与检测应用程序是否在虚拟机内无关。我已经进行了所有验证,并在这些情况下使用了线性插值。该主题是关于检测当前 Windows session 是否使用真正的 GPU 来显示桌面。我正在寻找一种更复杂的解决方案来使用 DirectX 和 DXGI 的功能进行决策。

最佳答案

如果您想检测 Microsoft Basic Renderer,最好的选择是使用它的 VID/PID 组合:

ComPtr<IDXGIDevice> dxgiDevice;
if (SUCCEEDED(device.As(&dxgiDevice)))
{
    ComPtr<IDXGIAdapter> adapter;
    if (SUCCEEDED(dxgiDevice->GetAdapter(&adapter)))
    {
        DXGI_ADAPTER_DESC desc;
        if (SUCCEEDED(adapter->GetDesc(&desc)))
        {
            if ( (desc.VendorId == 0x1414) && (desc.DeviceId == 0x8c) )
            {
                // WARNING: Microsoft Basic Render Driver is active.
                // Performance of this application may be unsatisfactory.
                // Please ensure that your video card is Direct3D10/11 capable
                // and has the appropriate driver installed.
            }
        }
    }
}

参见 Microsoft DocsAnatomy of Direct3D 11 Create Device

You will probably find for testing/debugging that you don't want to explicitly block these scenarios, but you do want to provide some kind of warning or notice feedback to the user that they are using software rather than hardware rendering.

Win32 经典桌面应用程序的远程桌面检测最好直接通过 GetSystemMetrics( SM_REMOTESESSION ) 完成。

参见 Microsoft Docs

关于c++ - 如何检查是否使用了真正的硬件视频适配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48326295/

相关文章:

c++ - 我无法在 C++ 中初始化结构值

c++ - OpenGL 着色器错误 C1068 :Too much data in type constructor

windows - Dos/Windows 批量插入符号在 set/P 提示符下转义

c++ - 绘制带纹理的四边形看起来变形了

c++ - 读取与在 union 中编写的不同的成员是否是未定义的行为?

c++ - 虚函数指针混淆

java - NSIS 和卸载时从 XML 读取

windows - 从 emacs 中使用默认 Windows 应用程序打开文件

c++ - Direct3D 中的 Windows Phone 8 触摸位置

c++ - DirectX 9 HLSL 与 DirectX 10 HLSL : syntax the same?