从 COLORREF[] 中提取 DeviceContext
我有一个指向 COLORREF 缓冲区的指针,类似于: COLORREF* buf = new COLORREF[x*y];
子例程用颜色信息填充此缓冲区。每个 COLORREF 代表一个像素。
现在我想将此缓冲区绘制到设备上下文。我当前的方法有效,但速度相当慢(==每次绘制约 200 毫秒,具体取决于图像的大小):
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。
I have a pointer to a COLORREF buffer, something like: COLORREF* buf = new COLORREF[x*y];
A subroutine fills this buffer with color-information. Each COLORREF represents one pixel.
Now I want to draw this buffer to a device context. My current approach works, but is pretty slow (== ~200ms per drawing, depending on the size of the image):
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]);
}
Is there a way to do this faster; all at once, not one pixel after another?
I am not really familiar with the GDI. I heard about al lot of APIs like CreateDIBitmap(), BitBlt(), HBITMAP, CImage and all that stuff, but have no idea how to apply it. It seems all pretty complicated...
MFC is also welcome.
Any ideas?
Thanks in advance.
(Background: the subroutine I mentioned above is an OpenCL kernel - the GPU calculates an Mandelbrot image and safes it in the COLORREF buffer.)
EDIT:
Thank you all for your suggestions. The answers (and links) gave me some insight into Windows graphics programming. The performance is now acceptable (semi-realtime-scrolling into the Mandelbrot works :)
I ended up with the following solution (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();
So basically CBitmap::CreateBitmap() saved me from using the raw API (which I still do not fully understand). The example in the documentation of CDC::CreateCompatibleDC was also helpful.
My Mandelbrot is now blue - using SetPixelV() it was red. But I guess that has something to do with CBitmap::CreateBitmap() interpreting my buffer, not really important.
I might try the OpenGL suggestion because it would have been the much more logical choice and I wanted to try OpenCL under Linux anyway.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在这种情况下,我可能会使用 DIB 部分(您使用
CreateDIBSection
)。 DIB 部分是一个位图,允许您直接以数组形式访问内容,但仍将其与所有常用的 GDI 函数一起使用。我认为这将为您带来基于 GDI 的最佳性能。如果您需要更好的,那么 @Kornel 基本上是正确的 - 您需要切换到对硬件加速有更直接支持的东西(DirectX 或 OpenGL - 尽管在我看来,OpenGL是一个更好的选择比 DirectX 更好的选择)。
鉴于您当前正在 OpenCL 中进行计算并将输出存储在颜色缓冲区中,OpenGL 将是真正显而易见的选择。特别是,您可以让 OpenCL 将输出存储在 OpenGL 纹理中,然后让 OpenGL 使用该纹理绘制一个四边形。或者,由于您只是将输出放在屏幕上,因此您可以在 OpenGL 片段着色器(或者当然是 DirectX 像素着色器)中进行计算,因此您不会将输出放入屏幕外的内存中这样您就可以将结果复制到屏幕上。如果没记错的话,橙皮书中有一个 Mandelbrot 着色器作为示例之一。
Under the circumstances, I'd probably use a DIB section (which you create with
CreateDIBSection
). A DIB section is a bitmap that allows you to access the contents directly as an array, but still use it with all the usual GDI functions.I think that'll give you the best performance of anything based on GDI. If you need better, then @Kornel is basically correct -- you'll need to switch to something that has more direct support for hardware acceleration (DirectX or OpenGL -- though IMO, OpenGL is a much better choice for the job than DirectX).
Given that you're currently doing the calculation in OpenCL and depositing the output in a color buffer, OpenGL would be the really obvious choice. In particular, you can have OpenCL deposit the output in an OpenGL texture, then you have OpenGL draw a quad using that texture. Alternatively, since you're just putting the output on screen anyway, you could just do the calculation in an OpenGL fragment shader (or, of course, a DirectX pixel shader), so you wouldn't put the output into memory off-screen just so you can copy the result onto the screen. If memory serves, the Orange book has a Mandelbrot shader as one of its examples.
是的,当然,这很慢。您正在为每个单独的像素在内核和视频设备驱动程序中进行往返。您可以通过先绘制到内存中,然后一口气更新屏幕来加快速度。例如,这需要 CreateDIBitmap、CreateCompatibleDc() 和 BitBlt()。
现在不是进行有关图形编程的大量教程的好时机和地点。有关 GDI 和/或 Windows API 编程的任何介绍性文本都很好地涵盖了它。您需要了解的一切都可以在 Petzold 的开创性编程 Windows 中找到。
Yes, sure, that's slow. You are making a round-trip through the kernel and video device driver for each individual pixel. You make it fast by drawing to memory first, then update the screen in one fell swoop. That takes, say, CreateDIBitmap, CreateCompatibleDc() and BitBlt().
This isn't a good time and place for an extensive tutorial on graphics programming. It is well covered by any introductory text on GDI and/or Windows API programming. Everything you'll need to know you can find in Petzold's seminal Programming Windows.
由于您已经有了一个像素数组,因此可以直接使用 BitBlt 将其传输到窗口的 DC。请参阅此链接以获取部分示例:
http://msdn.microsoft.com/en-us/library/aa928058。 ASPX
Since you already have an array of pixels, you can directly use BitBlt to transfer it to the window's DC. See this link for a partial example:
http://msdn.microsoft.com/en-us/library/aa928058.aspx