图像绘制速度

时间:2015-01-02 16:44:36

标签: c# winforms performance system.drawing

我正在开发游戏,但目前我正在运行基准测试。

如果有人可以帮我解决这个问题,我将不胜感激。

我正在做的是,当我点击开始按钮时,我在面板上触发绘制事件,使用以下代码:

    private void startToolStripMenuItem_Click(object sender, EventArgs e)
    {
        try
        {
            pnlArea.Invalidate();

        }
        catch (Exception)
        {
            throw;
        }
    }

然后我在我的绘画活动中这样做:

    private void pnlArea_Paint(object sender, PaintEventArgs e)
    {
        try
        {
            stopwatch = new Stopwatch();
            // Begin timing
            stopwatch.Start();

            if (gameStatus == GameStatus.PlaceHead)
            {
                e.Graphics.DrawImage(dictHead["HeadRight"], 100, 100, 15, 15);
            }

            //e.Graphics.Clear(Color.White);

            if (gameStatus == GameStatus.GameTest)
            {
                int x = 0;
                int y = 0;
                for (int i = 0; i < 5000; i++)
                {
                    x += 15;
                    if (x > 1000)
                    {
                        x = 0;
                        y += 15;
                    }

                    e.Graphics.DrawImage(body.Value, x, y, 15, 15);

                }
            }

            toolTimer.Text = Math.Round((stopwatch.Elapsed.TotalMilliseconds / 1000), 2).ToString() + "s";

            // Stop timing
            stopwatch.Stop();
        }
        catch (Exception)
        {

            throw;
        }
    }

这是我在上面的代码中绘制的正文部分:

enter image description here

这是确切的尺寸 - &gt; 15px x 15px

但有时需要1.2秒! 有什么方法可以改善这个吗?

这是最终结果屏幕的示例: enter image description here

2 个答案:

答案 0 :(得分:5)

您需要考虑如何最大限度地减少您进行的绘图调用次数。目前,您绘制5000个小盒子以生成网格。每次绘制一个框时,都会执行几条指令,然后调用图形方法来渲染缩放图像。这对于每个网格方块来说都是很多开销。

所以你可以看到的第一件事就是找到更有效的方法来绘制图像 - 例如,DrawImageUnscaled可能比DrawImage工作得更快,并达到你想要的效果。但这是低效算法的优化 - 要获得真正的性能优势,您需要做的就是看看是否可以采用新的,更高效的算法。

如果必须使用位图进行渲染,那么请查看模式如何重复 - 您是否可以创建一个更大的位图来提供4x4或16x16的单元格组,然后渲染它?还是一个代表整个列或行的位图?然后你可以使用50个调用而不是5000个来进行渲染。

但如果您不需要使用位图渲染,您可以做得更好。例如,如果您gfx.Clear(backgroundColor)然后向下和向下绘制大约140条黑线,则只需141次调用即可创建相同的显示。或者,如果你绘制大约70个矩形,你可以有效地每次调用2行。这大大减少了你必须进行的方法调用次数,并允许图形系统使用高度优化的线渲染和矩形渲染程序在一个爆发中绘制更多的像素(实际上,由于系统知道线条始终是垂直和水平的,因此矩形可能比广义线明显更快。)

(如果有些位不遵循此模式,那么您是否仍然可以渲染背景网格,然后在顶部绘制更改?)

接下来,如果图像的只有一小部分区域从一帧变为另一帧,那么即使其中4999个没有变化,你的算法也将绘制5,000个盒子(或者当1个就足够时为70个矩形)。如果您(a)只使视图中需要更改的部分无效,并且(b)编写渲染例程以确定哪些网格方块在剪辑边界之外,因此绘制毫无意义,那么您可以大大改善问题。这可能会减少您对每帧绘制1个矩形而不是5000个的更新。 (实现相同目标的另一种方法是将图像保留在屏幕外的位图中,只需在其上绘制更改。当您将其渲染到主屏幕显示时,图形卡将为您剪辑并获得相同的结果 - 更快的重绘速度)

所有关于通过&#34;懒惰&#34;来实现相同的显示。并且在横向思考尽可能少的工作。 (让计算机更快地运行总是归结为要求它做得更少)

答案 1 :(得分:1)

除了每个人都给我的信息之外,我还得出结论来对面板进行双重缓冲。这解决了我的问题 - &gt;

class DoubleBufferedPanel : Panel { public DoubleBufferedPanel() : base() { DoubleBuffered = true; } }

我只是使用了这个双缓冲面板。

新基准,完全没有闪烁! : enter image description here