【问题标题】:C++ Win32: Speeding up Bitmap OperationsC++ Win32:加速位图操作
【发布时间】:2015-11-08 16:50:09
【问题描述】:

我希望加快位图显示程序的速度。它不是非常慢,我只是认为它可以更快。我在 Win32 环境中运行它。代码如下:

void load(LPCWSTR file, int i) {
    hBitmap[i] = (HBITMAP)::LoadImage(NULL, file, IMAGE_BITMAP, 0, 0,
        LR_LOADFROMFILE);
    GetObject(hBitmap[i], sizeof(BITMAP), (LPSTR)&hSize[i]);
}
void newBit(int i, int x, int y, HDC hdc) {

    BITMAP Bitmap = hSize[i];
    HBITMAP hBit = hBitmap[i];

    HDC hDCBits = CreateCompatibleDC(hdc);
    SelectObject(hDCBits, hBit);
    StretchBlt(hdc, x, y, Bitmap.bmWidth, Bitmap.bmHeight,
        hDCBits, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, SRCCOPY);
    DeleteDC(hDCBits);
}

我在开始时运行“加载”功能,我可以接受需要多长时间。每当在程序中需要时,我都会运行 newBit 函数。我特别使用了 stretchBlt 命令,因为我需要调整大小的能力。任何对我做错了什么以及我可以改进的地方的见解将不胜感激。

【问题讨论】:

  • 您需要将SelectObject(hDCBits, hBit); 的结果保存到HBITMAP,然后在删除HDC 之前将其选回hDCBits。不这样做会导致资源泄漏。 GDI 句柄是有限的资源。此外,由于您正在缓存已加载的图像 - 您应该添加另一个变量,以便您只创建和销毁一次 HDC。您可以通过调用 GetCurrentObject(hDCBits, OBJ_BITMAP); 来获取其中选择的初始位图,这样 (a) 您只需保存一次副本,并且 (b) 您可以在最终销毁 HDC 之前恢复此位图。

标签: c++ winapi bitmap gdi stretchblt


【解决方案1】:

由于我怀疑它与您之前的问题here 有关系,因此我发布以下答案。

如果您想在窗口中创建一些动画并想加快速度,请考虑使用 GDI+ 而不是纯 winapi。 使用 GDI+,您只需将绘图方法放入 WM_PAINT 消息中,然后通过使控件矩形无效并更新窗口来更新您的场景。
比如这样的:

InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);

WM_PAINT 消息处理可能如下所示:

case WM_PAINT:
{
    /************************************************************************/
    /* Initialize                                                           */
    /************************************************************************/
    hdc = BeginPaint(hwnd, &ps);
    Graphics graphics(hdc);
    Bitmap *pMemBitmap = new Bitmap(rect.right, rect.bottom);
    Graphics* pMemGraphics = Graphics::FromImage(pMemBitmap);
    SolidBrush back(Color(0, 0, 0));
    pMemGraphics->FillRectangle(&back, 0, 0, rect.right, rect.bottom); // Fill your background with some color
    pMemGraphics->SetSmoothingMode(SmoothingModeHighQuality); // Set your raster quality
    graphics.SetSmoothingMode(SmoothingModeHighQuality);

    // Rotate some primitive around your screen
    static double x = M_PI + M_PI / 2;
    x += 0.03f;

    if(x > M_PI * 2)
    {
        x = 0;
    }
    double posX = cos(x);
    double posY = sin(x);

    Pen pen(Color(255, 255, 255, 0), 5);
    pMemGraphics->DrawEllipse(&pen, (int)(posX * 50 - 15 + rect.right / 2), (int)(posY * 50 - 15 + rect.bottom / 2), 30, 30);
    graphics.DrawImage(pMemBitmap, 0, 0); // Draw the entire bitmap to screen (double buffering)

    /************************************************************************/
    /* Cleanup                                                              */
    /************************************************************************/
    delete pMemGraphics;
    delete pMemBitmap;
    EndPaint(hwnd, &ps);
    break;
}

为了避免闪烁,你应该告诉winapi不要像这样擦除背景:

case WM_ERASEBKGND:
{
    return true; // Tell winapi, we already handled that.
}

【讨论】:

  • 这可能不会发生。一个可能的原因可能是:GDI+ 不会让您获得更多性能。它是在软件中实现的,通常比 GDI 慢。使用Windows Imaging ComponentDirect2D 渲染表面更有可能提高性能。
  • 我仍然认为,使用 GDI+ 会比普通的 winapi 表现更好。当然,他可以使用一些 GPU 加速库,如 OpenGL 或 Direct2D,但根据我读到的他想做的,GDI+ 就足够了。
  • GDI is hardware accelerated (用于此问题中使用的操作)。但是,将SmoothingModeHighQuality 与 GDI+ 一起使用不会利用 GPU 硬件,并且会(显着)比普通的 GDI 实现慢。想一想,也许 Direct2D 也不能提高这种简单场景的性能。但是,如果涉及任何处理/过滤,它会。
  • 好吧,我知道 GDI+ 没有任何硬件加速。我发布的代码示例只是为了帮助 Jacob 开始使用 GDI+。我只是觉得,在他的情况下使用 GDI+ 还是不错的。
  • 问题是寻求帮助,提高性能。 GDI+ 对很多事情都有帮助,但它不是这个问题的答案。
猜你喜欢
  • 1970-01-01
  • 2018-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多