window 显示驱动开发-处理多个锁

使用 Direct3D 运行时,可以允许顶点缓冲区和索引缓冲区具有多个未完成的锁。 用户模式显示驱动程序必须以 与 Windows 2000 显示驱动程序模型中运行时相同的方式处理多个锁。

用户模式显示驱动程序不得对已锁定的资源调用其 LockAsync 函数失败。 也就是说,在第一次调用其 LockAsync 函数成功锁定该资源后,驱动程序无法对特定资源的 LockAsync 函数执行任何调用。 同样,在首次调用其 Lock 函数成功锁定该资源后,驱动程序不能失败对其锁定特定资源的 Lock 函数的任何调用。 运行时将其对驱动程序的 LockAsync 函数进行的每个调用与对驱动程序的 UnlockAsync 函数的调用相匹配。 运行时还通过调用驱动程序的 Unlock 函数来匹配对驱动程序的 Lock 函数进行的每个调用。

用户模式显示驱动程序无法调用其 UnlockAsync 函数,除非之前调用驱动程序的 LockAsync 函数时,D3DDDIARG_UNLOCKASYNC结构所描述的资源实际上未锁定。 同样,驱动程序不能失败对其 Unlock 函数的调用,除非 D3DDDIARG_UNLOCK 结构描述的资源实际上没有被之前调用驱动程序的 Lock 函数锁定。 在以前未锁定资源的情况下, UnlockAsync 和 Unlock 返回E_INVALIDARG。

1. 核心规则

(1) 多重锁定支持

  • 顶点/索引缓冲区:必须支持 多个未完成的锁定(Multiple Pending Locks),行为需与 Windows 2000 显示驱动模型 一致。
  • 其他资源(如纹理/常量缓冲区):无强制要求,可由驱动自行决定。

(2) 锁定函数调用约束

函数 调用限制
Lock 首次成功锁定后,后续对同一资源的 Lock 调用 不得失败(即使资源已锁定)。
LockAsync 同一资源 仅允许一次成功的 LockAsync,后续调用必须失败。

(3) 解锁函数调用约束

函数 调用限制
Unlock 仅当资源 未被锁定 时可返回 E_INVALIDARG,否则必须成功。
UnlockAsync 仅当资源 未被 LockAsync 锁定 时可返回 E_INVALIDARG,否则必须成功。

2. 驱动实现要求

(1) 锁定状态跟踪
驱动需维护资源的锁定状态(如通过标志位或引用计数):

typedef struct _DRIVER_RESOURCE {
    volatile LONG LockCount;       // Lock 调用次数
    volatile BOOL IsLockedAsync;   // LockAsync 是否生效
} DRIVER_RESOURCE;

HRESULT APIENTRY Lock(
    D3D10DDI_HDEVICE hDevice,
    D3D10DDI_HRESOURCE hResource,
    UINT Subresource,
    D3DDDILOCK_FLAGS Flags
) {
    DRIVER_RESOURCE* pRes = GetResource(hResource);
    InterlockedIncrement(&pRes->LockCount); // 原子递增
    return S_OK; // 必须成功
}

(2) 解锁验证逻辑

HRESULT APIENTRY UnlockAsync(
    D3D10DDI_HDEVICE hDevice,
    CONST D3DDDIARG_UNLOCKASYNC* pUnlockAsync
) {
    DRIVER_RESOURCE* pRes = GetResource(pUnlockAsync->hResource);
    if (!pRes->IsLockedAsync) {
        return E_INVALIDARG; // 未锁定时报错
    }
    pRes->IsLockedAsync = FALSE;
    return S_OK;
}

(3) LockAsync 严格限制

HRESULT APIENTRY LockAsync(
    D3D10DDI_HDEVICE hDevice,
    CONST D3DDDIARG_LOCKASYNC* pLockAsync
) {
    DRIVER_RESOURCE* pRes = GetResource(pLockAsync->hResource);
    if (pRes->IsLockedAsync) {
        return E_FAIL; // 禁止多次锁定
    }
    pRes->IsLockedAsync = TRUE;
    return S_OK;
}

3. 运行时行为保障

调用配对:运行时保证每次 Lock/LockAsync 都有对应的 Unlock/UnlockAsync 调用。

线程安全:运行时负责跨线程调用的同步,驱动无需处理锁的线程竞争。

4. 异常场景处理

场景 驱动行为
重复 Lock 同一资源 返回 S_OK,更新锁定计数。
重复 LockAsync 同一资源 返回 E_FAIL
对未锁定资源调用 Unlock 返回 E_INVALIDARG
对未锁定资源调用 UnlockAsync 返回 E_INVALIDARG

5. WHCK 认证测试项

测试项 验证目标
Device.Graphics.UMD.MultipleLocks 顶点/索引缓冲区的多重锁定支持。
Device.Graphics.UMD.LockAsyncStrict LockAsync 的严格单次锁定限制。
Device.Graphics.UMD.UnlockValidation 解锁调用的正确错误码返回。

6. 调试与问题排查

常见错误:

  • 资源泄漏:未配对的锁定/解锁操作(需依赖运行时保障)。
  • 数据竞争:驱动内部状态未原子访问(如 LockCount)。

工具推荐:

  • PIX on Windows:捕获锁定/解锁调用序列。
  • DirectX Debug Runtime:检测未配对的锁定操作。

7. 总结

必须支持:顶点/索引缓冲区的多重锁定,行为兼容 Windows 2000 模型。

严格限制:

  • LockAsync 同一资源仅允许成功一次。
  • 解锁调用需验证资源锁定状态。

线程安全:依赖运行时同步,驱动仅需原子维护内部状态。

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