GDI双缓冲奇怪的慢

时间:2013-11-10 01:34:31

标签: c winapi gdi

所以我有一个用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()减速约两个数量级。关于这可能是什么的任何建议?

0 个答案:

没有答案