创建函数均不会返回错误代码,这对于 Direct3D 版本 11 线程模型来说是理想的。 所有 create 函数都使用 pfnSetErrorCb 从驱动程序中检索回错误代码。 为了最大程度地与 Direct3D 版本 10 驱动程序模型的兼容性,未引入返回错误代码的新 DDI 创建函数。 相反,驱动程序必须在创建函数期间继续使用 具有 pfnSetErrorCb 的统一设备/即时上下文D3D10DDI_HRTCORELAYER句柄。 当驱动程序支持命令列表时,驱动程序应使用与相应上下文关联的相应 pfnSetErrorCb 。 也就是说,延迟上下文错误应转到具有相应句柄的 pfnSetErrorCb 的特定延迟上下文调用,依此类推。
延迟上下文可以通过调用 pfnSetErrorCb 来返回E_OUTOFMEMORY,这些函数以前只允许D3DDDIERR_DEVICEREMOVED (如 Draw、 SetBlendState 等) ,因为延迟上下文内存需求随着每次调用 DDI 函数而永久增长。 Direct3D API 会触发本地上下文删除,以帮助驱动程序处理此类故障情况,从而有效地删除部分生成的命令列表。 应用程序继续确定它正在记录命令列表;但是,当应用程序最终调用 FinishCommandList 函数时, FinishCommandList 返回E_OUTOFMEMORY失败代码。
核心规则
驱动实现模板
void APIENTRY CreateResource(
D3D10DDI_HDEVICE hDevice,
D3D11DDIARG_CREATERESOURCE* pArgs,
D3D10DDI_HRESOURCE hResource
) {
// 1. 尝试创建资源
HRESULT hr = GPU_AllocateResource(pArgs, &hResource.pDrvPrivate);
// 2. 通过回调报告错误(而非返回值)
if (FAILED(hr)) {
pDevice->pRTCallbacks->pfnSetErrorCb(
hDevice->hRTCoreLayer, // 统一设备/即时上下文句柄
hr,
D3DDDIERR_DEVICEREMOVED // 或具体错误码
);
}
}
新增允许的错误码
错误码 | 适用场景 |
---|---|
E_OUTOFMEMORY |
延迟上下文命令记录时内存不足(如命令缓冲区耗尽)。 |
D3DDDIERR_DEVICEREMOVED |
设备丢失(如GPU超时)。 |
延迟上下文错误回调绑定
// 延迟上下文的错误回调设置(驱动初始化时)
void InitDeferredContext(
D3D10DDI_HDEVICE hDevice,
D3D11DDI_HDEFERREDCONTEXT hDeferredContext
) {
// 绑定延迟上下文专属的错误回调
hDeferredContext->pErrorCallbacks = &g_DeferredErrorCallbacks;
}
// 延迟上下文中的错误报告示例
void APIENTRY DeferredDraw(
D3D11DDI_HDEFERREDCONTEXT hContext,
UINT VertexCount
) {
if (!HasEnoughCommandBufferSpace(hContext, VertexCount)) {
hContext->pErrorCallbacks->pfnSetErrorCb(
hContext->hRTCoreLayer,
E_OUTOFMEMORY,
D3DDDIERR_DEVICEREMOVED
);
return;
}
// 正常记录命令...
}
运行时与驱动协作
sequenceDiagram
participant App
participant Runtime
participant Driver
App->>Runtime: BeginCommandList
Runtime->>Driver: DeferredDraw (内存不足)
Driver->>Runtime: pfnSetErrorCb(E_OUTOFMEMORY)
Runtime->>Driver: DiscardCommandList (隐式清理)
Runtime->>App: FinishCommandList 返回E_OUTOFMEMORY
驱动责任
内存监控:实时跟踪延迟上下文的命令缓冲区使用情况。
及时报告:在首次内存不足时立即触发 pfnSetErrorCb,停止后续命令记录。
状态回滚:在 DiscardCommandList 调用时释放临时内存。
错误回调的上下文关联
上下文类型 | 错误回调目标 | 线程安全要求 |
---|---|---|
即时上下文 | 设备级 pfnSetErrorCb |
需全局锁保护回调调用。 |
延迟上下文 | 上下文专属 pfnSetErrorCb |
仅允许所属线程访问,无需锁。 |
驱动实现示例
// 即时上下文的线程安全错误报告
void ReportImmediateError(
D3D10DDI_HDEVICE hDevice,
HRESULT hr
) {
AutoLock lock(&g_ErrorCallbackLock);
pDevice->pRTCallbacks->pfnSetErrorCb(
hDevice->hRTCoreLayer,
hr,
D3DDDIERR_DEVICEREMOVED
);
}
错误注入测试
强制内存不足:在驱动中模拟 E_OUTOFMEMORY,验证应用是否能正确处理 FinishCommandList 失败。
设备丢失恢复:触发 D3DDDIERR_DEVICEREMOVED,检查资源重建逻辑。
调试层检查
未报告的错误:若创建函数失败但未调用 pfnSetErrorCb,调试层输出:
[D3D11 DEBUG] MISSING ERROR: CreateResource failed but no error callback invoked.
统一错误报告:所有创建函数通过 pfnSetErrorCb 反馈错误,保持与D3D10 DDI兼容。
延迟上下文扩展:支持 E_OUTOFMEMORY 报告,驱动需监控命令缓冲区内存。
线程隔离:延迟上下文的错误回调需与所属线程绑定,避免锁竞争。