Увеличить скорость блинтинга?

9

Я работаю над 2-й боковой скроллер в PyGame. Для каждой карты мы используем одну текстуру (это фактический размер текстуры):

текстура карты

Затем мы загружаем изображение с этим кодом:

sprite = pygame.image.load("Maps/MapTesting.png")
sprite.convert()
sprite = pygame.transform.scale(sprite,
              (sprite.get_width()*6, sprite.get_height()*6))

Как видите, текстура взорвалась 6 раз, чтобы создать фактическую текстуру карты. В среднем эта текстура составляет около 4500x800. Эту текстуру нужно перетаскивать на экран каждый кадр , потому что весь экран загрязнен (благодаря боковой прокрутке). Мы делаем это с помощью этого кода:

screen.blit(sprite, (0, 0),
(cameraposx, cameraposy, windowheight, windowwidth))

И это работает. Проблема в том, что он довольно медленный: я получаю скудные 40 FPS на малоприличном ПК, и это без какого-либо реального AI / объектов, в то время как мы стремимся к 60 FPS. Как мы можем ускорить это?


Обратите внимание, что приведенный выше код очищен и вырван из контекста. Полный код можно найти здесь: https://github.com/nightcracker/PyGG2

И последнее, но не менее важное: хотя приведенное выше изображение может выглядеть как 8-битное, в игре есть элементы, требующие большей битовой глубины.

orlp
источник
Разбейте до нормального размера на текстуру, скажем, 1024 в ширину на блок, и разбейте только те два, которые актуальны одновременно.
Яри ​​Комппа
@JariKomppa: Попробовал, не влияет на блиттинг (pygame достаточно умен, чтобы бить только прямоугольник, о котором я говорю), только использование памяти.
orlp
Вы не могли бы ... не использовать pygame (trollface.jpg) .... jkjk, в этом случае я предполагаю, что это не то место, где происходит ваше замедление, вы тщательно его тестировали?
ультифинит
@ultifinitus: Да, я профилировал его с помощью cProfile.
orlp
Какая разница в скорости, если вы показываете ее в реальном разрешении? Что, если вы предварительно вычислите большее изображение?
ультифинит

Ответы:

7

Позвольте мне перечислить некоторые общие сравниваемые оптимизации, связанные с блиттингом пикселей на поверхности (из моего опыта).

1) Обычно изображения палитры (индексированные изображения) при блицировании будут подвергаться одному дополнительному уровню перенаправления (для получения цвета). Поэтому они будут медленными при блицании по сравнению с изображениями с истинным цветом.

2) Пиксельные данные истинного цвета (предположим, без альфа-канала, скажем, 24-битных данных) могут быть быстро скопированы, поскольку мы можем сделать memcpy для каждой строки развертки изображения (если мы копируем часть изображения) в буфер кадра устройства .Если данные, которые будут скопированы, представляют собой полное изображение, то мы можем напрямую запомнить все данные, что намного быстрее!

3) Пиксельные данные альфа-пикселя будут самыми дорогими, поскольку они будут включать вычисление результирующего каждого компонента, и нам нужно снова упаковать его в данные RGB. Проще говоря, больше операций для каждого пикселя для получения окончательного цвета!

Finalrgb = Alpha*(Srgb) + (1-Alpha)*Drgb (this is for normal blend equation)
    where Srgb is source-rgb (we need to apply for each of the component for final color)
       Drgb is the color that will be there in the destination buffer.

Я не работал над pyGame раньше. Но, беглый взгляд на его исходный код, заставил меня предположить, что он использует функции Blit 'sdl' под капотом. Обычно Sdl blit будет очень быстрым и оптимизированным, поэтому просто сделайте не из вышеупомянутых пунктов и профиль еще раз! Удачи!

* Обновление: * Установка цветового ключа похожа на добавление одной дополнительной проверки при перетаскивании каждого пикселя на поверхность. Что-то вроде этого -

       for(eachPixelColor in allPixels)
         {
            if(eachPixelColor is NOT colorKeyColor)
            {
              copy color to the frame buffer!
            }

         }

Итак, здесь, если вы видите, мы ограничены в использовании memcpy, поскольку нам нужно проверить правильность цвета каждого пикселя!

Ayyappa
источник
Хорошо, как выясняется, вызов set_colorkeyпроскользнул на текстуру карты, дав ей (дорогой) альфа-канал. Это convertисправлено, и теперь я использую 150 FPS стабильно на этом дерьмовом ПК. Спасибо!
orlp
эй отредактирует связанный с цветом ключ, даже забыл добавить некоторую информацию об этом: D
Ayyappa
5

sprite.convert() не делает то, что вы думаете, что делает.

sprite = sprite.convert() это то, что вам нужно.

Kylotan
источник
Woops, у меня есть sprite = sprite.convert()в реальном коде, хотя :)
orlp
Ага, хорошо :) В таком случае, я не могу предложить вам ничего, кроме как рассмотреть возможность использования pyglet вместо pygame или использовать pyOpenGL напрямую, если вы знакомы с OpenGL.
Kylotan
@ Килотан: хороший улов приятель! я не проверял это :)
Ayyappa
или, еще лучше:sprite = pygame.image.load("Maps/MapTesting.png").convert()
MestreLion