Я работаю над программой, которая будет иметь много растровых изображений DIB (созданных CreateDIBSection
) и придется рисовать на них много текста, используя Win API.
Для рисования на растровом изображении Windows необходим контекст устройства, созданный CreateCompatibleDC
,
А теперь вот два подхода:
Я могу создать DC один раз для каждого растрового изображения, используя его для рисования и удаляя его при освобождении растрового изображения.
Или я могу создать DC только тогда, когда мне нужно отрисовать растровое изображение, вызвать функции рисования и удалить DC.
Какой подход лучше? Я предпочитаю первое из-за меньшего количества вызовов — это сделает мой код намного меньше, а также немного быстрее.
Но не слишком ли дорого держать долгоживущий DC для каждого растрового изображения?
Edit1: Приложение на самом деле является библиотекой инструментария GUI, которая может использоваться в будущем непредсказуемым образом, поэтому мне нужно хорошо сбалансированное решение с максимально возможной производительностью и минимальным использованием системных ресурсов.
Объекты GDI ограничены как для процесса, так и для сеанса. Вы боретесь за ресурсы со всеми другими процессами, запущенными в том же сеансе. Имея это в виду, вы должны использовать ресурсы GDI только при необходимости (вариант 2 в вашем вопросе).
Запись в блоге Марка Руссиновича Расширение границ Windows: объекты USER и GDI — часть 2 входит в изрядное количество деталей. Чтобы подвести итог, вот список ограничений, которые оконный менеджер накладывает на ресурсы 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-битного 5 МБ растрового изображения:
CreateCompatibleDC
: 17 микросекунд
BitBlt
: 2500 микросекунд
Результат для 8bit 275kb:
CreateCompatibleDC
: 12 микросекунд
BitBlt
: 500 микросекунд