Насколько дешево / дорого стоит память DC в Win API?

Я работаю над программой, которая будет иметь много растровых изображений DIB (созданных CreateDIBSection) и придется рисовать на них много текста, используя Win API.

Для рисования на растровом изображении Windows необходим контекст устройства, созданный CreateCompatibleDC,

А теперь вот два подхода:

  1. Я могу создать DC один раз для каждого растрового изображения, используя его для рисования и удаляя его при освобождении растрового изображения.

  2. Или я могу создать DC только тогда, когда мне нужно отрисовать растровое изображение, вызвать функции рисования и удалить DC.

Какой подход лучше? Я предпочитаю первое из-за меньшего количества вызовов - это сделает мой код намного меньше, а также немного быстрее.

Но не слишком ли дорого держать долгоживущий DC для каждого растрового изображения?

Edit1: Приложение на самом деле является библиотекой инструментария GUI, которая может использоваться в будущем непредсказуемым образом, поэтому мне нужно хорошо сбалансированное решение с максимально возможной производительностью и минимальным использованием системных ресурсов.

2 ответа

Решение

Объекты GDI ограничены как для процесса, так и для сеанса. Вы боретесь за ресурсы со всеми другими процессами, запущенными в том же сеансе. Имея это в виду, вы должны использовать ресурсы GDI только при необходимости (вариант 2 в вашем вопросе).

Запись в блоге Марка Руссиновича " Расширяя границы Windows: объекты USER и GDI - часть 2" подробно описана. Чтобы подвести итог, вот список ограничений, которые оконный менеджер накладывает на ресурсы GDI:

  • 10.000 объектов GDI на процесс (значение по умолчанию, настраивается через раздел реестра HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Windows \ GDIProcessHandleQuota).
  • 65,535 объектов GDI за сеанс пользователя.
  • Предел памяти объекта GDI - это предел выгружаемого пула (см. Расширение границ Windows: выгружаемый и невыгружаемый пул).

Вот тест, чтобы проверить, сколько времени потребуется, чтобы позвонить 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-битного 5 МБ растрового изображения:

CreateCompatibleDC: 17 микросекунд
BitBlt: 2500 микросекунд

Результат для 8bit 275kb:

CreateCompatibleDC: 12 микросекунд
BitBlt: 500 микросекунд

Другие вопросы по тегам