2

所以我有一个用 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()。我知道那个问题。)dccachedc

然后在 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()在这里复制太复杂了,但它通过将大量小位图blitting到表面上来工作(它正在渲染文本,每个位图都是一个缓存的字形)。位图按需创建,然后缓存;它们在 WM_SIZE 中被丢弃。位图是使用CreateCompatibleDC()CreateCompatibleBitmap()完全如上创建的。

据我所知,上面的代码完全是香草。这意味着必须有某种我正在做出的假设是无效的。我的推理是:

  • 通过离屏位图渲染很慢,因此在渲染过程中必须进行某种格式转换。

  • 直接渲染速度很快,因此没有。

  • 因此,必须有一些事情paint_cb()在做不同的事情,具体取决于它是将 DC 放到屏幕上还是屏幕外位图上。

  • 除了没有。paint_cb()既不知道也不关心。

  • ???

我在这里想念什么?我应该寻找什么?不知何故,我在上面的代码中所做的事情导致paint_cb()速度降低了大约两个数量级。关于这可能是什么的任何建议?

4

0 回答 0