为什么绘制 OnPaint 图形比绘制图像图形更快?
我正在寻找一种方法来加快游戏引擎的绘制速度,这是目前的重大瓶颈,并导致速度减慢。我即将将其转换为 XNA,但我刚刚注意到一些事情。
假设我已经加载了一张小图像。
Image img = Image.FromFile("mypict.png");
我们在屏幕上有一个我们想要绘图的图片框。所以我们有一个处理程序。
pictureBox1.Paint += new PaintEventHandler(pictureBox1_Paint);
我希望我们加载的图像平铺在图片框上(毕竟这是一个游戏)。到底为什么是这段代码:
void pictureBox1_Paint(object sender, PaintEventArgs e)
{
for (int y = 0; y < 16; y++)
for (int x = 0; x < 16; x++)
e.Graphics.DrawImage(image, x * 16, y * 16, 16, 16);
}
比这段代码快 25 倍以上:
Image buff = new Bitmap(256, 256, PixelFormat.Format32bppPArgb); // actually a form member
void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (Graphics g = Graphics.FromImage(buff))
{
for (int y = 0; y < 16; y++)
for (int x = 0; x < 16; x++)
g.DrawImage(image, x * 16, y * 16, 16, 16);
}
e.Graphics.DrawImage(buff, 0, 0, 256, 256);
}
为了消除明显的问题,我尝试注释掉最后一个 e.Graphics.DrawImage (这意味着我没有看到任何东西,但它摆脱了一个调用不在第一个示例中)。在第一个示例中,我还保留了 using 块(不必要),但它仍然非常快。我已将 g
的属性设置为匹配 e.Graphics
- 例如 InterpolationMode
、CompositingQuality
等,但是我所做的任何事情都无法弥补这种令人难以置信的绩效差距。我找不到两个 Graphics 对象之间的任何区别。什么给?
我使用 System.Diagnostics.Stopwatch 进行的测试表明,第一个代码片段的运行速度约为 7100 fps,而第二个代码片段的运行速度仅为 280 fps。我的参考图像是 VS2010ImageLibrary\Objects\png_format\WinVista\SecurityLock.png,大小为 48x48 像素,我将其修改为 72 dpi 而不是 96,但这些也没有区别。
I'm looking for a way to speed up the drawing of my game engine, which is currently the significant bottleneck, and is causing slowdowns. I'm on the verge of converting it over to XNA, but I just noticed something.
Say I have a small image that I've loaded.
Image img = Image.FromFile("mypict.png");
We have a picturebox on the screen we want to draw on. So we have a handler.
pictureBox1.Paint += new PaintEventHandler(pictureBox1_Paint);
I want our loaded image to be tiled on the picturebox (this is for a game, after all). Why on earth is this code:
void pictureBox1_Paint(object sender, PaintEventArgs e)
{
for (int y = 0; y < 16; y++)
for (int x = 0; x < 16; x++)
e.Graphics.DrawImage(image, x * 16, y * 16, 16, 16);
}
over 25 TIMES FASTER than this code:
Image buff = new Bitmap(256, 256, PixelFormat.Format32bppPArgb); // actually a form member
void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (Graphics g = Graphics.FromImage(buff))
{
for (int y = 0; y < 16; y++)
for (int x = 0; x < 16; x++)
g.DrawImage(image, x * 16, y * 16, 16, 16);
}
e.Graphics.DrawImage(buff, 0, 0, 256, 256);
}
To eliminate the obvious, I've tried commenting out the last e.Graphics.DrawImage (which means I don't see anything, but it gets rid a call that isn't in the first example). I've also left in the using block (needlessly) in the first example, but it's still just as blazingly fast. I've set properties of g
to match e.Graphics
- things like InterpolationMode
, CompositingQuality
, etc, but nothing I do bridges this incredible gap in performance. I can't find any difference between the two Graphics objects. What gives?
My test with a System.Diagnostics.Stopwatch
says that the first code snippet runs at about 7100 fps, while the second runs at a measly 280 fps. My reference image is VS2010ImageLibrary\Objects\png_format\WinVista\SecurityLock.png
, which is 48x48 px, and which I modified to be 72 dpi instead of 96, but those made no difference either.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当您在屏幕上绘图时,操作系统能够利用图形适配器中的特殊硬件来执行简单的操作,例如复制图像。
When you're drawing to the screen, the OS is able to take advantage of special hardware in the graphics adapter to do simple operations such as copying an image around.
我的两者都得到了〜5毫秒。对于 GDI+ 完成的软件渲染来说,7100 fps 太快了。视频驱动程序为了赢得基准测试而作弊是出了名的,他们可以检测到不必执行 BitBlt,因为图像没有改变。尝试将随机值传递给 e.Graphics.TranslateTransform 以消除作弊。
I'm getting ~5 msec for both. 7100 fps is way too fast for the software rendering done by GDI+. Video drivers notoriously cheat to win benchmarks, they can detect that a BitBlt doesn't have to be performed because the image didn't change. Try passing random values to e.Graphics.TranslateTransform to eliminate the cheat.
您确定区别不是来自 using-block,即设置 try-finally 块并从图像缓冲区创建 Graphics 实例。
我可以很容易地看到后者是一项昂贵的操作,与绘制事件不同,在绘制事件中您只需获取对已创建的图形实例的引用。
Are you sure the difference isn't from the using-block, i.e. setting up the try-finally block and creating the Graphics instance from the image buffer.
I could easily see the latter as being an expensive operation, unlike the paint event where you simply get a reference to an already created graphics instance.