所以我有一个用C语言编写的老式GDI应用程序。它通过直接渲染到屏幕上重绘,只触摸每个像素一次。一切正常。
我现在需要升级它以使用更复杂的渲染系统,我不能保证每个像素都被触摸一次---渲染算法需要黑色背景。但是,如果我直接在屏幕上渲染,我会闪烁。所以我需要加倍缓冲。
我的问题是,在添加双缓冲之后,它的速度很慢,我不明白为什么。
在WM_SIZE中,我创建了一个离屏表面:
case WM_SIZE:
{
RECT rect;
GetClientRect(window, &rect);
HDC dc = GetDC(window);
/* omitting freeing cachedc and cachebitmap for brevity */
cachedc = CreateCompatibleDC(dc);
cachebitmap = CreateCompatibleBitmap(dc, rect.right, rect.bottom);
SelectObject(cachedc, cachebitmap);
ReleaseDC(window, dc);
break;
}
(请注意,对CreateCompatibleBitmap()
的调用使用dc
而不是cachedc
。我知道这个问题。)
然后在WM_PAINT中我进行绘制:
case WM_ERASEBKGND:
return 1;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(window, &ps);
FillRect(cachedc, &ps.rcPaint, GetStockObject(BLACK_BRUSH));
paint_cb(window, &ps, cachedc);
BitBlt(ps.hdc,
ps.rcPaint.left, ps.rcPaint.top,
ps.rcPaint.right, ps.rcPaint.bottom,
cachedc,
ps.rcPaint.left, ps.rcPaint.top,
SRCCOPY);
EndPaint(window, &ps);
break;
}
那是慢代码。但是,如果我改变WM_PAINT来执行此操作,那么它会快速运行(尽管有闪烁):
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(window, &ps);
FillRect(ps.hdc, &ps.rcPaint, GetStockObject(BLACK_BRUSH));
paint_cb(window, &ps, ps.hdc);
EndPaint(window, &ps);
break;
}
paint_cb()
太复杂了,无法在此处重现,但它的工作原理是在表面上插入大量的小位图(它是渲染文本,每个位图都是一个缓存的字形)。位图是按需创建的,然后缓存;它们在WM_SIZE中被丢弃。完全使用CreateCompatibleDC()
和CreateCompatibleBitmap()
创建位图,如上所述。
据我所知,上面的代码完全是香草。这意味着我必须进行某种假设,这是无效的。我的理由是:
通过屏幕外位图进行渲染很慢,因此在渲染过程中必须进行某种格式转换。
直接渲染很快,因此没有。
因此,paint_cb()
必须有不同的功能,具体取决于它是在屏幕上显示DC还是在屏幕外位图。
除了没有。 paint_cb()
既不知道也不关心。
???
我在这里缺少什么?我应该寻找什么?不知何故,我在上面的代码中所做的事情导致paint_cb()
减速约两个数量级。关于这可能是什么的任何建议?