CreateCompatibleBitmap和CreateDIBSection(内存DC)

11
从我在这里读到的内容来看,大多数Windows GDI函数都是加速的。因此,例如对BitBltAlphaBlend的调用会使用硬件加速(如果可用)。它还提到窗口的内容仅保留在视频内存中。现在,这对于窗口DC来说非常好和正确,但是我如何使用驻留在视频卡内存中的内存DC?一旦我们完成了这个过程,如何直接访问像素,我认为这将涉及以下三个步骤:1.将数据暂时复制到系统内存中2.更改像素数据3.复制回视频内存。

我尝试了两种方法,都分配了系统内存,可以在任务管理器中看到...

  1. CreateCompatibleBitmap

    HDC hDC = GetDC(NULL);
    m_hDC = CreateCompatibleDC(hDC);
    m_hBmp = CreateCompatibleBitmap(hDC, cx, cy);
    ReleaseDC(NULL, hDC);
    
    m_hOldBmp = (HBITMAP)SelectObject(m_hDC, m_hBmp);
    

    and then call to obtain the bits

    GetBitmapBits(...)
    

    according to various comments this should indeed create the compatible bitmap in video memory, but why can I still see an increase in system memory (even when I don't call GetBitmapBits)?

  2. CreateDIBSection

    HDC hDC = GetDC(NULL);
    m_hDC = CreateCompatibleDC(hDC);
    
    BITMAPINFO bmi;
    memset(&bmi, 0, sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = cx;
    bmi.bmiHeader.biHeight = -cy; // top-down
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;
    m_hBmp = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&m_pBits, NULL, NULL);
    
    ReleaseDC(NULL, hDC);
    
    m_hOldBmp = (HBITMAP)SelectObject(m_hDC, m_hBmp);
    

    in this case we receive the pointer to the bits immediately (m_pBits) so it's obvious that these reside in system memory...

还是说这是一个在系统内存中保留的副本,供两种方法使用?但如果我改变了系统内存中的位,调用BitBlt仍然需要再次检查/复制系统内存... 在我看来并不是很优化。

编辑:我还尝试使用BeginBufferedPaintGetBufferedPaintBits创建内存DC。它也分配系统内存,因此在这方面,我想它只是上述方法的包装器,但缓存DC,因此下一次调用不一定必须重新创建内存DC。请参见雷蒙德·陈的article

编辑#2:我想实际问题是:我是否正确地在方法1或2中创建内存DC以获得硬件加速的GDI操作?对我来说,它们都似乎很快,而且两种方法提供的速度也相同,所以没有真正的方法来检查它...


2
仅用于位块传送操作的GDI功能在Windows 7上独占硬件加速。即使在Windows 7上,GDI +仍然是软件渲染,速度仍然慢得多。如果您正在进行任何复杂的需要性能的操作,则简单的答案是不要使用GDI。如果您想直接访问硬件,请使用OpenGL或DirectX。 GDI始终是一个抽象。 - AJG85
2
据我所读,除了 Vista(由于其新引入的驱动程序设计)之外,每个 Windows 版本上的 GDI 函数都是硬件加速的。顺便说一下,我不使用 GDI+,也不建议任何人再使用它,因为它在 Win7 中没有硬件加速。 - demorge
GDI在Windows XP中被弃用,取而代之的是GDI+,然后在Vista中重新引入了GDI,但没有硬件加速。最终,在Windows 7中他们意识到了自己的错误。无论如何,是否支持MS-GDI仍取决于显示适配器驱动程序。 - AJG85
2
此外,检查系统内存是否被使用并不是硬件加速图形的有效指标。根据图形芯片甚至驱动程序的不同,纹理数据可能存储或备份在系统内存中(例如OpenGL的默认行为)。GDI本身就是硬件加速的,但您无法实际控制它。如果您需要控制,我同意AJG85的建议,应该使用图形API。 - Knowleech
因此,BitBlt API 被硬件加速,而大多数其他 GDI 操作则没有。 - KANJICODER
显示剩余2条评论
1个回答

6

内存DC并不是在设备上创建的。它们旨在将GDI输出放入内存中。

来自MSDN上的Memory Device Contexts

为了使应用程序能够将输出放置在内存中而不是发送到实际设备,可以使用一种称为内存设备上下文的专用设备上下文进行位图操作。内存DC使系统将一部分内存视为虚拟设备。

如果您想要硬件加速的2D图形,则应考虑使用Direct2D


啊,这让事情变得清晰了,它还说:在调色板设备上显示从DIB或DDB创建的图像时,您可以通过排列逻辑调色板以匹配系统调色板的布局来提高绘制图像的速度。这表明CreateCompatibleBitmap应该是最快的方法,但由于我的系统以32位颜色运行,因此使用32位布局的CreateDIBSection同样快(这两个函数创建的是相同的位图格式)。 - demorge
从我使用Direct2D和GDI的性能经验来看,我不建议使用Direct2D。它速度比较慢,与GDI差不多。 - Trinidad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接