从COLORREF []上绘制DeviceContext

时间:2010-08-28 19:22:45

标签: c++ winapi mfc gdi device-context

我有一个指向COLORREF缓冲区的指针,类似于:COLORREF* buf = new COLORREF[x*y];

子程序用颜色信息填充此缓冲区。每个COLORREF代表一个像素。

现在我想将此缓冲区绘制到设备上下文中。我当前的方法有效,但速度很慢(每个绘图== ~200ms,具体取决于图像的大小):

for (size_t i = 0; i < pixelpos; ++i) 
{
    // Get X and Y coordinates from 1-dimensional buffer.
    size_t y = i / wnd_size.cx;
    size_t x = i % wnd_size.cx;
    ::SetPixelV(hDC, x, y, buf[i]);
}

有没有办法更快地完成这项工作;一次又一次,不是一个接一个的像素?
我对GDI并不熟悉。我听说过很多API,比如CreateDIBitmap(),BitBlt(),HBITMAP,CImage等等,但不知道如何应用它。看来一切都很复杂...... MFC也很受欢迎。

有什么想法吗?

提前致谢。

(背景:我上面提到的子程序是OpenCL内核 - GPU计算Mandelbrot图像并将其保存在COLORREF缓冲区中。)

修改
谢谢大家的建议。答案(和链接)让我对Windows图形编程有了一些了解。性能现在可以接受(半实时滚动到Mandelbrot工作:) 我最终得到了以下解决方案(MFC):

...
CDC dcMemory;
dcMemory.CreateCompatibleDC(pDC);

CBitmap mandelbrotBmp;
mandelbrotBmp.CreateBitmap(clientRect.Width(), clientRect.Height(), 1, 32, buf);

CBitmap* oldBmp = dcMemory.SelectObject(&mandelbrotBmp);
pDC->BitBlt(0, 0, clientRect.Width(), clientRect.Height(), &dcMemory, 0, 0, SRCCOPY);

dcMemory.SelectObject(oldBmp);
mandelbrotBmp.DeleteObject();

所以基本上CBitmap :: CreateBitmap()使我免于使用原始API(我仍然不完全理解)。 CDC::CreateCompatibleDC文档中的示例也很有用 我的Mandelbrot现在是蓝色的 - 使用SetPixelV()它是红色的。但我想这与CBitmap :: CreateBitmap()解释我的缓冲区有关,这并不重要。

我可能会尝试OpenGL建议,因为它本来是更合乎逻辑的选择,我想在Linux下试用OpenCL。

3 个答案:

答案 0 :(得分:2)

是的,当然,这很慢。您正在通过内核和视频设备驱动程序为每个像素进行往返。你先通过绘制内存来快速创建,然后一下子更新屏幕。例如,CreateDIBitmap,CreateCompatibleDc()和BitBlt()。

这不是一个关于图形编程的广泛教程的好时间和地点。关于GDI和/或Windows API编程的任何介绍性文本都对此有很好的介绍。您需要了解的所有内容都可以在Petzold的开创性编程Windows中找到。

答案 1 :(得分:2)

由于您已经有一个像素数组,您可以直接使用BitBlt将其传输到窗口的DC。有关部分示例,请参阅此链接: http://msdn.microsoft.com/en-us/library/aa928058.aspx

答案 2 :(得分:2)

在这种情况下,我可能会使用DIB部分(您使用CreateDIBSection创建)。 DIB部分是一个位图,允许您直接以数组的形式访问内容,但仍然将它与所有常用的GDI函数一起使用。

我认为这将为您提供基于GDI的最佳性能。如果你需要更好,那么@Kornel基本上是正确的 - 你需要切换到更直接支持硬件加速的东西(DirectX OpenGL - 虽然IMO,OpenGL要好得多比DirectX更适合工作。

鉴于您目前正在OpenCL中进行计算并将输出存储在颜色缓冲区中,OpenGL将成为真正明显的选择。特别是,您可以让OpenCL将输出存放在OpenGL纹理中,然后让OpenGL使用该纹理绘制四边形。或者,因为您只是将输出放在屏幕上,您可以在OpenGL片段着色器(或者当然是DirectX像素着色器)中进行计算,因此您不会将输出放在屏幕外的内存中只是这样你就可以将结果复制到屏幕上。如果内存服务,橙色书有一个Mandelbrot着色器作为其中一个例子。