Criando um aplicativo de composição personalizado para monitores especializados e montados na cabeça

A API Windows.Devices.Display.Core é uma API WinRT (Tempo de Execução do Windows) de baixo nível para compositores de terceiros e componentes internos do Windows que fica abaixo de todas as outras APIs públicas para enumerar, configurar e conduzir adaptadores de exibição e destinos de exibição no Windows. A ideia é tratar o controlador de exibição como um mecanismo separado, análogo ao mecanismo 3D e ao mecanismo de mídia na GPU. Essa API é responsável por:

  • Respondendo a perguntas sobre o hardware de exibição (como recursos e possíveis modos de exibição)
  • Respondendo a perguntas sobre a configuração atual
  • Definindo propriedades no hardware de exibição (como modos de exibição)
  • Configurando o hardware de exibição (a resolução dos monitores conectados, seu formato de fio, etc.)
  • Alocar e varrer superfícies especiais de GPU conhecidas como primárias
  • Permitir a interoperabilidade entre o Direct3D e as APIs Windows.Devices.Display.Core (por exemplo, compartilhamento de superfícies, cercas)

Vale a pena destacar o que Windows.Devices.Display.Core não é:

  • Não é uma API usada por jogos ou aplicativos para exibir conteúdo em uma janela. Os aplicativos ainda usam DXGI, XAML, APIs de composição, GDI etc.
  • Não é uma API usada por jogos ou aplicativos para exibir conteúdo em tela cheia. Os aplicativos ainda usam DXGI, os aplicativos Win32 ainda usam HWNDs e os aplicativos UWP sempre exibem conteúdo em um CoreWindow.

Essa API é para aplicativos de composição que conduzem apenas hardware especializado.

Diagrama mostrando camadas arquitetônicas de API para exibições especializadas.

Cenários para criar compositores personalizados

As APIs Windows.Devices.Display.Core são apropriadas para uso nos seguintes cenários:

  • Monitores de realidade virtual e aumentada que exigem um compositor proprietário para acionar diretamente o controlador de exibição e receber controle refinado sobre a configuração de tempo e modo separada da área de trabalho do Windows.
  • Cenários de hardware de exibição especializados que exigem controle dedicado sobre uma exibição em um ambiente comercial. Por exemplo, nos casos em que a área de trabalho do Windows não pode ser renderizada corretamente em tal tela devido à distorção de hardware, telas em escala de cinza, etc.
  • Cenários de "dispositivo" especializados em que um monitor pode ser totalmente dedicado a um aplicativo sem qualquer interferência da experiência da área de trabalho do Windows por um longo período de tempo (por exemplo, um monitor de vídeo dedicado).

A API faz isso ao:

  • Fornecendo controle refinado sobre as informações completas do modo de exibição, incluindo formato de fio, HDR, etc.
  • O uso de cercas para sincronizar a apresentação permite que um compositor encadeie a apresentação entre processos ou subcomponentes com sobrecarga de desempenho quase zero.
  • Melhorar a capacidade de consultar e configurar a Rede de Vídeo Presente subjacente (VidPN) para permitir que os componentes do sistema e os componentes de composição de baixo nível executem operações mais complexas de maneira menos propensa a erros e mais extensível.

Observe que essa API é apenas para um conjunto muito específico de casos de uso de terceiros com hardware especializado. Seu uso é altamente restrito a hardwares que se declaram necessitando da funcionalidade dessa API. Portanto, um certo grau de familiaridade com os conceitos de hardware é esperado dos desenvolvedores, e os parceiros devem entrar em contato diretamente com a Microsoft para ajudar com problemas.

Requisitos de hardware e software

Os compositores personalizados de terceiros só podem adquirir monitores que tenham sido pré-designados como monitores montados na cabeça (HMDs) ou monitores "especializados". Esta designação deve ser fornecida de duas maneiras:

  • Extensão EDID – dispositivos de exibição personalizados projetados para uso permanente como HMDs, monitores de raio-X, paredes de vídeo ou outros cenários especializados devem implementar a extensão Microsoft EDID para monitores especializados e montados na cabeça.
  • Substituição de usuário – para instalações de hardware personalizadas usando monitores prontos para uso, o Windows fornece uma alternância de interface do usuário para designar monitores como "especializados".

Os monitores não podem ser designados como HMDs ou monitores especializados substituindo o EDID no software.

Observação

Exibições especializadas só estão disponíveis a partir do Windows 10, versão 2004, e exigem Windows 10 Enterprise, Windows 10 Pro for Workstations ou Windows 10 IoT Enterprise.

Roteiro para implementar um compositor personalizado

A implementação de um compositor personalizado pode ser dividida em vários estágios:

  • Enumerar e descobrir HMDs associados ou monitores especializados
  • Adquirir a propriedade dos monitores selecionados
  • Configurar modos para todos os monitores selecionados
  • Criar recursos para apresentar quadros aos monitores
  • Renderizar conteúdo e agendar apresentação de quadros
API Objetivo e Público-Alvo
DisplayInformation Usado para recuperar propriedades de renderização e layout para um CoreWindow.
HdmiDisplayInformation API somente do Xbox para enumerar e definir um conjunto restrito de modos. Altamente especializado para cenários de aplicativos de mídia do Xbox.
DisplayMonitor Usado para consultar propriedades de um dispositivo de monitor físico. Não expõe nenhuma informação de tempo de execução sobre como um monitor está configurado ou usado atualmente pelo sistema operacional.
EnumDisplayDevices, EnumDisplayMonitors, EnumDisplaySettingsEx APIs Win32 herdadas para consultar HMONITORs, dispositivos GDI e mapeamentos de monitor físico. As informações retornadas aqui são altamente virtualizadas e mantidas para compatibilidade de aplicativos.
Direct3D Usado para renderizar conteúdo de pixel em superfícies de GPU e executar computação em uma GPU.
Cadeias de troca DXGI Usado para apresentação em tela cheia com e sem janelas. O conteúdo da cadeia de troca de aplicativos flui por meio do compositor do sistema, DWM.
Enumeração de saída DXGI Fornece wrappers DXGI em torno de HMONITORs.
QueryDisplayConfig, SetDisplayConfig, DisplayConfigGetDeviceInfo, DisplayConfigSetDeviceInfo APIs do Win32 para configurar a topologia de exibição. Não fornece nenhum mecanismo para enumerar vários modos, mas tem um conjunto avançado de informações sobre a configuração e as configurações atuais. No entanto, nem todas as propriedades mais recentes de um modo são expostas por essas APIs.
Windows.Devices.Display.Core (este documento) Usado para enumerar destinos, enumerar modos, configurar modos, alocar superfícies de GPU para apresentação e apresentar conteúdo para monitores.

Visão geral da configuração do monitor

Enumeração de hardware físico

A API Windows.Devices.Display.Core tem vários objetos para representar objetos de hardware físico. Um DisplayAdapter é normalmente (mas nem sempre) um dispositivo de hardware físico, como uma GPU conectada ao PCI Express ou uma GPU integrada em uma CPU. Os objetos DisplayTarget representam os conectores físicos (por exemplo, HDMI, VGA, DisplayPort etc.) que podem ser conectados a partir da GPU. Isso pode incluir conexões internas não visíveis ao usuário para dispositivos com monitores internos (laptops, tablets, etc.). Pode haver mais objetos DisplayTarget representados no software do que um usuário pode conectar fisicamente ao mesmo tempo. Por exemplo, como o padrão de conexão DisplayPort permite o encadeamento, os drivers de GPU normalmente enumeram vários destinos DisplayPort por porta física para levar em conta monitores encadeados.

Ilustração da topologia de hardware para adaptadores de vídeo e destinos de exibição.

Objetos para modos de configuração

Para enumerar objetos DisplayTarget , modos de configuração e consulta, etc., as conexões com objetos DisplayTarget são representadas com objetos DisplayPath . Grupos de caminhos que exibem o mesmo conteúdo (grupos de clones) são representados por DisplayView e são agregados em um DisplayState. Um objeto DisplayState pode, portanto, representar um conjunto completo de estado de modo que pode ser enviado aos drivers para vários monitores.

Ilustração da topologia de modo com objetos de caminho de exibição, exibição de exibição e estado de exibição.

Estado atômico para configuração e enumeração de modo

A API Windows.Devices.Display.Core foi projetada para garantir que os compositores possam adquirir acesso a vários estados de exibição do sistema atomicamente e com comportamentos de desatualização bem definidos. Isso é importante porque as GPUs são recursos compartilhados, com largura de banda e restrições de energia muito apertadas. Em sistemas modernos, os dispositivos podem chegar/partir a qualquer momento e outras coisas podem afetar a lista de modos de exibição disponíveis (por exemplo, encaixe/desencaixe, estados de suspensão, outro componente alterando os modos em outro caminho). Portanto, é importante que os compositores sejam resilientes a alterações na configuração do sistema usando a API Windows.Devices.Display.Core e seguindo os padrões recomendados para configurar o estado.

A API Windows.Devices.Display.Core, portanto, fornece um modelo transacional simples de leitura-modificação-confirmação, semelhante a um banco de dados. Os clientes podem ler atomicamente um objeto DisplayState para dispositivos de exibição no sistema. Todos os objetos são imutáveis ou fornecem APIs bem definidas para atualizar/confirmar o estado de volta ao sistema. As alterações não são feitas até que DisplayState.TryApply seja chamado, o que "confirma" as alterações no sistema. A confirmação/aplicação de alterações em um DisplayState falha sem impacto ou é bem-sucedida com as alterações completas aplicadas.

Para aproveitar os recursos de atomicidade da API:

  • Escreva qualquer lógica de configuração de modo em um loop de repetição.
  • Crie um novo DisplayState no início da configuração do modo, dentro de cada loop.
  • Use o sinalizador FailIfStateChanged ao chamar DisplayState.TryApply para detectar que o estado do sistema não é mais o mesmo de quando o DisplayState foi criado. Isso permite que você tente novamente a operação. Se a operação falhar com SystemStateChanged, repita o loop inteiro.
  • Não misture outras APIs (DXGI, GDI etc.) que leem ou alteram o estado com o uso de APIs Windows.Devices.Display.Core, pois elas podem não ter as mesmas garantias de atomicidade.
#include <winrt\Windows.Devices.Display.Core.h>
using namespace winrt::Windows::Devices::Display::Core;
...

// Create a DisplayManager
DisplayManager manager = DisplayManager::Create(DisplayManagerOptions::EnforceSourceOwnership);

// Loop around trying to acquire a target and set a mode
bool shouldRetry;
do
{
    shouldRetry = false;

    // ... Find the target that you want to use
    auto targets = manager.GetCurrentTargets();
    DisplayTarget selectedTarget = ...;

    auto stateCreationResult = manager.TryAcquireTargetsAndCreateEmptyState(
        winrt::single_threaded_vector<DisplayTarget>({ selectedTarget }));

    if (stateCreationResult.ErrorCode() != DisplayManagerResult::Success)
    {
        winrt::check_hresult(stateCreationResult.ExtendedErrorCode());
    }

    auto state = stateCreationResult.State();
    DisplayPath newPath = state.ConnectTarget(selectedTarget);

    // ... Configure the path

    auto applyResult = state.TryApply(DisplayStateApplyOptions::FailIfStateChanged);

    if (applyResult.Status() == DisplayStateOperationStatus::SystemStateChanged)
    {
        shouldRetry = true;
    }
    else if (applyResult.Status() != DisplayStateOperationStatus::Success)
    {
        winrt::check_hresult(applyResult.ExtendedErrorCode());
    }

} while (shouldRetry);

As seguintes APIs leem o estado atomicamente do sistema:

As seguintes APIs confirmam o estado de volta ao sistema:

  • DisplayManager
  • DisplayState
    • TryApply Atualiza o estado de exibição atual do sistema definindo ou limpando os modos em todos os destinos de propriedade no sistema, por meio dos drivers de exibição.

Limitações conhecidas

A API Windows.Devices.Display.Core tem várias limitações conhecidas (a partir de Windows 10, versão 2004):

  • Drivers de exibição indiretos (por exemplo, Miracast, adaptadores de vídeo USB, drivers de software) não podem ser abordados no momento. DisplayManager.CreateDisplayDevice falhará quando passar um adaptador de exibição indireto.

Código de exemplo

Para obter um aplicativo de exemplo, consulte Exemplo de compositor personalizado Windows.Devices.Display.Core.