Suporte à sobreposição de hardware

Uma sobreposição de hardware é uma área dedicada de memória de vídeo que pode ser sobreposta na superfície primária. Nenhuma cópia é executada quando a sobreposição é exibida. A operação de sobreposição é executada em hardware, sem modificar os dados na superfície primária.

O uso de sobreposições de hardware para reprodução de vídeo era comum em versões anteriores do Windows, pois as sobreposições são eficientes para conteúdo de vídeo com uma alta taxa de quadros. A partir do Windows 7, o Direct3D 9 dá suporte a sobreposições de hardware. Esse suporte destina-se principalmente à reprodução de vídeo e difere em alguns aspectos das APIs anteriores do DirectDraw:

  • A sobreposição não pode ser reduzida, espelhada ou desinterlaceada.
  • Não há suporte para chaves de cor de origem e mesclagem alfa.
  • As sobreposições poderão ser ampliadas se o hardware de sobreposição der suporte a ela. Caso contrário, não há suporte para alongamento. Na prática, nem todos os drivers gráficos dão suporte ao alongamento.
  • Cada dispositivo dá suporte a no máximo uma sobreposição.
  • A sobreposição é executada usando uma chave de cor de destino, mas o runtime do Direct3D seleciona automaticamente a cor e desenha o retângulo de destino. O Direct3D controla automaticamente a posição da janela e atualiza a posição de sobreposição sempre que o PresentEx é chamado.

Criando uma superfície de sobreposição de hardware

Para consultar o suporte à sobreposição, chame IDirect3D9::GetDeviceCaps. Se o driver der suporte à sobreposição de hardware, o sinalizador D3DCAPS_OVERLAY será definido no D3DCAPS9. Membro Caps .

Para descobrir se há suporte para um formato de sobreposição específico para um determinado modo de exibição, chame IDirect3D9ExOverlayExtension::CheckDeviceOverlayType.

Para criar a sobreposição, chame IDirect3D9Ex::CreateDeviceEx e especifique o efeito de troca D3DSWAPEFFECT_OVERLAY . O buffer de fundo poderá usar um formato não RGB se o hardware der suporte a ele.

As superfícies de sobreposição têm as seguintes limitações:

  • O aplicativo não pode criar mais de uma cadeia de troca de sobreposição.
  • A sobreposição deve ser usada no modo de janela. Ele não pode ser usado no modo de tela inteira.
  • O efeito de troca de sobreposição deve ser usado com a interface IDirect3DDevice9Ex . Não há suporte para IDirect3DDevice9.
  • Não é possível usar várias amostras.
  • Não há suporte para os sinalizadores D3DPRESENT_DONOTFLIP e D3DPRESENT_FLIPRESTART .
  • As estatísticas de apresentação não estão disponíveis para a superfície de sobreposição.

Se o hardware não der suporte à ampliação, é recomendável criar uma cadeia de troca tão grande quanto o modo de exibição, para que a janela possa ser redimensionada para qualquer dimensão. Recriar a cadeia de troca não é uma maneira ideal de lidar com o redimensionamento da janela, pois ela pode causar artefatos de renderização graves. Além disso, devido à maneira como a GPU gerencia a memória de sobreposição, recriar a cadeia de troca pode potencialmente fazer com que um aplicativo fiquem sem memória de vídeo.

Novos sinalizadores de D3DPRESENT_PARAMETERS

Os sinalizadores de D3DPRESENT_PARAMETERS a seguir são definidos para criar sobreposições.

Sinalizador Descrição
D3DPRESENTFLAG_OVERLAY_LIMITEDRGB O intervalo RGB é de 16 a 235. O padrão é 0 a 255.
Requer a funcionalidade de D3DOVERLAYCAPS_LIMITEDRANGERGB .
D3DPRESENTFLAG_OVERLAY_YCbCr_BT709 As cores YUV usam a definição BT.709. O padrão é BT.601.
Requer a funcionalidade de D3DOVERLAYCAPS_YCbCr_BT709 .
D3DPRESENTFLAG_OVERLAY_YCbCr_xvYCC Gere os dados usando YCbCr estendido (xvYCC).
Requer a funcionalidade de D3DOVERLAYCAPS_YCbCr_BT601_xvYCC ou D3DOVERLAYCAPS_YCbCr_BT709_xvYCC .

 

Usando sobreposições de hardware

Para exibir a superfície de sobreposição, o aplicativo chama IDirect3DDevice9Ex::P resentEx. O runtime do Direct3D desenha automaticamente a chave de cor de destino.

Os sinalizadores PresentEx a seguir são definidos para sobreposições.

Sinalizador Descrição
D3DPRESENT_UPDATECOLORKEY Defina esse sinalizador se a composição do DWM (Gerenciador de Janelas da Área de Trabalho) estiver desabilitada. Esse sinalizador faz com que o Direct3D redesenhe a chave de cor.
Se o DWM estiver habilitado, esse sinalizador não será necessário, pois o Direct3D desenha a chave de cor uma vez na superfície que o DWM usa para redirecionamento.
D3DPRESENT_HIDEOVERLAY Oculta a sobreposição.
D3DPRESENT_UPDATEOVERLAYONLY Atualizações a sobreposição sem alterar o conteúdo.
Esse sinalizador será útil se a janela for movida enquanto o vídeo estiver em pausa.

 

Um aplicativo deve estar preparado para lidar com os seguintes casos:

  • Se outro aplicativo estiver usando a sobreposição, PresentEx retornará D3DERR_NOTAVAILABLE.
  • Se a janela for movida para outro monitor, o aplicativo deverá recriar a cadeia de troca. Caso contrário, se o aplicativo chamar PresentEx para exibir a sobreposição em um monitor diferente, PresentEx retornará D3DERR_INVALIDDEVICE.
  • Se o modo de exibição for alterado, o Direct3D tentará restaurar a sobreposição. Se o novo modo não der suporte à sobreposição, PresentEx retornará D3DERR_UNSUPPORTEDOVERLAY.

Código de exemplo

O exemplo a seguir mostra como criar uma superfície de sobreposição.

const UINT VIDEO_WIDTH = 256;
const UINT VIDEO_HEIGHT = 256;

HRESULT CreateHWOverlay(
    HWND hwnd, 
    IDirect3D9Ex *pD3D, 
    IDirect3DDevice9Ex **ppDevice
    )
{
    *ppDevice = NULL;

    D3DCAPS9                caps;
    ZeroMemory(&caps, sizeof(caps));

    HRESULT hr = pD3D->GetDeviceCaps(
        D3DADAPTER_DEFAULT,
        D3DDEVTYPE_HAL,
        &caps
        );

    if (FAILED(hr))
    {
        return hr;
    }

    // Check if overlay is supported.
    if (!(caps.Caps & D3DCAPS_OVERLAY))
    {
        return D3DERR_UNSUPPORTEDOVERLAY;
    }

    D3DOVERLAYCAPS          overlayCaps = { 0 };

    IDirect3DDevice9Ex           *pDevice = NULL;
    IDirect3D9ExOverlayExtension *pOverlay = NULL;

    // Check specific overlay capabilities.
    hr = pD3D->QueryInterface(IID_PPV_ARGS(&pOverlay));

    if (SUCCEEDED(hr))
    {
        hr = pOverlay->CheckDeviceOverlayType(
            D3DADAPTER_DEFAULT,
            D3DDEVTYPE_HAL,
            VIDEO_WIDTH,
            VIDEO_HEIGHT,
            D3DFMT_X8R8G8B8,
            NULL,
            D3DDISPLAYROTATION_IDENTITY,
            &overlayCaps
            );
    }

    // Create the overlay.
    if (SUCCEEDED(hr))
    {

        DWORD flags =   D3DCREATE_FPU_PRESERVE | 
                        D3DCREATE_MULTITHREADED | 
                        D3DCREATE_SOFTWARE_VERTEXPROCESSING;

        
        D3DPRESENT_PARAMETERS   pp = { 0 };

        pp.BackBufferWidth = overlayCaps.MaxOverlayDisplayWidth;
        pp.BackBufferHeight = overlayCaps.MaxOverlayDisplayHeight;
        pp.BackBufferFormat = D3DFMT_X8R8G8B8;
        pp.SwapEffect = D3DSWAPEFFECT_OVERLAY;
        pp.hDeviceWindow = hwnd;
        pp.Windowed = TRUE;
        pp.Flags = D3DPRESENTFLAG_VIDEO;
        pp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
        pp.PresentationInterval       = D3DPRESENT_INTERVAL_ONE;

        hr = pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
            NULL, flags, &pp, NULL, &pDevice);
    }

    if (SUCCEEDED(hr))
    {
        (*ppDevice) = pDevice;
        (*ppDevice)->AddRef();
    }

    SafeRelease(&pD3D);
    SafeRelease(&pDevice);
    SafeRelease(&pOverlay);
    return hr;
}

APIs de vídeo direct3D