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

C++ Win API中的内存DC有多便宜/贵?,c++,c,winapi,dib,C++,C,Winapi,Dib,我正在开发一个程序,该程序将有许多由CreateDIBSection创建的DIB位图,并且必须使用WinAPI在这些位图上绘制大量文本 为了在位图上绘制,Windows需要由CreateCompatibleDC创建的设备上下文 现在有两种方法: 我可以为每个位图创建一次DC,将其用于绘图,并在释放位图时将其删除 或者,我只能在需要绘制位图、调用绘制函数和删除DC时创建DC 更好的方法是什么?我更喜欢第一种,因为调用更少-这将使我的代码更小,也更快一点 但是为每个位图持有一个长寿的DC不是太贵了吗

我正在开发一个程序,该程序将有许多由CreateDIBSection创建的DIB位图,并且必须使用WinAPI在这些位图上绘制大量文本

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

现在有两种方法:

我可以为每个位图创建一次DC,将其用于绘图,并在释放位图时将其删除

或者,我只能在需要绘制位图、调用绘制函数和删除DC时创建DC

更好的方法是什么?我更喜欢第一种,因为调用更少-这将使我的代码更小,也更快一点

但是为每个位图持有一个长寿的DC不是太贵了吗

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

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

马克·鲁西诺维奇的博客文章涉及相当多的细节。总结一下要点,下面是窗口管理器对GDI资源的限制列表:

每个进程默认值10.000个GDI对象,可通过注册表项HKEY\U LOCAL\U MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuota配置。 每个用户会话65.535个GDI对象。 GDI对象内存限制是分页池限制,请参阅。 每个进程以及每个会话都受到限制。您正在与同一会话中运行的所有其他进程竞争资源。考虑到这一点,您应该只在您的问题中的选项2需要时使用GDI资源

马克·鲁西诺维奇的博客文章涉及相当多的细节。总结一下要点,下面是窗口管理器对GDI资源的限制列表:

每个进程默认值10.000个GDI对象,可通过注册表项HKEY\U LOCAL\U MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuota配置。 每个用户会话65.535个GDI对象。 GDI对象内存限制是分页池限制,请参阅。
下面是一个测试,用于检查调用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微秒比特BLT:2500微秒

8位275kb的结果:

CreateCompatibleDC:12微秒比特BLT:500微秒


下面是一个测试,用于检查调用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微秒比特BLT:2500微秒

8位275kb的结果:

CreateCompatibleDC:12微秒比特BLT:500微秒


通常的做法是调用GetDC或GetDCEx,draw,然后ReleaseDC。我不需要在窗口上绘制,所以GetDC不是一个选项。CreateCompatibleDC是需要使用的。这是与窗口无关的内存DC。@selbie Hm,您的意思可能是2?我仍然不想知道这个问题的答案。哦,这就是我的意思!是的2@selbie-那么,您的观点是,内存设备上下文非常昂贵,内存、操作系统资源足以以大量API调用的代价来尽量减少内存中的实例:CreateCompatibleDC、2xNxSelectObject和DeleteDC在每次绘制操作中,即使是改变了像素?通常的做法是调用GetDC或GetDCEx、draw,然后释放DC。我不需要在窗口上绘制,所以GetDC不是一个选项。CreateCompatibleDC是需要使用的。这是与窗口无关的内存DC。@selbie Hm,您的意思可能是2?我仍然不想知道这个问题的答案。哦,这就是我的意思!是的2@selbie-那么,您的观点是,内存设备上下文非常昂贵,内存、操作系统资源足以以大量API调用的代价来尽量减少内存中的实例:CreateCompatibleDC、2xNxSelectObject和DeleteDC在每次绘制操作中,即使是改变像素?