【问题标题】:How to check if a true hardware video adapter is used如何检查是否使用了真正的硬件视频适配器
【发布时间】:2018-06-27 19:41:52
【问题描述】:

我开发了一个应用程序,它在其窗口中显示类似视频的内容。我使用此处描述的技术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 会话。但是对于 RDP 会话 IDXGIAdapter 仍然返回供应商以防真机但它不使用 GPU(我可以通过 Process Hacker 2 和 AMD 系统监视器看到它(在 ATI Radeon 的情况下))所以我仍然有很高的 CPU 消耗三次插值。如果使用 ATI Radeon 与 Windows 7 进行 RDP 会话,则它比通过物理控制台大 10%。

还是我弄错了,RDP 不知何故使用了 GPU 资源,这就是它通过 IDXGIAdapter::GetDesc 返回真实硬件适配器的原因?

DirectDraw

我还查看了 DirectX 诊断工具。看起来“DirectDraw Acceleration”信息字段完全返回了我需要的内容。如果是物理(控制台)会话,它会显示“已启用”。如果是 RDP 和虚拟机(没有硬件视频加速)会话,它会显示“不可用”。我查看了来源,理论上我可以使用验证算法。但它实际上是针对我的应用程序中不使用的 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 会话,Flags == 0 但正如我通过 Process Hacker 2 看到的那样,未使用 GPU。至少在带有 ATI Radeon 的 Windows 7 上,在 RDP 会话的情况下,我可以看到更大的 CPU 使用率。所以看起来 DXGI_ADAPTER_FLAG_SOFTWARE 仅适用于 Microsoft Basic Render Driver。所以问题没有解决。

问题

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

UPD

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

【问题讨论】:

    标签: c++ windows directx directx-11 dxgi


    【解决方案1】:

    如果您想检测 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.
                }
            }
        }
    }
    

    MSDNAnatomy of Direct3D 11 Create Device

    对于测试/调试,您可能会发现您不想明确阻止这些场景,但您确实想向用户提供某种警告或通知反馈,说明他们使用的是软件而不是硬件渲染。

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

    MSDN

    【讨论】:

    • 对于远程桌面场景,我相信你检查DXGI_ADAPTER_DESC1或更高版本的标志为DXGI_ADAPTER_FLAG_SOFTWARE。我需要仔细检查...
    • 感谢您的回答,但不幸的是我不需要检测 Microsoft Basic Renderer。当我对真实机器进行 RDP 会话时,IDXGIAdapter 返回(在描述中)安装在机器上的真实视频适配器。根据 Process Hacker 2 等工具,不使用 GPU,但使用 CPU 进行渲染。我查看了 IDXGIAdapter1::GetDesc1 和 DXGI_ADAPTER_FLAG 并且在 RDP 会话的情况下它没有 DXGI_ADAPTER_FLAG_SOFTWARE 标志。
    • 您在原始帖子中的逻辑存在缺陷,因为您试图“锁定”到三个供应商之一。我的回答是,如果您担心的话,您应该反转逻辑并排除 MBR。 RDP 是一个明显的问题,您当然总是可以直接检测到它。你知道你是否在使用 RemoteFX vGPU?
    • “我们在原始帖子中的逻辑存在缺陷,因为您试图‘锁定’到三个供应商之一。”您能确定虚拟机不会模拟实际具有软件实现的真实硬件显卡吗?目前我只能测试VMWare。它在设备中有 VMWare SVGA 3D,但 IDXGIDevice 返回“Microsoft Basic Renderer”。但是其他虚拟化软件呢?
    • 如果您备份并解释您要解决的问题是什么而不是解决方案,这可能会有所帮助。如果您担心您的应用程序性能不佳,请检测 RDP 和/或 MBR 场景并设置一个警告框,以便用户知道它性能不佳。您不能假设 NVIDIA、AMD 和/或 Intel 永远不会推出软件渲染器。事实上,许多早期的英特尔“GPU”只不过是软件而已。
    【解决方案2】:

    在我努力回答一个 3 年前的问题时。

    我必须通过注册表。首先是在注册表中找到适配器的LUID,得到适配器的GUID

    private string GetAdapterGuid(long luid)
    {
        var directXRegistryKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\DirectX");
        if (directXRegistryKey == null)
            return "";
        var subKeyNames = directXRegistryKey.GetSubKeyNames();
        foreach (var subKeyName in subKeyNames)
        {
            var subKey = directXRegistryKey.OpenSubKey(subKeyName);
            if (subKey.GetValueKind("AdapterLuid") != RegistryValueKind.QWord)
                continue;
            var luidValue = (long)subKey.GetValue("AdapterLuid");
            if (luidValue == luid)
                return subKeyName;
        }
        return "";
    }
    

    一旦你有了那个Guid,你就可以像这样在HKLM中搜索显卡的详细信息。如果是虚拟的,则服务名称将为“INDIRECTKMD”:

    private bool IsVirtualAdapter(string adapterGuid)
    {
        var videoRegistryKey = Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Control\Video\{adapterGuid}\Video");
        if (videoRegistryKey == null)
            return false;
        if (videoRegistryKey.GetValueKind("Service") != RegistryValueKind.String)
            return false;
        var serviceName = (string)videoRegistryKey.GetValue("Service");
        return serviceName.ToUpper() == "INDIRECTKMD";
    }
    

    检查服务名称比解析 DeviceDesc 值更容易。

    我的用例涉及准备好 Guid,因此我将功能拆分,您可以将其合并为一个。

    它也只通过这个检测 RDP/MSTSC,其他虚拟适配器可能需要额外的服务名称。或者您可以尝试仅检测 Nvidia/AMD/Intel 驱动程序名称...由您决定。

    【讨论】:

      猜你喜欢
      • 2014-11-01
      • 2021-12-04
      • 1970-01-01
      • 2018-01-07
      • 1970-01-01
      • 1970-01-01
      • 2021-03-04
      • 1970-01-01
      • 2021-05-03
      相关资源
      最近更新 更多