硬件覆盖是视频内存的专用区域,可覆盖在主图面上。 显示覆盖层时不执行任何复制。 覆盖作在硬件中执行,而无需修改主图面中的数据。
在早期版本的 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;
}
相关主题