硬件覆盖支持
硬件覆盖层是可以覆盖在主图面上的视频内存的专用区域。 显示覆盖时不执行复制。 覆盖操作在硬件中执行,无需修改主图面中的数据。
在早期版本的 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_DONOTFLIP和D3DPRESENT_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 | 在不更改内容的情况下汇报覆盖层。 如果窗口在视频暂停时移动,则此标志非常有用。 |
应用程序应准备好处理以下情况:
- 如果另一个应用程序正在使用覆盖, 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;
}
相关主题