하드웨어 오버레이 지원

하드웨어 오버레이는 기본 화면에 오버레이할 수 있는 비디오 메모리의 전용 영역입니다. 오버레이가 표시되면 복사가 수행되지 않습니다. 오버레이 작업은 기본 표면의 데이터를 수정하지 않고 하드웨어에서 수행됩니다.

오버레이는 프레임 속도가 높은 비디오 콘텐츠에 효율적이므로 이전 버전의 Windows에서는 비디오 재생에 하드웨어 오버레이를 사용하는 것이 일반적이었습니다. Windows 7부터 Direct3D 9는 하드웨어 오버레이를 지원합니다. 이 지원은 주로 비디오 재생을 위한 것이며, 이전 DirectDraw API와 몇 가지 측면에서 다릅니다.

  • 오버레이는 축소, 미러링 또는 디인터레이할 수 없습니다.
  • 원본 색 키 및 알파 혼합은 지원되지 않습니다.
  • 오버레이 하드웨어가 지원하는 경우 오버레이를 확장할 수 있습니다. 그렇지 않으면 스트레칭이 지원되지 않습니다. 실제로 모든 그래픽 드라이버가 스트레칭을 지원하는 것은 아닙니다.
  • 각 디바이스는 최대 하나의 오버레이를 지원합니다.
  • 오버레이는 대상 색 키를 사용하여 수행되지만 Direct3D 런타임은 자동으로 색을 선택하고 대상 사각형을 그립니다. Direct3D는 창의 위치를 자동으로 추적하고 PresentEx 가 호출 될 때마다 오버레이 위치를 업데이트합니다.

하드웨어 오버레이 Surface 만들기

오버레이 지원을 쿼리하려면 IDirect3D9::GetDeviceCaps를 호출합니다. 드라이버가 하드웨어 오버레이를 지원하는 경우 D3DCAPS9에서 D3DCAPS_OVERLAY 플래그가 설정됩니다. Caps 멤버입니다.

특정 오버레이 형식이 지정된 디스플레이 모드에서 지원되는지 확인하려면 IDirect3D9ExOverlayExtension::CheckDeviceOverlayType을 호출합니다.

오버레이를 만들려면 IDirect3D9Ex::CreateDeviceEx 를 호출하고 D3DSWAPEFFECT_OVERLAY 스왑 효과를 지정합니다. 백 버퍼는 하드웨어에서 지원하는 경우 RGB가 아닌 형식을 사용할 수 있습니다.

오버레이 표면에는 다음과 같은 제한 사항이 있습니다.

  • 애플리케이션은 둘 이상의 오버레이 스왑 체인을 만들 수 없습니다.
  • 오버레이는 창 모드에서 사용해야 합니다. 전체 화면 모드에서는 사용할 수 없습니다.
  • 오버레이 스왑 효과는 IDirect3DDevice9Ex 인터페이스와 함께 사용해야 합니다. IDirect3DDevice9에는 지원되지 않습니다.
  • 다중 샘플링을 사용할 수 없습니다.
  • D3DPRESENT_DONOTFLIPD3DPRESENT_FLIPRESTART 플래그는 지원되지 않습니다.
  • 오버레이 화면에는 프레젠테이션 통계를 사용할 수 없습니다.

하드웨어에서 확장이 지원되지 않는 경우 창 크기를 모든 차원으로 조정할 수 있도록 디스플레이 모드만큼 큰 스왑 체인을 만드는 것이 좋습니다. 스왑 체인을 다시 만드는 것은 심각한 렌더링 아티팩트를 일으킬 수 있으므로 창 크기 조정을 처리하는 최적의 방법이 아닙니다. 또한 GPU가 오버레이 메모리를 관리하는 방식으로 인해 스왑 체인을 다시 만들면 애플리케이션에 비디오 메모리가 부족해질 수 있습니다.

새 D3DPRESENT_PARAMETERS 플래그

다음 D3DPRESENT_PARAMETERS 플래그는 오버레이를 만들기 위해 정의됩니다.

플래그 설명
D3DPRESENTFLAG_OVERLAY_LIMITEDRGB RGB 범위는 16~235입니다. 기본값은 0~255입니다.
D3DOVERLAYCAPS_LIMITEDRANGERGB 기능이 필요합니다.
D3DPRESENTFLAG_OVERLAY_YCbCr_BT709 YUV 색은 BT.709 정의를 사용합니다. 기본값은 BT.601입니다.
D3DOVERLAYCAPS_YCbCr_BT709 기능이 필요합니다.
D3DPRESENTFLAG_OVERLAY_YCbCr_xvYCC 확장된 YCbCr(xvYCC)을 사용하여 데이터를 출력합니다.
D3DOVERLAYCAPS_YCbCr_BT601_xvYCC 또는 D3DOVERLAYCAPS_YCbCr_BT709_xvYCC 기능이 필요합니다.

 

하드웨어 오버레이 사용

오버레이 표면을 표시하기 위해 애플리케이션은 IDirect3DDevice9Ex::P resentEx를 호출합니다. Direct3D 런타임은 자동으로 대상 색 키를 그립니다.

다음 PresentEx 플래그는 오버레이에 대해 정의됩니다.

플래그 설명
D3DPRESENT_UPDATECOLORKEY DWM(데스크톱 창 관리자) 컴퍼지션을 사용하지 않도록 설정하면 이 플래그를 설정합니다. 이 플래그를 사용하면 Direct3D에서 색 키를 다시 그리게 됩니다.
DWM을 사용하도록 설정한 경우 Direct3D는 DWM이 리디렉션에 사용하는 표면에 색 키를 한 번 그리기 때문에 이 플래그가 필요하지 않습니다.
D3DPRESENT_HIDEOVERLAY 오버레이를 숨깁니다.
D3DPRESENT_UPDATEOVERLAYONLY 콘텐츠를 변경하지 않고 오버레이를 업데이트.
이 플래그는 비디오가 일시 중지되는 동안 창이 이동하는 경우에 유용합니다.

 

애플리케이션은 다음 사례를 처리할 준비가 되어 있어야 합니다.

  • 다른 애플리케이션이 오버레이를 사용하는 경우 PresentExD3DERR_NOTAVAILABLE 반환합니다.
  • 창이 다른 모니터로 이동되면 애플리케이션이 스왑 체인을 다시 만들어야 합니다. 그렇지 않으면 애플리케이션이 PresentEx 를 호출하여 다른 모니터에 오버레이를 표시하면 PresentExD3DERR_INVALIDDEVICE 반환합니다.
  • 디스플레이 모드가 변경되면 Direct3D는 오버레이를 복원하려고 시도합니다. 새 모드가 오버레이를 지원하지 않으면 PresentExD3DERR_UNSUPPORTEDOVERLAY 반환합니다.

코드 예

다음 예제에서는 오버레이 표면을 만드는 방법을 보여 줍니다.

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;
}

Direct3D 비디오 API