运行时可以通过调用驱动程序的 ResourceMap 函数) 在延迟上下文中映射动态资源 (,因为 Direct3D 版本 11 API 可确保首次使用映射的动态资源放弃先前的内容。 最佳选择是在连续使用原始动态资源的每个放弃上创建新的动态资源。 需要创建此别名资源,以便允许在延迟上下文时间线中对虚拟动态资源执行的操作不会影响直接上下文时间线中对虚拟动态资源执行的操作。 请记住,延迟上下文只是记录在调用驱动程序的 CommandListExecute 函数期间最终实现的操作。 使用动态资源时,将保留应用程序的原始意图,并将写入组合 GPU 可访问的内存提供给应用程序 (即,内存针对一次性 CPU 上传) 进行优化。
每个资源映射都可以直接提供指向别名资源的指针。 延迟的上下文录制需要额外的负担来实现这种类型的别名。 例如,延迟的上下文录制可能需要为别名纹理创建新视图。 与驱动程序别名的集成是必要的,而且似乎可以这样做。 执行命令列表时, (最后一个本地上下文创建的资源,以满足映射-丢弃调用) 必须替换为支持动态资源的“当前”资源,以直接上下文等方式。
在延迟上下文、映射丢弃调用之后,以及调用驱动程序的 CommandListExecute 函数(其中本地延迟上下文资源最好交换为“当前”资源的即时上下文版本)后,仍必须支持调用驱动程序的 ResourceCopy 函数以将资源复制到动态资源。 不经常使用调用驱动程序的 ResourceCopy 函数和动态资源目标,因此应使用写入时复制机制。 如果调用 的 ResourceCopy 会影响映射丢弃调用后延迟上下文中的动态资源,或者在将命令列表本地资源保存为当前资源的即时上下文上,则应在概念上分配新资源以提供副本的新目标,并且如果操作是 ResourceCopyRegion) ,则必须将旧资源复制到新资源
核心概念
驱动实现流程
sequenceDiagram
participant App
participant Runtime
participant Driver
App->>Runtime: Map(DISCARD) on Deferred Context
Runtime->>Driver: ResourceMap(DISCARD)
Driver->>Driver: 创建别名资源 (hAliasResource)
Driver->>App: 返回hAliasResource的指针
App->>Runtime: 写入数据
Runtime->>Driver: CommandListExecute
Driver->>Driver: 替换命令列表中的hAliasResource为原始资源
Driver->>Driver: 执行命令列表
Driver->>Driver: 回收hAliasResource
ResourceMap (延迟上下文)
void* APIENTRY ResourceMap(
D3D10DDI_HDEVICE hDevice,
D3D10DDI_HRESOURCE hResource,
UINT Subresource,
D3D10_DDI_MAP MapType,
UINT MapFlags,
D3D10DDI_MAPPED_SUBRESOURCE* pMappedSubresource
) {
if (MapType == D3D10_DDI_MAP_WRITE_DISCARD) {
// 1. 创建别名资源(相同格式/尺寸)
D3D11DDI_HRESOURCE hAliasResource;
CreateAliasResource(hResource, &hAliasResource);
// 2. 返回别名资源的可写指针
pMappedSubresource->pData = GetAliasPointer(hAliasResource);
pMappedSubresource->RowPitch = ...;
pMappedSubresource->DepthPitch = ...;
// 3. 记录别名映射关系
StoreAliasMapping(hDevice, hResource, hAliasResource);
return pMappedSubresource->pData;
}
// 其他MAP类型处理...
}
CommandListExecute 时的资源替换
void APIENTRY CommandListExecute(
D3D10DDI_HDEVICE hDevice,
D3D11DDI_HCOMMANDLIST hCommandList
) {
// 1. 遍历命令列表,替换所有别名资源为原始资源
ReplaceAliasResources(hCommandList);
// 2. 提交命令到GPU
SubmitCommandBuffer(hCommandList);
// 3. 回收别名资源
RecycleAliasResources(hCommandList);
}
应用场景
当延迟上下文中调用 ResourceCopy 到动态资源时:
触发条件:目标资源为动态且已被 MAP_DISCARD 别名化。
行为:驱动需隐式创建新副本,避免修改别名资源。
驱动实现示例
void APIENTRY ResourceCopy(
D3D10DDI_HDEVICE hDevice,
D3D10DDI_HRESOURCE hDstResource,
D3D10DDI_HRESOURCE hSrcResource
) {
if (IsDynamicAndAliased(hDstResource)) {
// 1. 创建新副本
D3D11DDI_HRESOURCE hNewCopy;
CreateCopy(hDstResource, &hNewCopy);
// 2. 执行复制到新副本
GPU_CopyResource(hSrcResource, hNewCopy);
// 3. 更新别名绑定
UpdateAliasMapping(hDstResource, hNewCopy);
} else {
// 常规复制
GPU_CopyResource(hSrcResource, hDstResource);
}
}
线程安全要求
调试验证
别名泄露检测:
命令列表执行后,检查未回收的别名资源:
void DebugCheckAliasLeaks() {
if (!g_AliasPool.empty()) {
DebugPrint("WARNING: %d alias resources not recycled.\n", g_AliasPool.size());
}
}
写入时复制正确性:
通过 PIX 捕获验证 ResourceCopy 是否生成新副本。
别名资源池化:
预分配一组动态资源,循环使用以减少运行时开销。
std::vector g_DynamicAliasPool;
延迟释放:
在GPU完成命令列表后回收别名资源(通过 pfnFinishCommandListCallback)。
别名隔离:通过临时资源实现延迟上下文的 MAP_DISCARD,确保与即时上下文隔离。
写入时复制:动态资源的 ResourceCopy 需隐式创建副本,保护别名数据。
生命周期管理:严格绑定别名资源到命令列表执行周期,避免泄露。