使用多平面覆盖时,这些要求适用于在 Microsoft DirectX 应用中创建的分配
DirectX 11 资源创建
调用 CreateResource (D3D11) 函数时:
- D3D10_DDI_BIND_PRESENT和D3D10_DDI_RESOURCE_MISC_SHARED常量值在 D3D11DDIARG_CREATERESOURCE 结构的 BindFlags 成员中设置,表示可以扫描出分配。
- 可能还会设置 Flags 中的其他位字段标志,例如:
- D3D10_DDI_BIND_SHADER_RESOURCE
- D3D10_DDI_BIND_RENDER_TARGET
- D3D11_DDI_BIND_UNORDERED_ACCESS
- D3D11_DDI_BIND_DECODER
- D3D11_1DDI_RESOURCE_MISC_RESTRICTED_CONTENT
- D3D11_1DDI_RESOURCE_MISC_RESTRICT_SHARED_RESOURCE_DRIVER
- 在 CreateResource (D3D11 中传递DXGI_DDI_PRIMARY_DESC结构时,) 调用:
- DXGI_DDI_PRIMARY_DESC 具有适当的 VidPnSourceId 成员值。
- DXGI_DDI_PRIMARY_DESC。ModeDesc 与当前模式匹配。
- 对于多平面覆盖资源,驱动程序不得在 DXGI_DDI_PRIMARY_DESC 的 DriverFlags 成员中设置 DXGI_DDI_PRIMARY_DRIVER_FLAG_NO_SCANOUT标志值。
1. 绑定标志 (BindFlags) 处理
1.1 必须支持的标志组合
当创建可用于扫描输出(scan-out)的资源时,D3D11DDIARG_CREATERESOURCE 结构中的 BindFlags 必须包含:
BindFlags = D3D10_DDI_BIND_PRESENT | D3D10_DDI_RESOURCE_MISC_SHARED;
1.2 常见辅助绑定标志
绑定标志 | 用途 |
---|---|
D3D10_DDI_BIND_SHADER_RESOURCE |
允许资源作为着色器输入 |
D3D10_DDI_BIND_RENDER_TARGET |
允许作为渲染目标 |
D3D11_DDI_BIND_UNORDERED_ACCESS |
支持UAV访问 (Compute Shader) |
D3D11_DDI_BIND_DECODER |
视频解码器专用资源 |
典型实现检查:
BOOL IsValidMpoBindFlags(UINT BindFlags) {
// 必须包含PRESENT和SHARED
if (!(BindFlags & D3D10_DDI_BIND_PRESENT) ||
!(BindFlags & D3D10_DDI_RESOURCE_MISC_SHARED)) {
return FALSE;
}
// 不允许冲突标志
if ((BindFlags & D3D11_DDI_BIND_DECODER) &&
(BindFlags & D3D11_DDI_BIND_UNORDERED_ACCESS)) {
return FALSE;
}
return TRUE;
}
2. 受限内容处理
2.1 保护内容标志
MiscFlags = D3D11_1DDI_RESOURCE_MISC_RESTRICTED_CONTENT |
D3D11_1DDI_RESOURCE_MISC_RESTRICT_SHARED_RESOURCE_DRIVER;
安全要求:
当设置 RESTRICTED_CONTENT 时:
- 必须启用内存加密 (如 Intel PAVP)
- 禁止CPU直接访问资源
设置 RESTRICT_SHARED_RESOURCE_DRIVER 时:
- 需要验证共享句柄的访问权限
- 记录所有跨进程访问尝试
3. 主表面 (Primary Surface) 配置
3.1 DXGI_DDI_PRIMARY_DESC 验证
HRESULT ValidatePrimaryDesc(
const DXGI_DDI_PRIMARY_DESC* pDesc,
UINT VidPnSourceId)
{
// 检查VidPnSourceId有效性
if (VidPnSourceId >= MAX_VIDPN_SOURCES) {
return E_INVALIDARG;
}
// 验证显示模式匹配
CURRENT_MODE mode = GetCurrentMode(VidPnSourceId);
if (memcmp(&pDesc->ModeDesc, &mode, sizeof(DXGI_DDI_MODE_DESC)) != 0) {
return DXGI_DDI_ERR_UNSUPPORTED;
}
// MPO资源必须允许扫描输出
if (pDesc->DriverFlags & DXGI_DDI_PRIMARY_DRIVER_FLAG_NO_SCANOUT) {
return E_FAIL;
}
return S_OK;
}
3.2 多平面覆盖特殊要求
对于MPO资源:
- 必须清除 NO_SCANOUT 标志
- 格式必须匹配显示控制器能力:
BOOL IsValidMpoFormat(DXGI_FORMAT fmt) {
return (fmt == DXGI_FORMAT_NV12) ||
(fmt == DXGI_FORMAT_B8G8R8A8_UNORM);
}
4. 资源创建流程
4.1 MPO资源创建序列
sequenceDiagram
App->UMD: CreateResource(BindFlags=PRESENT|SHARED)
UMD->KMD: DxgkDdiCreateAllocation(Flags=MPO)
KMD->Hardware: 配置保护内存区域
Hardware-->KMD: 返回物理地址
KMD-->UMD: 分配句柄
UMD-->App: 资源创建完成
4.2 错误处理矩阵
错误场景 | 返回码 |
---|---|
缺少PRESENT/SHARED标志 | E_INVALIDARG |
无效的VidPnSourceId | DXGI_DDI_ERR_INVALIDARG |
不支持的像素格式 | DXGI_DDI_ERR_UNSUPPORTED |
硬件资源不足 | E_OUTOFMEMORY |
5. 安全实现要点
5.1 内存保护机制
typedef struct _SECURE_RESOURCE_CTX {
PHYSICAL_ADDRESS EncryptedPA; // 加密物理地址
UINT64 SessionKey; // 硬件解密密钥
D3DKMT_HANDLE hProtectedAlloc;// 保护内存句柄
} SECURE_RESOURCE_CTX;
5.2 访问控制
NTSTATUS CheckResourceAccess(
HANDLE hResource,
D3DKMT_HANDLE hDevice)
{
// 验证设备所有权
if (!IsOwnerDevice(hResource, hDevice)) {
return STATUS_ACCESS_DENIED;
}
// 检查RESTRICTED_CONTENT权限
if (IsRestricted(hResource) &&
!HasContentProtectionCapability(hDevice)) {
return STATUS_GRAPHICS_PRESENT_OCCLUDED;
}
return STATUS_SUCCESS;
}
6. WHQL 认证要求
6.1 必须通过的测试
- Device.Graphics.WDDM.MPO.CreateResource
- 验证标志组合有效性
- 测试保护资源创建
Device.Graphics.WDDM.SharedResource
- 跨进程共享测试
- 安全验证检查
6.2 认证检查清单
- 正确处理所有标准绑定标志组合
- 实现 RESTRICTED_CONTENT 保护路径
- 主表面描述符验证逻辑
- 拒绝非法 NO_SCANOUT 配置
7. 性能优化建议
内存池管理:
class MpoAllocPool {
public:
void* AllocSecureSurface(UINT size) {
return SecureMemAlloc(size, GPU_PAGE_SIZE);
}
};
硬件加速:
- 使用 GPU 专用指令初始化保护资源
- 启用压缩表面 (如 CCS) 减少带宽占用
8. 调试与验证
8.1 诊断命令
# 检查当前MPO资源状态
dxgdiag.exe /test mpo
8.2 事件追踪
// 在资源创建时记录关键参数
EventWriteCreateResource(
hDevice,
BindFlags,
Format,
pPrimaryDesc);