You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

D3D11触发Fence后Map调用仍缓慢的问题排查

计算着色器Map调用后台性能暴跌问题分析

现状概述

运行计算着色器,通过D3D11 Query统计得着色器本身耗时约0.22ms,但实际总耗时平均约0.6ms,Map调用占用了部分时间。着色器负责计算自上一帧以来所有变更像素的dirty RECT并返回CPU,功能运行正常。

核心问题:正常场景下总耗时约0.6ms,性能理想;但程序后台运行且存在GPU密集型应用(如Blender、3A游戏)时,总耗时从0.6ms飙升至9ms,Map调用速度异常缓慢,需要定位原因。

当前实现代码细节

结果缓冲区创建

buffer_desc.ByteWidth = sizeof(RECT);
buffer_desc.StructureByteStride = sizeof(RECT);
buffer_desc.Usage = D3D11_USAGE_DEFAULT;
buffer_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
buffer_desc.CPUAccessFlags = 0;
hr = ID3D11Device5_CreateBuffer(ctx->device, &buffer_desc, NULL, &ctx->reduction_final);

UAV设置

uav_desc.Format = DXGI_FORMAT_UNKNOWN;
uav_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uav_desc.Buffer.FirstElement = 0;
uav_desc.Buffer.NumElements = 1;
uav_desc.Buffer.Flags = 0;
hr = ID3D11Device5_CreateUnorderedAccessView(ctx->device, (ID3D11Resource*) ctx->reduction_final, &uav_desc, &ctx->reduction_final_UAV);

暂存缓冲区创建

buffer_desc.ByteWidth = sizeof(RECT);
buffer_desc.StructureByteStride = sizeof(RECT); 
buffer_desc.Usage = D3D11_USAGE_STAGING;
buffer_desc.BindFlags = 0;
buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
hr = ID3D11Device5_CreateBuffer(ctx->device, &buffer_desc, NULL, &ctx->cpu_staging);

Map调用实现

hr = ID3D11DeviceContext4_Map(ctx->device_ctx, (ID3D11Resource*) ctx->cpu_staging, 0, D3D11_MAP_READ, 0, &mapped_res);

Fence与事件创建

hr = ID3D11Device5_CreateFence(ctx->device, 1, D3D11_FENCE_FLAG_NONE, &IID_ID3D11Fence, (void**) &ctx->fence);
ctx->fence_handle = CreateEventA(NULL, FALSE, FALSE, NULL);

Dispatch后的复制与Fence信号

ID3D11DeviceContext4_CopyResource(ctx->device_ctx, (ID3D11Resource*) ctx->cpu_staging, (ID3D11Resource*) ctx->reduction_final);
ID3D11DeviceContext4_Signal(ctx->device_ctx, ctx->fence, ++ctx->fence_counter);
hr = ID3D11Fence_SetEventOnCompletion(ctx->fence, ctx->fence_counter, ctx->fence_handle);

等待与Map读取逻辑

DWORD waitResult = WaitForSingleObject(ctx->fence_handle, 1);
if (waitResult != WAIT_OBJECT_0)
{
    LOG("Timeout Count: %u", ++timeout_count);
    return false;
}
else
{
    LOG("Timeout Count: %u", timeout_count);

    ID3D11DeviceContext4_Map(ctx->device_ctx, (ID3D11Resource*) ctx->cpu_staging, 0, D3D11_MAP_READ, 0, &mapped_res);
    memcpy(rect, mapped_res.pData, sizeof(RECT));
    ID3D11DeviceContext4_Unmap(ctx->device_ctx, (ID3D11Resource*) ctx->cpu_staging, 0);
    return true;
}

核心疑问

  1. 对Map调用的工作原理存在哪些误解?
  2. 有没有办法缩短Map调用的耗时?
  3. Fence是否可能在复制操作完成前就触发信号?

已尝试的优化方案

  • 设置SetGPUThreadPriority为7
  • 设置AvSetMmThreadCharacteristicsW为"DisplayPostProcessing"、"Games"和"Capture"
  • 设置AvSetMmThreadPriority为AVRT_PRIORITY_CRITICAL

内容的提问来源于stack exchange,提问作者vulkur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 20:05:24