问题
I am working on a program that will have many DIB bitmaps (created by CreateDIBSection
) and will have to draw a lot of text on them using Win API.
In order to draw on the bitmap, Windows needs device context, created by CreateCompatibleDC
.
And now here are two approaches:
I can create the DC once per bitmap, using it for drawing and delete it when freeing the bitmap.
Or I can create DC only when I need to draw to the bitmap, call the draw functions and delete the DC.
What is the better approach? I prefer the first, because of less calls - this will make my code much smaller and also a little bit faster.
But isn't it too expensive to hold a long living DC for every bitmap?
Edit1: The application is actually a GUI toolkit library that can be used in different and unpredictable way in the future, so I need a well balanced decision with maximal possible performance and minimal system resource usage.
回答1:
GDI objects are limited, both per process as well as per session. You are competing for resources with all other processes running in the same session. With that in mind, you should consume GDI resources only when needed (option 2 in your question).
Mark Russinovich's blog entry Pushing the Limits of Windows: USER and GDI Objects – Part 2 goes into a fair amount of detail. To sum up the gist, here is a list of limits that the window manager places on GDI resources:
- 10.000 GDI objects per process (default value, configurable through the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuota).
- 65.535 GDI objects per user session.
- GDI object memory limit is the paged pool limit (see Pushing the Limits of Windows: Paged and Nonpaged Pool).
回答2:
Here is a test to examine how long it take to call CreateCompatibleDC
. I find on average it takes about 10 to 15 microseconds to make each call. This is relatively fast compared to BitBlt
, specially for larger images. Therefore there is not much advantage in holding the memory 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;
}
Result on Windows 10:
Result for 24bit 5MB bitmap:
CreateCompatibleDC
: 17 microsecondsBitBlt
: 2500 microseconds
Result for 8bit 275kb:
CreateCompatibleDC
: 12 microsecondsBitBlt
: 500 microseconds
来源:https://stackoverflow.com/questions/33472482/how-cheap-expensive-is-memory-dc-in-win-api