window显示驱动开发—RecycleCreateCommandList

发布于:2025-07-29 ⋅ 阅读:(18) ⋅ 点赞:(0)

运行时会调用驱动程序的 RecycleCreateCommandList 函数,使之前未使用的 DDI 句柄重新完全有效。

这些回收 DDI 函数提供了优化机会,有助于回收小内存量命令列表的资源。 以下伪代码展示了通过从 API 到 DDI 的函数调用流程来实现运行时的情况:

::FinishCommandList()
{
  // Empty InterlockedSList, integrating into the cache
  Loop { DC::pfnRecycleCommandList }

  If (Previously Destroyed CommandList Available)
 { IC::pfnRecycleCreateCommandList }
 else
  {
    IC::pfnCalcPrivateCommandListSize
    IC::pfnCreateCommandList
    IC::pfnCalcDeferredContextHandleSize(D3D11DDI_HT_COMMANDLIST)
  }

  Loop { DC::pfnDestroy* (context-local handle destroy) }

  IC::pfnRecycleCreateDeferredContext
}
...
Sporadic: DC::pfnCreate* (context-local open during first-bind per CommandList)

CommandList::Destroy()
{
  // If DC still alive, almost always recycle:
  If (DC still alive)
 { IC::pfnRecycleDestroyCommandList }
  Else
 { IC::pfnDestroyCommandList }
  // Add to InterlockedSList
}

 以下状态图显示了即时上下文 DDI 命令列表句柄的有效性。 绿色状态代表一个句柄,可与 CommandListExecute 一起使用。

 1. 运行时与驱动协作流程

伪代码:命令列表生命周期(小内存量优化路径)

sequenceDiagram
    participant App
    participant Runtime
    participant Driver
    App->>Runtime: ID3D11DeviceContext::FinishCommandList
    Runtime->>Driver: RecycleCreateCommandList (复用句柄)
    alt 缓存命中
        Driver->>Runtime: 返回已回收的hCommandList
        Runtime->>Driver: RecordCommands (记录新命令)
        Runtime->>Driver: RecycleCommandList (执行后回收)
    else 缓存未命中
        Driver->>Runtime: 返回E_OUTOFMEMORY
        Runtime->>Driver: CreateCommandList (创建新句柄)
        Runtime->>App: 返回失败或新句柄
    end

2. 驱动函数实现规范

RecycleCreateCommandList (关键回收路径)

HRESULT APIENTRY RecycleCreateCommandList(
    D3D11DDI_HDEFERREDCONTEXT hDeferredContext,
    D3D11DDI_HCOMMANDLIST* phCommandList
) {
    // 1. 从延迟上下文的线程本地缓存获取可复用句柄
    if (!hDeferredContext->commandListCache.empty()) {
        *phCommandList = hDeferredContext->commandListCache.back();
        hDeferredContext->commandListCache.pop_back();
        
        // 2. 重置内部状态(保留内存分配)
        ResetCommandListData(*phCommandList);
        return S_OK;
    }
    
    // 3. 缓存为空时直接返回错误(无回调)
    return E_OUTOFMEMORY;
}

RecycleCommandList (内存整合)

void APIENTRY RecycleCommandList(
    D3D11DDI_HCOMMANDLIST hCommandList,
    D3D11DDI_HDEFERREDCONTEXT hDeferredContext
) {
    // 1. 确保由正确的延迟上下文线程调用
    assert(GetCurrentThreadId() == hDeferredContext->threadId);

    // 2. 回收至线程本地缓存
    hDeferredContext->commandListCache.push_back(hCommandList);
    
    // 3. 可选:释放非必要内存(如大型临时缓冲区)
    TrimCommandListMemory(hCommandList);
}

3. 内存管理优化策略

缓存层级设计

缓存级别 内容 优化目标
线程本地缓存 高频小命令列表(如CopyResource 零分配、无锁操作
全局备用池 低频大命令列表 减少内存碎片

动态缓存大小调整

// 根据使用频率动态调整线程本地缓存大小
void AdjustCacheSize(D3D11DDI_HDEFERREDCONTEXT hContext) {
    const size_t currentSize = hContext->commandListCache.size();
    if (currentSize > hContext->maxCacheSize && hContext->hits > hContext->misses) {
        hContext->maxCacheSize *= 2; // 扩展缓存
    } else if (currentSize < hContext->maxCacheSize / 4) {
        hContext->maxCacheSize /= 2; // 收缩缓存
    }
}

4. 错误处理与调试

严格校验(调试构建)

#if DBG
void ValidateRecycledHandle(D3D11DDI_HCOMMANDLIST hCommandList) {
    if (IsHandleCorrupted(hCommandList)) {
        DebugBreak(); // 捕获重复释放或无效状态
    }
}
#endif

性能计数器

指标 采集方法 优化参考
缓存命中率 hits / (hits + misses) >90% 表示优化有效
平均回收延迟 QueryPerformanceCounter 应 <1μs

5. 线程模型与同步

无锁实现要求
线程本地缓存:每个延迟上下文维护独立的 std::vector 或环形缓冲区,无需同步。

全局池(可选):使用原子操作或无锁队列(如 mpsc_queue)。

禁止行为
跨线程访问缓存:若检测到非所属线程操作,触发调试层断言。

阻塞操作:禁止在回收路径中使用 malloc/free 或系统锁。

6. 总结

高频复用路径:

RecycleCreateCommandList 和 RecycleCommandList 构成零分配闭环。

低开销设计:线程本地缓存 + 无锁结构确保小命令列表的极致性能。

弹性扩展:动态缓存大小适应不同负载场景。

 


网站公告

今日签到

点亮在社区的每一天
去签到