Почему рисование на графике OnPaint быстрее, чем графическое изображение? - PullRequest
7 голосов
/ 05 апреля 2010

Я ищу способ ускорить отрисовку моего игрового движка, который в настоящее время является существенным узким местом и вызывает замедление. Я на грани преобразования его в 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 и т. Д., Но ничто из того, что я делаю, не устраняет этот невероятный разрыв в производительности. Я не могу найти никакой разницы между двумя графическими объектами. Что дает?

Мой тест с System.Diagnostics.Stopwatch говорит, что первый фрагмент кода работает со скоростью около 7100 кадров в секунду, а второй - со слабыми 280 кадрами в секунду. Мое эталонное изображение VS2010ImageLibrary\Objects\png_format\WinVista\SecurityLock.png, что составляет 48x48 пикселей, и я изменил его на 72 dpi вместо 96, но они также не имели никакого значения.

Ответы [ 3 ]

1 голос
/ 06 апреля 2010

Я получаю ~ 5 мсек для обоих. 7100 кадров в секунду - это way слишком быстро для программного рендеринга, выполняемого GDI +. Драйверы видео, как известно, обманывают, чтобы выиграть тесты, они могут обнаружить, что BitBlt не нужно выполнять, потому что изображение не изменилось. Попробуйте передать случайные значения в e.Graphics.TranslateTransform, чтобы убрать чит.

1 голос
/ 05 апреля 2010

Когда вы рисуете на экран, ОС может использовать преимущества специального оборудования в графическом адаптере для выполнения простых операций, таких как копирование изображения вокруг.

0 голосов
/ 06 апреля 2010

Вы уверены, что отличие не от блока using, то есть для настройки блока try-finally и создания экземпляра Graphics из буфера изображений.

Я мог бы легко увидеть последнее как дорогостоящую операцию, в отличие от события рисования, когда вы просто получаете ссылку на уже созданный графический экземпляр.

...