Как проверить, используется ли настоящий аппаратный видеоадаптер

Я разрабатываю приложение, которое показывает что-то вроде видео в своем окне. Я использую технологии, описанные здесь Знакомство с Direct2D 1.1. В моем случае единственная разница в том, что в конечном итоге я создаю растровое изображение, используя

ID2D1DeviceContext::CreateBitmap

тогда я использую

ID2D1Bitmap::CopyFromMemory

чтобы скопировать на него необработанные данные RGB, а затем я вызываю

ID2D1DeviceContext::DrawBitmap

рисовать растровое изображение. Я использую высококачественный режим кубической интерполяции D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC для масштабирования, чтобы получить наилучшее изображение, но в некоторых случаях (RDP, Citrix, виртуальные машины и т. д.) он очень медленный и требует очень высокой загрузки ЦП. Это происходит потому, что в этих случаях используется неаппаратный видеоадаптер. Поэтому для неаппаратных адаптеров я пытаюсь отключить интерполяцию и использовать более быстрые методы. Проблема в том, что я не могу точно проверить, есть ли в системе настоящий аппаратный адаптер.

Когда я вызываю D3D11CreateDevice, я использую его с D3D_DRIVER_TYPE_HARDWARE, но на виртуальных машинах он обычно возвращает «Microsoft Basic Render Driver», который является программным драйвером и не использует GPU (он потребляет CPU). Итак, в настоящее время я проверяю идентификатор поставщика. Если производитель AMD (ATI), NVIDIA или Intel, то я использую кубическую интерполяцию. В другом случае я использую самый быстрый метод, который не сильно потребляет процессор.

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)), поэтому у меня по-прежнему высокая загрузка ЦП с кубическая интерполяция. В случае сеанса RDP в Windows 7 с ATI Radeon это на 10% больше, чем через физическую консоль.

Или я ошибаюсь, и RDP каким-то образом использует ресурсы GPU, и поэтому он возвращает реальный аппаратный адаптер через IDXGIAdapter::GetDesc?

Прямая отрисовка

Также я посмотрел средство диагностики DirectX. Похоже, информационное поле «Ускорение DirectDraw» возвращает именно то, что мне нужно. В случае физических (консольных) сеансов отображается «Включено». В случае сеансов 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
             }
         }
     }
 }

Информация о флаге DXGI_ADAPTER_FLAG_SOFTWARE

 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 не используется. По крайней мере, в Windows 7 с ATI Radeon я вижу большую загрузку ЦП в случае сеанса RDP. Таким образом, похоже, что DXGI_ADAPTER_FLAG_SOFTWARE предназначен только для Microsoft Basic Render Driver. Так что проблема не решена.

Вопрос

Есть ли правильный способ проверить, используется ли настоящая аппаратная видеокарта (GPU) для текущего сеанса Windows? Или, может быть, можно проверить, имеет ли конкретный режим интерполяции ID2D1DeviceContext::DrawBitmap аппаратную реализацию и использует ли GPU для текущей сессии?

UPD

Тема не об обнаружении сеансов RDP или Citrix. Речь не идет о том, чтобы определить, находится ли приложение внутри виртуальной машины или нет. У меня уже есть все проверки, и я использую линейную интерполяцию для этих случаев. Эта тема посвящена определению того, используется ли настоящий графический процессор для текущего сеанса Windows для отображения рабочего стола. Я ищу более сложное решение для принятия решений с использованием функций DirectX и DXGI.


person Eugen    schedule 18.01.2018    source источник


Ответы (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.
            }
        }
    }
}

См. MSDN и Анатомия Direct3D 11 Create Device

Вы, вероятно, обнаружите, что для тестирования/отладки вы не хотите явно блокировать эти сценарии, но вы хотите предоставить какое-то предупреждение или уведомить пользователя о том, что он использует программный, а не аппаратный рендеринг.

Обнаружение удаленного рабочего стола из классических настольных приложений Win32 лучше выполнять напрямую через GetSystemMetrics( SM_REMOTESESSION ).

См. MSDN.

person Chuck Walbourn    schedule 18.01.2018
comment
Я полагаю, что для сценария удаленного рабочего стола вы проверяете флаги DXGI_ADAPTER_DESC1 или более поздних версий для DXGI_ADAPTER_FLAG_SOFTWARE. Мне нужно перепроверить это... - person Chuck Walbourn; 18.01.2018
comment
Спасибо за ответ, но, к сожалению, мне не нужно обнаруживать Microsoft Basic Renderer. Когда я выполняю сеанс RDP на реальной машине, IDXGIAdapter возвращает (в описании) реальный видеоадаптер, установленный на машине. Согласно таким инструментам, как Process Hacker 2, графический процессор не используется, а ЦП используется для рендеринга. Я посмотрел на IDXGIAdapter1::GetDesc1 и DXGI_ADAPTER_FLAG, и снова у него нет флага DXGI_ADAPTER_FLAG_SOFTWARE в случае сеансов RDP. - person Eugen; 18.01.2018
comment
Ваша логика в исходном сообщении ошибочна, поскольку вы пытаетесь «привязаться» к одному из трех поставщиков. Мой ответ заключается в том, что вместо этого вы должны изменить логику и исключить MBR, если это вас беспокоит. RDP — это отдельная проблема, которую вы, конечно, всегда можете обнаружить напрямую. Знаете ли вы, используете ли вы RemoteFX vGPU? - person Chuck Walbourn; 19.01.2018
comment
наша логика в исходном посте ошибочна, поскольку вы пытаетесь «привязаться» к одному из трех поставщиков. Можете ли вы быть уверены, что виртуальная машина не будет симулировать реальную аппаратную видеокарту, которая на самом деле имеет программную реализацию? В настоящее время я могу только протестировать VMWare. В устройствах используется VMWare SVGA 3D, но IDXGIDevice возвращает Microsoft Basic Renderer. Но как насчет другого программного обеспечения для виртуализации? - person Eugen; 19.01.2018
comment
Вероятно, было бы полезно, если бы вы сделали резервную копию и объяснили, какую проблему вы пытаетесь решить, а не решение. Если вы беспокоитесь о том, что ваше приложение не будет работать должным образом, определите сценарий RDP и/или MBR и установите окно с предупреждением, чтобы пользователь знал, что оно не будет работать должным образом. Вы не можете предположить, что NVIDIA, AMD и/или Intel никогда не выпустят программный рендерер. На самом деле многие ранние графические процессоры Intel были ничем иным, как программным обеспечением. - person Chuck Walbourn; 19.01.2018
comment
Но я уже объяснил проблему. Это в основном посте: я использую высококачественный режим кубической интерполяции ... но в некоторых случаях (RDP, Citrix, виртуальные машины и т. д.) он очень медленный и потребляет очень много ресурсов процессора. Так что в настоящее время я просто ограничил карты, которые могут делать кубическую интерполяцию для NVIDIA, AMD и INTEL. Также да, он уже проверяет, находится ли он внутри RDP-сессии и не использует там кубическую интерполяцию. Я просто ищу более сложное решение, потому что программное обеспечение можно запускать в Citrix или, как вы заметили, может быть старый Intel GPU и т. д. - person Eugen; 19.01.2018
comment
Чак, ПОЖАЛУЙСТА, ПОЖАЛУЙСТА, ПОЖАЛУЙСТА, не публикуйте здесь, как определить, находитесь ли вы внутри сеанса Citrix. Тема не об этом. Тема: КАК ПРОВЕРИТЬ, ИСПОЛЬЗУЕТ ЛИ ТЕКУЩАЯ СЕССИЯ WINDOWS НАСТОЯЩИЙ АППАРАТНЫЙ АДАПТЕР ДЛЯ ОТОБРАЖЕНИЯ РАБОТЫ! - person Eugen; 19.01.2018
comment
В неудаленных сценариях MBR — единственный случай, когда вы можете получить программное устройство, когда запрашиваете аппаратное устройство. Как правило, нет никакой гарантии производительности для какого-либо конкретного поставщика или комбинации карт, поэтому лучше всего выполнить тест на целевой системе с включенной фильтрацией и, если она слишком медленная, отключить ее. - person Chuck Walbourn; 19.01.2018