Win API中的内存DC有多便宜/昂贵?

时间:2015-11-02 07:17:24

标签: c++ c winapi dib

我正在开发一个程序,它将有许多DIB位图(由CreateDIBSection创建),并且必须使用Win API在它们上绘制大量文本。

为了绘制位图,Windows需要由CreateCompatibleDC创建的设备上下文。

现在有两种方法:

  1. 我可以为每个位图创建一次DC,使用它进行绘制,并在释放位图时将其删除。

  2. 或者只有当我需要绘制到位图,调用绘图函数并删除DC时,我才能创建DC。

  3. 更好的方法是什么?我更喜欢第一个,因为呼叫较少 - 这将使我的代码更小,也更快一点。

    但是,为每个位图保留一个长寿命的DC是不是太昂贵了?

    Edit1:应用程序实际上是一个GUI工具包库,将来可以以不同且不可预测的方式使用,因此我需要一个平衡良好的决策,以最大限度地提高性能和最小化系统资源使用。

2 个答案:

答案 0 :(得分:3)

每个进程以及每个进程的

GDI objects都是有限的。您正在与在同一会话中运行的所有其他进程竞争资源。考虑到这一点,您应该仅在需要时使用GDI资源(问题中的选项2)。

Mark Russinovich的博客文章Pushing the Limits of Windows: USER and GDI Objects – Part 2详细介绍了相关内容。总结一下要点,这里是窗口管理器对GDI资源的限制列表:

  • 每个进程10.000个GDI对象(默认值,可通过注册表项 HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Windows \ GDIProcessHandleQuota 配置)。
  • 每个用户会话65.535个GDI对象。
  • GDI对象内存限制是页面缓冲池限制(请参阅Pushing the Limits of Windows: Paged and Nonpaged Pool)。

答案 1 :(得分:2)

这是一项测试,用于检查调用CreateCompatibleDC所需的时间。我发现平均每次通话大约需要10到15微秒。与BitBlt相比,这相对较快,特别是对于较大的图像。因此,保持存储器DC没有多大优势。

case WM_PAINT:
{
    static HBITMAP hbitmap = (HBITMAP)LoadImage(0, L"path.bmp", 
        IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    std::wostringstream oss;

    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);

    auto start = std::chrono::system_clock::now();
    auto memdc = CreateCompatibleDC(hdc);
    oss << L"CreateCompatibleDC: " 
        << (std::chrono::system_clock::now() - start).count() / 10 << "\n";

    auto oldbitmap = SelectObject(memdc, hbitmap);

    start = std::chrono::system_clock::now();
    BitBlt(hdc, 0, 0, ps.rcPaint.right, ps.rcPaint.bottom, memdc, 0, 0, SRCCOPY);
    oss << L"BitBlt: "
        << (std::chrono::system_clock::now() - start).count() / 10 << "\n";

    SelectObject(memdc, oldbitmap);
    DeleteDC(memdc);

    EndPaint(hwnd, &ps);

    OutputDebugString(oss.str().c_str());
    break;
}

Windows 10上的结果:

24位5MB位图的结果:

  

CreateCompatibleDC:17微秒左BitBlt:2500微秒左

8bit 275kb的结果:

  

CreateCompatibleDC:12微秒左BitBlt:500微秒左