window显示驱动开发—pfnSetErrorCb 的问题

创建函数均不会返回错误代码,这对于 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失败代码。

1. 创建函数的错误报告机制

核心规则

  • 无返回值错误码:所有创建函数(如 CreateResource、CreateShader)必须 通过 pfnSetErrorCb 回调报告错误,而非直接返回错误码。
  • 兼容性保留:沿用 D3D10DDI_HRTCORELAYER 句柄传递错误,确保与D3D10 DDI兼容。

驱动实现模板

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 // 或具体错误码
        );
    }
}

2. 延迟上下文的错误处理扩展

新增允许的错误码

错误码 适用场景
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;
    }
    // 正常记录命令...
}

3. 内存不足的故障处理流程

运行时与驱动协作

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 调用时释放临时内存。

4. 线程安全与上下文隔离

错误回调的上下文关联

上下文类型 错误回调目标 线程安全要求
即时上下文 设备级 pfnSetErrorCb 需全局锁保护回调调用。
延迟上下文 上下文专属 pfnSetErrorCb 仅允许所属线程访问,无需锁。

驱动实现示例

// 即时上下文的线程安全错误报告
void ReportImmediateError(
    D3D10DDI_HDEVICE hDevice,
    HRESULT hr
) {
    AutoLock lock(&g_ErrorCallbackLock);
    pDevice->pRTCallbacks->pfnSetErrorCb(
        hDevice->hRTCoreLayer,
        hr,
        D3DDDIERR_DEVICEREMOVED
    );
}

5. 调试与验证

错误注入测试
强制内存不足:在驱动中模拟 E_OUTOFMEMORY,验证应用是否能正确处理 FinishCommandList 失败。

设备丢失恢复:触发 D3DDDIERR_DEVICEREMOVED,检查资源重建逻辑。

调试层检查
未报告的错误:若创建函数失败但未调用 pfnSetErrorCb,调试层输出:

[D3D11 DEBUG] MISSING ERROR: CreateResource failed but no error callback invoked.

6. 总结

统一错误报告:所有创建函数通过 pfnSetErrorCb 反馈错误,保持与D3D10 DDI兼容。

延迟上下文扩展:支持 E_OUTOFMEMORY 报告,驱动需监控命令缓冲区内存。

线程隔离:延迟上下文的错误回调需与所属线程绑定,避免锁竞争。

你可能感兴趣的:(windows图形显示驱动开发,驱动开发)