Use o DirectX com cores avançadas em exibições de intervalo dinâmico alto/padrão

Este tópico mostra como usar o DirectX com cenários de Cor Avançada, incluindo alto alcance dinâmico (HDR), ampla gama de cores (WCG) com gerenciamento automático de cores do sistema e alta profundidade de bits. Os monitores de computador pessoal (PC) premium com pelo menos um dos aprimoramentos acima estão cada vez mais comuns, fornecendo fidelidade de cores significativamente maior do que os monitores tradicionais de faixa dinâmica padrão (SDR).

Neste tópico, você terá uma visão geral dos principais conceitos técnicos por trás do suporte a Cor Avançada do Windows. Você aprenderá os requisitos e as instruções para renderizar conteúdo HDR, WCG e DirectX de alta profundidade de bits em uma dessas telas. Se tiver um aplicativo gerenciado por cores (por exemplo, usando perfis ICC), você aprenderá como o gerenciamento automático de cores permite uma melhor precisão de cores para seus cenários.

Introdução à Cor Avançada no Windows

Cor Avançada é um termo abrangente das tecnologias do sistema operacional (SO) para monitores com fidelidade de cores significativamente maior do que os monitores padrão. Os recursos estendidos predominantes são descritos nas seções abaixo. As capacidades de Cor Avançada foram introduzidas pela primeira vez para exibições HDR com o Windows 10, versão 1709 (Fall Creators Update) e para exibições SDR especialmente provisionadas com o Windows 11, versão 22H2 (10.0; Build 22621).

Alto alcance dinâmico

A faixa dinâmica refere-se à diferença entre a luminância máxima e mínima em uma cena; isso geralmente é medido em nits (candelas por centímetro quadrado). As cenas do mundo real, como este pôr do sol, geralmente têm faixas dinâmicas de 10 ordens de magnitude de luminância; o olho humano pode discernir um alcance ainda maior após a adaptação.

imagem de um pôr do sol com brilho e pontos mais escuros na cena rotulados

Desde o Direct3D 9, os mecanismos gráficos têm sido capazes de renderizar internamente suas cenas com esse nível de fidelidade fisicamente precisa. No entanto, uma tela de alcance dinâmico padrão típica pode reproduzir apenas um pouco mais de 3 ordens de magnitude de luminância e, portanto, qualquer conteúdo renderizado em HDR teve que ser mapeado (compactado) na faixa limitada da tela. Novos monitores HDR, incluindo aqueles que estão em conformidade com o padrão HDR10 (BT.2100), rompem essa limitação; por exemplo, as telas auto-emissivas de alta qualidade podem atingir mais de 6 ordens de magnitude.

Ampla gama de cores

A gama de cores refere-se ao intervalo e à saturação de matizes que uma tela pode reproduzir. As cores naturais mais saturadas que o olho humano pode perceber consistem em luz pura e monocromática, como a produzida por lasers. No entanto, as telas convencionais do consumidor geralmente podem reproduzir cores apenas dentro da gama sRGB, que representa apenas cerca de 35% de todas as cores perceptíveis por humanos. O diagrama abaixo é uma representação do "locus espectral" humano, ou todas as cores perceptíveis (em um determinado nível de luminância), onde o triângulo menor é a gama sRGB.

diagrama do locus espectral humano e gama sRGB

Os monitores de PC profissionais de última geração têm gamas de cores com suporte há muito tempo e que são significativamente mais amplas do que o sRGB, como Adobe RGB e DCI-P3, que cobrem cerca de metade das cores perceptíveis por humanos. E esses monitores de ampla gama estão se tornando mais comuns.

Gerenciamento automático de cores do sistema

O gerenciamento de cores é a tecnologia e a prática de garantir uma reprodução de cores precisa e consistente em todos os dispositivos. Se você for criador de conteúdo digital, será crucial que as cores em seu conteúdo visual, como uma foto, uma imagem de produto ou um logotipo, apareçam da mesma forma em sua tela e na ampla variedade de dispositivos digitais de seu público.

O Windows fornece APIs de suporte ao gerenciamento de cores desde o Windows 2000 com o ICM (Gerenciamento de Cores de Imagem) e APIs WCS (Sistema de Cores do Windows). posteriores. No entanto, essas APIs eram apenas auxiliares para aplicativos que desejavam/exigiam fazer gerenciamento de cores; enquanto a maioria dos aplicativos e conteúdo digital simplesmente assumia o espaço de cores sRGB padrão da indústria e nunca eram gerenciados por cores pelo sistema operacional. Essa era uma suposição razoável no passado, mas telas de ampla gama de alta qualidade estão se tornando muito mais comuns.

As novas versões do Windows dão suporte ao gerenciamento automático de cores do sistema; isso garante que todas as cores em todos os aplicativos do Windows, sejam elas com reconhecimento de cores ou não, apareçam com precisão e consistência em todos os monitores com suporte.

Observação

O gerenciamento automático de cores não é uma propriedade do hardware de exibição; em vez disso, é um recurso do Windows para oferecer suporte adequado a monitores com gamas de cores maiores do que sRGB.

Precisão profunda/profundidade de bits

A precisão numérica, ou profundidade de bits, refere-se à quantidade de informações usadas para identificar cores exclusivamente. Maior profundidade de bits significa que você pode distinguir entre cores muito semelhantes sem artefatos como faixas. Os monitores de PC convencionais dão suporte a 8 bits por canal de cor, enquanto o olho humano requer pelo menos 10 a 12 bits de precisão para evitar distorções perceptíveis.

imagem de moinhos de vento em um canal simulado de 2 bits por cor versus 8 bits por canal

Antes da Cor Avançada, o DWM (Gerenciador de Janelas da Área de Trabalho) restringia os aplicativos em janelas para gerar conteúdo em apenas 8 bits por canal de cor, mesmo que o monitor desse suporte a uma profundidade de bits maior. Quando a Cor Avançada está habilitada, o DWM executa sua composição usando o ponto flutuante de meia precisão IEEE (FP16), eliminando quaisquer gargalos e permitindo que a precisão total do monitor seja usada.

Arquitetura do sistema de Cor Avançada do Windows

As informações nesta seção são opcionais para criar aplicativos de Cor Avançada, mas é útil entender como a tecnologia funciona para otimizar a renderização e o comportamento do seu aplicativo.

Nesta seção, usaremos um diagrama simplificado para descrever os componentes relevantes da pilha de gráficos do Windows:

diagrama de blocos da pilha de gráficos do Windows: aplicativo para DWM para o kernel do monitor

Windows existentes: monitores de 8 bits/sRGB

Durante décadas, os monitores de consumidor e a pilha de gráficos do Windows foram baseadas em conteúdo sRGB de 8 bits por canal (24 bits por pixel). Os aplicativos que usam APIs gráficas, como DirectX, podem executar renderização interna usando altas profundidades de bits e espaços de cores estendidos; no entanto, o sistema operacional dava suporte somente a inteiros de 8 bits com sRGB implícito e nenhum gerenciamento de cores do sistema:

diagrama de blocos da pilha de monitor SDR: limitado a sRGB, 8 bits, sem gerenciamento de cores

Isso significava que quaisquer dados de cores adicionais renderizados por um aplicativo seriam perdidos ao serem exibidos; e que o aplicativo teve que realizar o gerenciamento de cores para garantir uma reprodução precisa em uma tela.

Windows 10, versão 1703: monitores HDR com Cor Avançada

O Windows 10, versão 1703 introduziu a primeira versão dos recursos de Cor Avançada para monitores HDR. Isso exigiu vários avanços significativos na pilha de gráficos do sistema operacional:

  • Suporte à sinalização de monitor HDR
  • Composição do sistema usando um espaço de cores canônico de alta profundidade de bits
  • Gerenciamento automático de cores do sistema

diagrama de blocos da pilha do monitor HDR: FP16, scRGB, com gerenciamento automático de cores

Cada avanço é abordado nas subseções abaixo. O resultado líquido é que os dados de cores estendidos do aplicativo agora são preservados corretamente pelo sistema operacional e reproduzidos com precisão em monitores HDR.

Suporte à sinalização de monitor HDR

A sinalização HDR em conectores de vídeo, como DisplayPort e HDMI, usa principalmente precisão de 10 bits por canal (ou maior) e o espaço de cores BT.2100 ST.2084. O kernel do monitor, o driver do monitor e o hardware de GPU subjacente precisam dar suporte à detecção, seleção e condução desse modo de sinalização.

Composição do sistema usando um espaço de cores canônico de alta profundidade de bits

O espaço de cores BT.2100 ST.2084 é um padrão eficiente para codificar cores HDR, mas não é adequado para muitas operações de renderização e composição (mesclagem). Também queremos preparar o sistema operacional para o futuro para dar suporte a tecnologias e espaços de cores muito além do BT.2100, que cobre menos de 2/3 das cores visíveis por humanos. Por fim, sempre que possível, queremos minimizar o consumo de recursos da GPU para melhorar a potência e o desempenho.

Quando no modo HDR, o DWM (Gerenciador de Janelas da Área de Trabalho) usa um CCCS (espaço de cores de composição canônica) definido como:

  • Espaço de cores scRGB (primários BT.709/sRGB com gama linear)
  • Meia precisão IEEE (profundidade de bits FP16)

Isso fornece um bom equilíbrio entre todas as metas acima. O CCCS permite valores de cor fora do intervalo numérico [0, 1]; dada a faixa de valores FP16 válidos, ela pode representar ordens de magnitude a mais de cores do que o alcance visual humano natural, incluindo valores de luminância acima de 5 milhões de nits. O FP16 tem excelente precisão para operações de mistura de gama linear, mas custa metade do consumo de memória da GPU e largura de banda da precisão única tradicional (FP32) sem perda de qualidade perceptível.

Gerenciamento automático de cores do sistema

O Windows é um ambiente multitarefa em que o usuário pode executar qualquer número de aplicativos SDR e HDR ao mesmo tempo com janelas sobrepostas. Portanto, é crucial que todos os tipos de conteúdo pareçam corretos e com qualidade máxima ao serem enviados para uma tela; por exemplo, um aplicativo de produtividade sRGB (SDR) com uma janela de vídeo BT.2100 ST.2084 (HDR) sendo reproduzida sobre ele.

Quando no modo HDR, o Windows executa operações de gerenciamento de cores em dois estágios:

  1. O DWM converte cada aplicativo de seu espaço de cores nativo em CCCS antes da mesclagem.
  2. O kernel do monitor converte o framebuffer do sistema operacional de CCCS para o espaço de cores de formato de transmissão (BT.2100 ST.2084).

diagrama de blocos do gerenciamento automático de cores que ocorre no DWM e no kernel do monitordiagrama de blocos do gerenciamento automático de cores que ocorre no DWM e no kernel do monitor, parte 2

Observação

Em ambos os estágios, a operação de gerenciamento de cores consiste em uma conversão de espaço de cores (matriz e 1DLUT). As cores que excedem a gama de cores de destino do monitor são cortadas numericamente.

Windows 11, versão v: monitores SDR com Cor Avançada

Embora a prevalência de monitores HDR esteja crescendo rapidamente, os monitores SDR continuarão sendo importantes nos próximos anos. O suporte a HDR no Windows 10, versão 1703, também estabeleceu a maior parte das bases necessárias para aprimorar os monitores SDR. O Windows 11, versão 22H2 estende as capacidades de Cor Avançada e do gerenciamento automático de cores para determinados monitores SDR qualificados. O diagrama de blocos gráficos para monitores SDR de Cor Avançada é muito semelhante ao dos HDR:

diagrama de blocos da pilha do monitor SDR AC: FP16, scRGB, com gerenciamento automático de cores

Suporte à sinalização de monitor SDR com alta profundidade de bits

A sinalização subjacente para monitores SDR permanece inalterada, embora o Windows 11, versão 22H2 dê suporte a 10 bits por canal e superior, dependendo das capacidades do monitor.

Composição do sistema usando um espaço de cores canônico de alta profundidade de bits

A funcionalidade Cor Avançada do DWM, incluindo a mesclagem no CCCS, é quase totalmente inalterada em relação aos monitores HDR. A principal diferença é que o DWM usa luminância relativa à exibição com monitores SDR e luminância relativa à cena com monitores HDR. Isso altera a maneira como o conteúdo renderizado de Cor Avançada é interpretado pelo sistema operacional:

Tipo de monitor Comportamento de luminância Como 1.0f é interpretado
SDR Relativo ao monitor Como o nível de branco de referência do monitor
HDR Relativo à cena Como 80 nits (branco de referência nominal)

Gerenciamento automático de cores do sistema

Os recursos de gerenciamento de cores do sistema operacional também permanecem praticamente inalterados em relação aos monitores HDR. A principal diferença é que o kernel do monitor é convertido para o espaço de cores relativo à exibição, conforme definido pelos dados de colorimetria e calibragem do monitor, em vez do espaço de cores padrão BT.2100 ST.2084 para monitores HDR.

Provisionamento de monitor necessário

Os dados precisos de um perfil MHC ICC são necessários para definir a operação de gerenciamento de cores de saída do kernel do monitor. Portanto, somente os monitores SDR que foram especificamente provisionados pelo fabricante ou por um provedor de calibragem de monitor com um perfil válido são elegíveis para o gerenciamento automático de cores. Consulte Comportamento do perfil ICC com Cor Avançada para obter mais informações.

Requisitos do sistema e suporte ao sistema operacional

Windows 10, versão 1709, fornecido inicialmente com suporte a Cor Avançada para monitores HDR. O Windows 11, versão 22H2, adiciona suporte a Cores Avançadas para monitores SDR com dados de provisionamento precisos.

Este tópico pressupõe que seu aplicativo esteja direcionado ao Windows 10, versão 2004 (ou posterior) para monitores HDR e para o Windows 11, versão 22H2 (ou posterior) para monitores SDR.

Exibição

Um monitor de alto alcance dinâmico deve implementar o padrão HDR10 ou BT.2100 ST.2084. A qualidade do monitor HDR pode variar muito, e recomendamos vivamente monitores certificados, como o VESA DisplayHDR. A partir do Windows 11, versão 22H2, o Windows exibe o status de certificação de exibições conhecidas no aplicativo Configurações.

Uma monitor de alcance dinâmico padrão deve ter dados precisos de provisionamento de cores para suporte a Cor Avançada. No Windows 11, versão 22H2, o único método com suporte para substituir esses dados é por meio de um perfil MHC ICC; Além disso, o usuário ou fabricante do monitor deve ter habilitado o gerenciamento automático de cores. Para obter mais informações, consulte Comportamento do perfil ICC com Cor Avançada.

Processador gráfico (GPU)

Para obter a funcionalidade completa de Cor Avançada em monitores SDR e HDR, é necessária uma GPU recente:

  • AMD Radeon RX série 400 (Polaris) ou mais recente
  • NVIDIA GeForce série 10 (Pascal) ou mais recente
  • Intel Core 10ª geração selecionado (Ice Lake) ou mais recente*

Observação

Os chipsets Intel codinome Comet Lake (código de modelo de 5 dígitos) não fornecem funcionalidade completa.

Requisitos de hardware adicionais podem ser aplicados, dependendo dos cenários, incluindo aceleração de codec de hardware (HEVC de 10 bits, VP9 de 10 bits etc.) e suporte a PlayReady (SL3000). Contate o seu fornecedor da sua GPU para obter mais informações específicas.

Driver gráfico (WDDM)

O driver gráfico mais recente disponível é altamente recomendado, seja no Windows Update ou no fornecedor da GPU ou no site do fabricante do computador. Este tópico depende da funcionalidade do driver do WDDM 2.7 (Windows 10, versão 2004) para monitores HDR e do WDDM 3.0 (Windows 11, versão 21H2) para monitores SDR.

APIs de renderização com suporte

O Windows 10 dá suporte a uma ampla variedade de APIs e estruturas de renderização. O suporte avançado a cores depende fundamentalmente da capacidade do seu aplicativo de executar apresentações modernas usando DXGI ou as APIs da Camada Visual.

Portanto, qualquer API de renderização que possa gerar saída para um desses métodos de apresentação pode dar suporte a Cor Avançada. Isso inclui (mas não se limita a) o abaixo.

  • Direct3D 11
  • Direct3D 12
  • Direct2D
  • Win2D
    • Requer o uso das APIs CanvasSwapChain ou CanvasSwapChainPanel de nível inferior.
  • Windows.UI.Input.Inking
    • Dá suporte à renderização de tinta seca personalizada usando DirectX.
  • XAML
    • Dá suporte à reprodução de vídeos HDR usando MediaPlayerElement.
    • Dá suporte à decodificação de imagens JPEG XR usando o elemento Image.
    • Dá suporte à interoperabilidade do DirectX usando SwapChainPanel.

Como lidar com capacidades de exibição dinâmica

O Windows 10 oferece suporte a uma enorme variedade de monitores com capacidade de Cor Avançada, desde painéis integrados com baixo consumo de energia até monitores de jogos e TVs de última geração. Os usuários do Windows esperam que seu aplicativo lide perfeitamente com todas essas variações, incluindo monitores SDR existentes onipresentes.

O Windows 10 fornece controle sobre os recursos HDR e Cor Avançada para o usuário. Seu aplicativo deve detectar a configuração do monitor atual e responder dinamicamente a quaisquer alterações na capacidade. Isso pode ocorrer por vários motivos, por exemplo, porque o usuário habilitou ou desabilitou um recurso, moveu o aplicativo entre diferentes monitores ou o estado de energia do sistema mudou.

Opção 1: AdvancedColorInfo

Observação

A API do Windows Runtime AdvancedColorInfo pode ser usada independentemente da API de renderização, dá suporte à Cor Avançada para monitores SDR e usa eventos para sinalizar quando os recursos são alterados. No entanto, ela está disponível apenas para aplicativos da Plataforma Universal do Windows (UWP); os aplicativos da área de trabalho (que não têm um CoreWindow) não podem usá-la. Para obter mais informações, consulte APIs do Windows Runtime sem suporte em aplicativos da área de trabalho.

Primeiro, obtenha uma instância de AdvancedColorInfo de DisplayInformation::GetAdvancedColorInfo.

Para verificar qual tipo de Cor Avançada está ativo no momento, use a propriedade AdvancedColorInfo::CurrentAdvancedColorKind. Essa é a propriedade mais importante a ser verificada e você deve configurar seu pipeline de renderização e apresentação em resposta ao tipo ativo:

Tipo de cor avançada Capacidades de monitor
SDR Monitor SDR sem capacidades de Cor Avançada
WCG Monitor SDR com alta profundidade de bits e gerenciamento automático de cores
HDR Monitor HDR com todas as capacidades de Cor Avançada

Para verificar quais tipos de Cor Avançada têm suporte, mas não necessariamente ativos, chame AdvancedColorInfo::IsAdvancedColorKindAvailable. Você pode usar essas informações, por exemplo, para solicitar que o usuário navegue até o aplicativo Configurações do Windows para que ele possa habilitar o HDR ou o gerenciamento automático de cores.

Os outros membros de AdvancedColorInfo fornecem informações quantitativas sobre o volume de cor física do painel (luminância e crominância), correspondendo aos metadados HDR estáticos SMPTE ST.2086. Embora o ST.2086 tenha sido originalmente projetado para monitores HDR, essas informações são úteis e estão disponíveis para monitores HDR e SDR. Você deve usar essas informações para configurar o mapeamento de tons e o mapeamento de gama do seu aplicativo.

Para lidar com alterações nos recursos de Cor Avançada, registre-se no evento DisplayInformation::AdvancedColorInfoChanged. Esse evento é gerado se qualquer parâmetro das capacidades de Cor Avançada do monitor for alterado por qualquer motivo.

Manipule esse evento obtendo uma nova instância de AdvancedColorInfo e verificando quais valores foram alterados.

IDXGIOutput6

Observação

A interface da Infraestrutura Gráfica do DirectX IDXGIOutput6 está disponível para qualquer aplicativo que use o DirectX, seja área de trabalho ou UWP (Plataforma Universal do Windows). No entanto, IDXGIOutput6 não dá suporte a exibições SDR com capacidades de Cor Avançada, como gerenciamento automático de cores; ele pode identificar apenas monitores HDR.

Se você estiver escrevendo um aplicativo da área de trabalho Win32 e usando o DirectX para renderizar, use DXGI_OUTPUT_DESC1 para obter as capacidades do monitor. Obtenha uma instância desse struct por meio de IDXGIOutput6::GetDesc1.

Para verificar qual tipo de Cor Avançada está ativo no momento, use a propriedade ColorSpace, que é do tipo DXGI_COLOR_SPACE_TYPE e contém um dos seguintes valores:

DXGI_COLOR_SPACE_TYPE Capacidades de monitor
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 Monitor SDR sem capacidades de Cor Avançada
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 Monitor HDR com todas as capacidades de Cor Avançada

Observação

Os monitores SDR com recursos de cores avançadas também são relatadas como DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; o DXGI não permite distinguir entre os dois tipos.

Observação

O DXGI não permite que você verifique quais tipos de cores avançadas têm suporte, mas não estão ativos no momento.

A maioria dos outros membros de DXGI_OUTPUT_DESC1 fornece informações quantitativas sobre o volume físico de cores do painel (luminância e crominância), correspondendo aos metadados HDR estáticos SMPTE ST.2086. Embora o ST.2086 tenha sido originalmente projetado para monitores HDR, essas informações são úteis e estão disponíveis para monitores HDR e SDR. Você deve usar essas informações para configurar o mapeamento de tons e o mapeamento de gama do seu aplicativo.

Os aplicativos da área de trabalho Win32 não têm um mecanismo nativo para responder às alterações da capacidade de Cor Avançada. Em vez disso, se o aplicativo usar um loop de renderização, você deverá consultar IDXGIFactory1::IsCurrent com cada quadro. Se ele relatar FALSE, você deverá obter um novo DXGI_OUTPUT_DESC1 e verificar quais valores foram alterados.

Além disso, a bomba de mensagens do Win32 deve lidar com a mensagem WM_SIZE, que indica que seu aplicativo pode ter sido movido entre monitores diferentes.

Observação

Para obter um novo DXGI_OUTPUT_DESC1, você deve obter o monitor atual. No entanto, você não deve chamar IDXGISwapChain::GetContainingOutput. Isso ocorre porque as cadeias de troca retornam uma saída DXGI obsoleta quando DXGIFactory::IsCurrent é falso; e recriar a cadeia de troca para obter uma saída atual resulta em uma tela temporariamente preta. Em vez disso, recomendamos que você enumere os limites de todas as saídas DXGI e determine qual delas tem a maior interseção com os limites da janela do aplicativo.

O código de exemplo a seguir vem do aplicativo de exemplo HDR do Direct3D 12 no GitHub.

// Retrieve the current default adapter.
ComPtr<IDXGIAdapter1> dxgiAdapter;
ThrowIfFailed(m_dxgiFactory->EnumAdapters1(0, &dxgiAdapter));

// Iterate through the DXGI outputs associated with the DXGI adapter,
// and find the output whose bounds have the greatest overlap with the
// app window (i.e. the output for which the intersection area is the
// greatest).

UINT i = 0;
ComPtr<IDXGIOutput> currentOutput;
ComPtr<IDXGIOutput> bestOutput;
float bestIntersectArea = -1;

while (dxgiAdapter->EnumOutputs(i, &currentOutput) != DXGI_ERROR_NOT_FOUND)
{
    // Get the retangle bounds of the app window
    int ax1 = m_windowBounds.left;
    int ay1 = m_windowBounds.top;
    int ax2 = m_windowBounds.right;
    int ay2 = m_windowBounds.bottom;

    // Get the rectangle bounds of current output
    DXGI_OUTPUT_DESC desc;
    ThrowIfFailed(currentOutput->GetDesc(&desc));
    RECT r = desc.DesktopCoordinates;
    int bx1 = r.left;
    int by1 = r.top;
    int bx2 = r.right;
    int by2 = r.bottom;

    // Compute the intersection
    int intersectArea = ComputeIntersectionArea(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2);
    if (intersectArea > bestIntersectArea)
    {
        bestOutput = currentOutput;
        bestIntersectArea = static_cast<float>(intersectArea);
    }

    i++;
}

// Having determined the output (display) upon which the app is primarily being 
// rendered, retrieve the HDR capabilities of that display by checking the color space.
ComPtr<IDXGIOutput6> output6;
ThrowIfFailed(bestOutput.As(&output6));

DXGI_OUTPUT_DESC1 desc1;
ThrowIfFailed(output6->GetDesc1(&desc1));

Configuração de sua cadeia de troca do DirectX

Depois de determinar que a tela atualmente dá suporte a recursos de Cor Avançada, configure sua cadeia de troca da seguinte maneira.

Usar um efeito de modelo de apresentação de inversão

Ao criar sua cadeia de troca usando um dos métodos CreateSwapChainFor[Hwnd|Composition|CoreWindow], você deverá usar o modelo de inversão DXGI selecionando a opção DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL ou DXGI_SWAP_EFFECT_FLIP_DISCARD, o que torna sua cadeia de troca qualificada para processamento de cores avançadas do DWM e várias otimizações de tela inteira. Para obter mais informações, consulte Para obter o melhor desempenho, use o modelo de inversão DXGI.

Opção 1. Usar o formato de pixel FP16 e o espaço de cores scRGB

O Windows 10 oferece suporte a duas combinações principais de formato de pixel e espaço de cores para Cor Avançada. Selecione um com base nos requisitos específicos do seu aplicativo.

Recomendamos que os aplicativos de uso geral usem a Opção 1. É a única opção que funciona para todos os tipos de monitores de Cor Avançada, conteúdo e APIS de renderização. Ao criar sua cadeia de troca, especifique DXGI_FORMAT_R16G16B16A16_FLOAT em seu DXGI_SWAP_CHAIN_DESC1. Por padrão, uma cadeia de troca criada com um formato de pixel de ponto flutuante é tratada como se usasse o espaço de cores DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709. Esse é o mesmo formato de pixel e espaço de cores usado pelo DWM.

Essa combinação fornece o intervalo numérico e a precisão para especificar qualquer cor fisicamente possível e executar processamento arbitrário, incluindo mesclagem.

No entanto, essa opção consome 64 bits por pixel, o que dobra a largura de banda da GPU e o consumo de memória em comparação com os formatos tradicionais de pixel UINT8. Além disso, o scRGB usa valores numéricos que estão fora do intervalo normalizado [0, 1] para representar cores que estão fora da gama sRGB e/ou maiores que 80 nits de luminância. Por exemplo, scRGB (1.0, 1.0, 1.0) codifica o branco D65 padrão a 80 nits; mas scRGB (12.5, 12.5, 12.5) codifica o mesmo branco D65 a 1000 nits muito mais brilhantes. Algumas operações gráficas exigem um intervalo numérico normalizado e você deve modificar a operação ou normalizar novamente os valores de cor.

A maneira como os valores de luminância são interpretados com essa opção difere entre as exibições SDR e HDR; veja abaixo.

Opção 2: use o formato de pixel UINT10/RGB10 e o espaço de cores HDR10/BT.2100

A Opção 2 é uma otimização de desempenho que só estará disponível se o app atender a todas as seguintes condições:

  • Direciona para um monitor HDR
  • Usa Direct3D 12 ou Direct3D 11
  • A cadeia de troca não requer mistura com alfa/transparência

Se o aplicativo não atender a todas essas condições, use a Opção 1.

Mas se seu aplicativo se qualificar para a opção 2, isso poderá fornecer melhor desempenho se seu aplicativo estiver consumindo conteúdo codificado em HDR10, como um player de vídeo, ou se ele for usado principalmente em cenários de tela inteira, como um jogo. Ao criar sua cadeia de troca, você deve considerar especificar DXGI_FORMAT_R10G10B10A2_UNORM em DXGI_SWAP_CHAIN_DESC1. Por padrão, isso é tratado como usando o espaço de cores sRGB; portanto, você deve chamar explicitamente IDXGISwapChain3::SetColorSpace1 e definir como seu espaço de cores DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, também conhecido como HDR10/BT.2100.

Essa opção consome os mesmos 32 bits por pixel que os formatos de pixel SDR UINT8 tradicionais. Além disso, em determinadas GPUs, isso elimina parte do processamento necessário para converter o conteúdo para o formato de transmissão HDR10.

Usando uma cadeia de troca de Cor Avançada quando o monitor está no modo SDR

Você pode usar uma cadeia de troca de Cor Avançada mesmo se o Monitor não for compatível com todos os recursos de Cor Avançada. Nesses casos, o DWM (Gerenciador de Janelas da Área de Trabalho) converterá seu conteúdo para se adequar aos recursos do monitor executando o recorte numérico. Por exemplo, se você renderizar para uma cadeia de troca scRGB FP16 e direcionar um monitor padrão, tudo fora do intervalo numérico [0, 1] será recortado.

Esse comportamento de conversão descendente também ocorrerá se a janela do aplicativo estiver abrangendo dois ou mais monitores com diferentes recursos de Cor Avançada. AdvancedColorInfo e IDXGIOutput6 são abstraídos para relatar apenas as características do monitor principal (principal sendo definido como o monitor que contém o centro da janela).

Corresponder o branco de referência do seu aplicativo ao nível de branco de referência do SDR do sistema operacional

Observação

O branco de referência aplica-se apenas a monitores HDR; para monitores SDR Advanced Color, (1.0, 1.0, 1.0) sempre significa a luminância de branco máxima que o monitor pode reproduzir.

Em muitos cenários, seu aplicativo desejará renderizar conteúdo SDR e HDR; por exemplo, renderizar legendas ou controles de transporte em vídeo HDR ou interface do usuário em uma cena de jogo. É importante entender o conceito de nível de branco de referência de SDR para garantir que seu conteúdo de SDR pareça correto em um monitor HDR. O branco de referência indica o brilho no qual um objeto branco difuso (como uma folha de papel ou, às vezes, uma interface do usuário) aparece em uma cena HDR. Como os valores de cor HDR têm brilho relativo à cena, um valor de cor específico deve ser exibido em um nível de luminância absoluto e não em relação ao valor máximo possível do painel. Por exemplo, scRGB (1.0, 1.0, 1.0) e HDR10 (497, 497, 497) codificam exatamente o branco D65 com luminância de 80 nits. O Windows permite que o usuário ajuste o nível de branco de referência SDR de acordo com sua preferência; essa é a luminância em que o Windows renderizará sRGB (1.0, 1.0, 1.0). Em monitores HDR de desktop, os níveis de branco de referência SDR são normalmente definidos para cerca de 200 nits.

Seu aplicativo HDR deve permitir que o usuário defina o nível de branco de referência desejado ou leia o valor configurado pelo sistema. Você deve mapear seus valores de cor branca difusa em sua cena para o nível de branco de referência SDR. Isso envolve multiplicar o buffer de quadros do aplicativo no espaço de gama linear.

Observação

Em uma tela que dá suporte a um controle de brilho, como em um laptop, o Windows também ajusta a luminância do conteúdo HDR (relativo à cena) para corresponder ao nível de brilho desejado pelo usuário, mas isso é invisível para o aplicativo. A menos que esteja tentando garantir uma reprodução precisa de bits do sinal HDR, geralmente você poderá ignorar isso.

Se o aplicativo sempre renderizar SDR e HDR em superfícies separadas e depender da composição do sistema operacional, o Windows executará automaticamente o ajuste correto para aumentar o conteúdo SDR para o nível de branco desejado. Por exemplo, se o aplicativo usar XAML e renderizar conteúdo HDR em seu próprio SwapChainPanel.

No entanto, se o aplicativo executar sua própria composição de conteúdo SDR e HDR em uma única superfície, você será responsável por executar o ajuste do nível de branco de referência do SDR por conta própria. Caso contrário, o conteúdo do SDR pode parecer muito escuro em condições típicas de exibição da área de trabalho. Primeiro, você deve obter o nível de branco de referência de SDR atual e, em seguida, ajustar os valores de cor de qualquer conteúdo de SDR que esteja renderizando.

Etapa 1. Obter o nível de branco de referência SDR atual

Você pode obter o nível de branco de referência de SDR atual de uma destas maneiras:

Etapa 2. Ajustar os valores de cor do conteúdo SDR

O Windows define o nível de branco de referência nominal ou padrão em 80 nits. Portanto, se você renderizasse um branco sRGB padrão (1.0, 1.0, 1.0) para uma cadeia de troca FP16, ela seria reproduzida com luminância de 80 nits. Para corresponder ao nível de branco de referência real definido pelo usuário, você deve ajustar o conteúdo SDR de 80 nits para o nível especificado por meio de AdvancedColorInfo.SdrWhiteLevelInNits.

Se você estiver renderizando usando FP16 e scRGB, ou qualquer espaço de cores que use gama linear (1.0), basta multiplicar o valor de cor SDR por AdvancedColorInfo.SdrWhiteLevelInNits / 80. Se você estiver usando Direct2D, haverá uma constante predefinida D2D1_SCENE_REFERRED_SDR_WHITE_LEVEL, que tem um valor 80.

D2D1_VECTOR_4F inputColor; // Input SDR color value.
D2D1_VECTOR_4F outputColor; // Output color adjusted for SDR white level.
auto acInfo = ...; // Obtain an AdvancedColorInfo.

float sdrAdjust = acInfo->SdrWhiteLevelInNits / D2D1_SCENE_REFERRED_SDR_WHITE_LEVEL;

// Normally in DirectX, color values are manipulated in shaders on GPU textures.
// This example performs scaling on a CPU color value.
outputColor.r = inputColor.r * sdrAdjust; // Assumes linear gamma color values.
outputColor.g = inputColor.g * sdrAdjust;
outputColor.b = inputColor.b * sdrAdjust;
outputColor.a = inputColor.a;

Se você estiver renderizando usando um espaço de cores gama não linear, como HDR10, executar o ajuste do nível de branco SDR será mais complexo. Se você estiver escrevendo seu próprio sombreador de pixel, considere converter em gama linear para aplicar o ajuste.

Adapte o conteúdo HDR aos recursos da tela usando o mapeamento de tons

Os monitores HDR e de Cor Avançada variam muito em termos de capacidades. Por exemplo, na luminância mínima e máxima e na gama de cores que eles são capazes de reproduzir. Em muitos casos, o conteúdo HDR conterá cores que excedem as capacidades do monitor. Para obter a melhor qualidade de imagem, é importante que você execute o mapeamento de tons HDR, essencialmente compactando a gama de cores para caber na tela, preservando melhor a intenção visual do conteúdo.

O parâmetro único mais importante a ser adaptado é a luminância máxima, também conhecida como MaxCLL (nível de luz do conteúdo); mapeadores de tons mais sofisticados também adaptarão a luminância mínima (MinCLL) e/ou cores primárias.

Etapa 1. Obtenha as capacidades de volume de cores do monitor

Aplicativos da UWP (Plataforma Universal do Windows)

Use AdvancedColorInfo para obter o volume de cores da exibição.

Aplicativos DirectX Win32 (área de trabalho)

Use DXGI_OUTPUT_DESC1 para obter o volume de cores do monitor.

Etapa 2. Obter as informações de volume de cores do conteúdo

Dependendo de onde veio o conteúdo HDR, existem várias maneiras possíveis de determinar suas informações de luminância e gama de cores. Determinados arquivos de vídeo e imagem HDR contêm metadados SMPTE ST.2086. Se o conteúdo foi renderizado dinamicamente, você poderá extrair informações da cena dos estágios internos de renderização, por exemplo, a fonte de luz mais brilhante em uma cena.

Uma solução mais geral, mas computacionalmente cara, é executar um histograma ou outra passagem de análise no quadro renderizado. O aplicativo de exemplo de renderização de imagem colorida avançada do Direct2D no GitHub demonstra como fazer isso usando o Direct2D; os trechos de código mais relevantes estão incluídos abaixo:

// Perform histogram pipeline setup; this should occur as part of image resource creation.
// Histogram results in no visual output but is used to calculate HDR metadata for the image.
void D2DAdvancedColorImagesRenderer::CreateHistogramResources()
{
    auto context = m_deviceResources->GetD2DDeviceContext();

    // We need to preprocess the image data before running the histogram.
    // 1. Spatial downscale to reduce the amount of processing needed.
    DX::ThrowIfFailed(
        context->CreateEffect(CLSID_D2D1Scale, &m_histogramPrescale)
        );

    DX::ThrowIfFailed(
        m_histogramPrescale->SetValue(D2D1_SCALE_PROP_SCALE, D2D1::Vector2F(0.5f, 0.5f))
        );

    // The right place to compute HDR metadata is after color management to the
    // image's native colorspace but before any tonemapping or adjustments for the display.
    m_histogramPrescale->SetInputEffect(0, m_colorManagementEffect.Get());

    // 2. Convert scRGB data into luminance (nits).
    // 3. Normalize color values. Histogram operates on [0-1] numeric range,
    //    while FP16 can go up to 65504 (5+ million nits).
    // Both steps are performed in the same color matrix.
    ComPtr<ID2D1Effect> histogramMatrix;
    DX::ThrowIfFailed(
        context->CreateEffect(CLSID_D2D1ColorMatrix, &histogramMatrix)
        );

    histogramMatrix->SetInputEffect(0, m_histogramPrescale.Get());

    float scale = sc_histMaxNits / sc_nominalRefWhite;

    D2D1_MATRIX_5X4_F rgbtoYnorm = D2D1::Matrix5x4F(
        0.2126f / scale, 0, 0, 0,
        0.7152f / scale, 0, 0, 0,
        0.0722f / scale, 0, 0, 0,
        0              , 0, 0, 1,
        0              , 0, 0, 0);
    // 1st column: [R] output, contains normalized Y (CIEXYZ).
    // 2nd column: [G] output, unused.
    // 3rd column: [B] output, unused.
    // 4th column: [A] output, alpha passthrough.
    // We explicitly calculate Y; this deviates from the CEA 861.3 definition of MaxCLL
    // which approximates luminance with max(R, G, B).

    DX::ThrowIfFailed(histogramMatrix->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, rgbtoYnorm));

    // 4. Apply a gamma to allocate more histogram bins to lower luminance levels.
    ComPtr<ID2D1Effect> histogramGamma;
    DX::ThrowIfFailed(
        context->CreateEffect(CLSID_D2D1GammaTransfer, &histogramGamma)
        );

    histogramGamma->SetInputEffect(0, histogramMatrix.Get());

    // Gamma function offers an acceptable tradeoff between simplicity and efficient bin allocation.
    // A more sophisticated pipeline would use a more perceptually linear function than gamma.
    DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_RED_EXPONENT, sc_histGamma));
    // All other channels are passthrough.
    DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_GREEN_DISABLE, TRUE));
    DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_BLUE_DISABLE, TRUE));
    DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_ALPHA_DISABLE, TRUE));

    // 5. Finally, the histogram itself.
    HRESULT hr = context->CreateEffect(CLSID_D2D1Histogram, &m_histogramEffect);
    
    if (hr == D2DERR_INSUFFICIENT_DEVICE_CAPABILITIES)
    {
        // The GPU doesn't support compute shaders and we can't run histogram on it.
        m_isComputeSupported = false;
    }
    else
    {
        DX::ThrowIfFailed(hr);
        m_isComputeSupported = true;

        DX::ThrowIfFailed(m_histogramEffect->SetValue(D2D1_HISTOGRAM_PROP_NUM_BINS, sc_histNumBins));

        m_histogramEffect->SetInputEffect(0, histogramGamma.Get());
    }
}

// Uses a histogram to compute a modified version of MaxCLL (ST.2086 max content light level).
// Performs Begin/EndDraw on the D2D context.
void D2DAdvancedColorImagesRenderer::ComputeHdrMetadata()
{
    // Initialize with a sentinel value.
    m_maxCLL = -1.0f;

    // MaxCLL is not meaningful for SDR or WCG images.
    if ((!m_isComputeSupported) ||
        (m_imageInfo.imageKind != AdvancedColorKind::HighDynamicRange))
    {
        return;
    }

    // MaxCLL is nominally calculated for the single brightest pixel in a frame.
    // But we take a slightly more conservative definition that takes the 99.99th percentile
    // to account for extreme outliers in the image.
    float maxCLLPercent = 0.9999f;

    auto ctx = m_deviceResources->GetD2DDeviceContext();

    ctx->BeginDraw();

    ctx->DrawImage(m_histogramEffect.Get());

    // We ignore D2DERR_RECREATE_TARGET here. This error indicates that the device
    // is lost. It will be handled during the next call to Present.
    HRESULT hr = ctx->EndDraw();
    if (hr != D2DERR_RECREATE_TARGET)
    {
        DX::ThrowIfFailed(hr);
    }

    float *histogramData = new float[sc_histNumBins];
    DX::ThrowIfFailed(
        m_histogramEffect->GetValue(D2D1_HISTOGRAM_PROP_HISTOGRAM_OUTPUT,
            reinterpret_cast<BYTE*>(histogramData),
            sc_histNumBins * sizeof(float)
            )
        );

    unsigned int maxCLLbin = 0;
    float runningSum = 0.0f; // Cumulative sum of values in histogram is 1.0.
    for (int i = sc_histNumBins - 1; i >= 0; i--)
    {
        runningSum += histogramData[i];
        maxCLLbin = i;

        if (runningSum >= 1.0f - maxCLLPercent)
        {
            break;
        }
    }

    float binNorm = static_cast<float>(maxCLLbin) / static_cast<float>(sc_histNumBins);
    m_maxCLL = powf(binNorm, 1 / sc_histGamma) * sc_histMaxNits;

    // Some drivers have a bug where histogram will always return 0. Treat this as unknown.
    m_maxCLL = (m_maxCLL == 0.0f) ? -1.0f : m_maxCLL;
}

Etapa 3. Execute a operação de mapeamento de tons HDR

O mapeamento de tons é inerentemente um processo com perdas e pode ser otimizado para várias métricas perceptivas ou objetivas e, portanto, não há um algoritmo padrão único. O Windows fornece um efeito de mapeador de tons HDR interno como parte do Direct2D, bem como no pipeline de reprodução de vídeo HDR do Media Foundation. Alguns outros algoritmos comumente usados incluem ACES Filmic, Reinhard e ITU-R BT.2390-3 EETF (função de transferência elétrica-elétrica).

Um operador de mapeador de tons Reinhard simplificado é mostrado neste próximo exemplo de código.

// This example uses C++. A typical DirectX implementation would port this to HLSL.
D2D1_VECTOR_4F simpleReinhardTonemapper(
    float inputMax, // Content's maximum luminance in scRGB values, e.g. 1.0 = 80 nits.
    float outputMax, // Display's maximum luminance in scRGB values, e.g. 1.0 = 80 nits.
    D2D1_VECTOR_4F input // scRGB color.
)
{
    D2D1_VECTOR_4F output = input;

    // Vanilla Reinhard normalizes color values to [0, 1].
    // This modification scales to the luminance range of the display.
    output.r /= inputMax;
    output.g /= inputMax;
    output.b /= inputMax;

    output.r = output.r / (1 + output.r);
    output.g = output.g / (1 + output.g);
    output.b = output.b / (1 + output.b);

    output.r *= outputMax;
    output.g *= outputMax;
    output.b *= outputMax;

    return output;
}

Captura de conteúdo de tela HDR e WCG

As APIs que dão suporte à especificação de formatos de pixel, como aqueles no namespace Windows.Graphics.Capture e o método IDXGIOutput5::DuplicateOutput1, fornecem a capacidade de capturar conteúdo HDR e WCG sem perder informações de pixel. Observe que, após a aquisição de quadros de conteúdo, será necessário processamento adicional. Por exemplo, o mapeamento de tom HDR para SDR (por exemplo, cópia de captura de tela SDR para compartilhamento na Internet) e o salvamento de conteúdo com o formato adequado (por exemplo, JPEG XR).

Alterações no gerenciamento de cores herdado e no comportamento do perfil ICC

O gerenciamento de Cor Avançada e o gerenciamento automático de cores cores de monitor consistentes e colorimetricamente precisas para todos os aplicativos, legados e modernos. No entanto, alguns aplicativos podem executar seu próprio gerenciamento de cores explícito usando perfis de cores do International Color Consortium (ICC).

Quando a Cor Avançada está ativa em monitores SDR ou HDR, o comportamento dos perfis ICC do monitor muda de maneiras não compatíveis com versões anteriores. Se seu aplicativo funcionar com perfis ICC de monitor, o Windows oferecerá auxiliares de compatibilidade para garantir que seu aplicativo continue a obter o comportamento correto.

Para obter mais informações sobre as alterações no comportamento do perfil ICC e como você pode adaptar seu aplicativo para maximizar a compatibilidade com a Cor Avançada, consulte Comportamento do perfil ICC com a Cor Avançada.

Recursos adicionais