Direct2D硬件加速性能取决于资源复用、COM生命周期正确管理及减少GPU状态切换;错误做法(如每帧创建画刷)会导致性能反低于GDI+,必须初始化时创建静态资源、避免Flush滥用、预计算变换并妥善处理设备丢失。

Direct2D 的硬件加速不是“开了就快”,而是靠正确组织资源、避免误用 COM 生命周期、减少 GPU 状态切换这三件事撑起来的。错一步,比如在每帧里 CreateSolidColorBrush,性能可能比 GDI+ 还差。
资源必须复用,不能每帧 new/delete
Direct2D 所有资源(ID2D1SolidColorBrush、ID2D1Bitmap、ID2D1Geometry)在 GPU 上创建开销极大。频繁调用 CreateXXX 会触发显存分配、驱动通信、着色器编译等操作——实测单次 CreateBitmap 在中端独显上耗时可达 0.3–0.8ms,远超一帧 16.7ms 的预算。
- 画刷、笔、几何体等静态资源,在初始化阶段一次性创建,成员变量持有
ComPtr智能指针管理生命周期 - 避免在
OnRender()或 WM_PAINT 中调用任何Create*方法;若需动态颜色,改用SetColor()复用已有画刷 - 位图资源若需缩放/旋转,优先用
ID2D1Bitmap::CopyFromBitmap或ID2D1RenderTarget::CreateCompatibleRenderTarget复用目标,而非反复重建
BeginDraw / EndDraw 必须成对,且不能滥用 Flush
BeginDraw 启动命令录制,EndDraw 提交并清空批次缓冲区。中间所有绘制指令(DrawRectangle、FillGeometry)都暂存在 CPU 内存,直到 EndDraw 或缓冲区满才真正发往 GPU。滥用 Flush 会强制提前提交,打断批处理优化,显著增加驱动开销。
- 确保每个
BeginDraw都有对应EndDraw,尤其注意异常路径(如HRESULT检查失败后仍要EndDraw) - 绝对不要在循环内调用
Flush;它只应在调试卡顿或等待 GPU 完成某阶段时手动触发 - 若需多层绘制(如 UI 叠加),用
ID2D1Layer替代多次BeginDraw/EndDraw,Layer 内部自动合批
几何体与变换要预计算,别让 GPU 做重复工作
每次调用 SetTransform 都会更新常量寄存器,并可能使后续绘制无法合批。更糟的是,如果对同一几何体反复应用不同变换(比如逐个绘制带旋转的图标),Direct2D 无法合并这些调用——顶点数据不同,GPU 就得拆成多个 Draw Call。
立即学习“C++免费学习笔记(深入)”;
- 对固定形状(如按钮轮廓、图标路径),用
ID2D1Factory::CreatePathGeometry创建一次,之后只调用FillGeometry+SetTransform - 若需大量相似变换(如粒子系统),改用实例化思想:把所有变换矩阵打包进一个
ID2D1Bitmap或常量缓冲区,写自定义 HLSL 着色器(通过 D2D 的效果接口接入) - 文本渲染务必用
IDWriteTextLayout预排版,避免每帧调用DrawText重新解析 Unicode、换行、字距
最容易被忽略的是设备丢失(D2DERR_RECREATE_TARGET)后的资源重建逻辑——它不只影响位图,还可能让缓存的 ID2D1Geometry 失效。真正的高性能不是峰值帧率,而是在窗口缩放、DPI 变更、显卡休眠唤醒后仍能快速恢复稳定渲染。这要求你把资源依赖关系梳理清楚,哪些该销毁重做,哪些只需 ResizeTarget 即可复用。



















