硬件覆盖支持

硬件覆盖层是可以覆盖在主图面上的视频内存的专用区域。 显示覆盖时不执行复制。 覆盖操作在硬件中执行,无需修改主图面中的数据。

在早期版本的 Windows 中,使用硬件覆盖进行视频播放很常见,因为覆盖对于帧速率较高的视频内容而言是高效的。 从 Windows 7 开始,Direct3D 9 支持硬件覆盖。 此支持主要用于视频播放,在某些方面与早期的 DirectDraw API 不同:

  • 覆盖层不能收缩、镜像或去隔行。
  • 不支持源颜色键和 alpha 混合。
  • 如果覆盖硬件支持覆盖层,则可以拉伸覆盖层。 否则,不支持拉伸。 实际上,并非所有图形驱动程序都支持拉伸。
  • 每个设备最多支持一个覆盖层。
  • 覆盖使用目标颜色键执行,但 Direct3D 运行时会自动选择颜色并绘制目标矩形。 每当调用 PresentEx 时,Direct3D 都会自动跟踪窗口的位置并更新覆盖位置。

创建硬件覆盖图面

若要查询覆盖支持,请调用 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_xvYCCD3DOVERLAYCAPS_YCbCr_BT709_xvYCC 功能。

 

使用硬件覆盖

为了显示覆盖图面,应用程序调用 IDirect3DDevice9Ex::P resentEx。 Direct3D 运行时自动绘制目标颜色键。

为覆盖定义了以下 PresentEx 标志。

标志 描述
D3DPRESENT_UPDATECOLORKEY 如果禁用桌面窗口管理器 (DWM) 组合,请设置此标志。 此标志会导致 Direct3D 重绘颜色键。
如果启用了 DWM,则不需要此标志,因为 Direct3D 在 DWM 用于重定向的图面上绘制颜色键一次。
D3DPRESENT_HIDEOVERLAY 隐藏覆盖。
D3DPRESENT_UPDATEOVERLAYONLY 在不更改内容的情况下汇报覆盖层。
如果窗口在视频暂停时移动,则此标志非常有用。

 

应用程序应准备好处理以下情况:

  • 如果另一个应用程序正在使用覆盖, PresentEx 将返回 D3DERR_NOTAVAILABLE
  • 如果窗口移动到另一台监视器,则应用程序必须重新创建交换链。 否则,如果应用程序调用 PresentEx 以在其他监视器上显示覆盖, 则 PresentEx 将返回 D3DERR_INVALIDDEVICE
  • 如果显示模式发生更改,Direct3D 会尝试还原覆盖。 如果新模式不支持覆盖, PresentEx 将返回 D3DERR_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