You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Windows Desktop Duplication API录屏性能问题求助:无法稳定30FPS

优化Windows Desktop Duplication API录屏性能的几点建议

看起来你遇到的核心问题是录屏帧率波动大,没法稳定在30FPS以上,结合你提供的代码和场景,我帮你梳理几个关键优化方向:

1. 减少不必要的GPU纹理拷贝

你的代码里做了两次CopyResource:先把捕获到的桌面纹理拷贝到lGDIImage,再从lGDIImage拷贝到CPU可访问的lDestImage。这中间的一次拷贝完全是多余的——直接把lAcquiredDesktopImage拷贝到lDestImage就能省掉一次GPU内存操作,这很可能是耗时波动的主要来源之一。

修改后的代码可以简化成:

// 去掉中间的lGDIImage拷贝,直接拷贝到CPU可访问纹理
processor->lImmediateContext->CopyResource(processor->lDestImage, processor->lAcquiredDesktopImage);
processor->lAcquiredDesktopImage.Release();
processor->lDeskDupl->ReleaseFrame();

2. 优化CPU可访问纹理的创建参数

确保lDestImage的创建完全匹配源桌面纹理的格式和属性:

  • 使用D3D11_USAGE_STAGING作为资源用法,配合D3D11_CPU_ACCESS_READ的CPU访问标志(你只需要读取数据,不需要写入,别用READ_WRITE
  • 纹理格式直接使用processor->lOutputDuplDesc.ModeDesc.Format,避免GPU在拷贝时做隐式格式转换(这会大幅增加耗时)

如果格式不匹配,哪怕是细微的差异,GPU都会在后台做格式转换,这不仅慢,还会导致性能波动。

3. 解决GPU-CPU同步的不确定性

CopyResource是异步执行的,GPU完成拷贝的时间不确定——如果CPU在GPU还没完成拷贝时就调用Map,会被阻塞等待GPU,这就是你看到单帧耗时波动(15ms到45ms)的核心原因之一。

可以用ID3D11Query来同步GPU和CPU,确保拷贝完成后再读取数据:

// 在CopyResource之后添加同步逻辑
ID3D11Query* syncQuery = nullptr;
D3D11_QUERY_DESC queryDesc = { D3D11_QUERY_EVENT, 0 };
processor->lDevice->CreateQuery(&queryDesc, &syncQuery);
processor->lImmediateContext->End(syncQuery);

// 等待GPU完成拷贝操作
while (processor->lImmediateContext->GetData(syncQuery, nullptr, 0, 0) == S_FALSE) {
    // 可以在这里加个短时间的Sleep,避免CPU空转
    Sleep(1);
}

syncQuery->Release();

// 之后再执行Map和memcpy操作

虽然同步会增加一点固定开销,但能消除等待GPU的不确定时间,让帧率变得稳定。

4. 排查Chrome硬件加速的资源冲突

Chrome播放视频时默认开启硬件加速,会占用大量GPU资源,和你的录屏API形成资源竞争,这也可能导致性能波动。你可以先临时关闭Chrome的硬件加速(设置→系统→使用硬件加速模式),看看录屏耗时是否变得稳定——如果稳定了,说明是GPU资源竞争的问题,后续可以考虑优化GPU资源的调度策略,或者针对Chrome场景做特殊处理。

5. 调整Map操作的参数

Map的第三个参数从D3D11_MAP_READ_WRITE改成D3D11_MAP_READ,因为你只需要读取纹理数据,不需要写入。驱动会针对只读访问做更高效的优化,减少Map操作的耗时。

修改后的代码:

processor->lImmediateContext->Map(processor->lDestImage, processor->subresource, D3D11_MAP_READ, 0, &resource);

总结

优先从减少GPU拷贝次数解决GPU-CPU同步问题入手,这两个改动能最大程度降低单帧耗时并稳定帧率。其次检查纹理格式是否匹配,以及Chrome硬件加速的影响。按照这个顺序调整,应该能让你达到稳定30FPS的录屏目标。

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

火山引擎 最新活动