我开发了一个应用程序,它在窗口中显示类似视频的内容。我使用此处描述的技术 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 Docs和 Anatomy 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 )
完成。
关于c++ - 如何检查是否使用了真正的硬件视频适配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48326295/