Zwiększyć prędkość blittingu?

9

Pracuję nad 2D SideCroller w PyGame. Dla każdej mapy używamy jednej tekstury (jest to faktyczny rozmiar tekstury):

tekstura mapy

Następnie ładujemy obraz za pomocą tego kodu:

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

Jak widać, tekstura zostaje wysadzona w powietrze 6 razy, aby utworzyć faktyczną teksturę mapy. Średnio ta tekstura ma około 4500 x 800. Ta tekstura musi być dopasowana do ekranu w każdej ramce , ponieważ cały ekran jest brudny (dzięki przewijaniu bocznemu). Robimy to za pomocą tego kodu:

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

I to działa. Problem polega na tym, że jest dość powolny: otrzymuję skromne 40 FPS na słabo przyzwoitym komputerze, i to bez żadnych faktycznych sztucznej inteligencji / obiektów, podczas gdy my dążymy do 60 FPS. Jak możemy to przyspieszyć?


Pamiętaj, że powyższy kod jest odkażony i wyjęty z kontekstu. Pełny kod można znaleźć tutaj: https://github.com/nightcracker/PyGG2

I na koniec, chociaż powyższy obraz może wyglądać jak 8-bitowy, w grze są elementy wymagające większej głębi bitowej.

orlp
źródło
Podziel na rozsądny rozmiar na teksturę, powiedzmy 1024 szerokość na blok i blituj tylko te dwa, które są istotne jednocześnie.
Jari Komppa,
@JariKomppa: Próbowałem, nie ma żadnego wpływu na blitting (pygame jest na tyle sprytny, by blitować tylko prostokąt, który mu mówię), tylko użycie pamięci.
orlp
Nie możesz ... nie używać pygame (trollface.jpg) .... jkjk, w tym przypadku zgaduję, że nie ma tam miejsca na spowolnienie, przetestowałeś go intensywnie?
ultifinitus
@ultifinitus: Tak, profilowałem go za pomocą cProfile.
lub
Jaka jest różnica prędkości, jeśli wyświetlasz ją w rzeczywistej rozdzielczości? Co się stanie, jeśli obliczysz większy obraz?
ultifinitus

Odpowiedzi:

7

Pozwól, że wymienię kilka ogólnych porównań optymalizacji związanych z Blittingiem pikseli na powierzchnię (z mojego doświadczenia).

1) Zwykle obrazy paletowe (obrazy indeksowane), kiedy są blted, przechodzą jeden dodatkowy poziom przekierowania (aby uzyskać kolor), więc będą one powolne podczas blitting w porównaniu do obrazów w prawdziwych kolorach.

2) Dane pikseli w rzeczywistym kolorze (załóżmy, że nie ma alfa - powiedzmy 24-bitowe dane) można bardzo szybko usunąć, ponieważ możemy wykonać memcpy dla każdej linii obrazu (jeśli kopiujemy część obrazu) w buforze ramki urządzenia .Jeśli dane, które mają zostać usunięte, to pełny obraz, wówczas możemy bezpośrednio zapisać w pamięci wszystkie dane, co jest znacznie szybsze!

3) Dane Blitting Alpha pixel będą najkosztowniejsze, ponieważ będą obejmowały obliczenie wyniku każdego komponentu i musimy go ponownie spakować do danych RGB. Mówiąc prościej, więcej operacji dla każdego piksela w celu uzyskania ostatecznego koloru!

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.

Nie pracowałem wcześniej nad pyGame, ale szybkie spojrzenie na jego kod źródłowy skłonił mnie do przypuszczenia, że ​​korzysta on z funkcji Blit „sdl” pod maską. Zwykle Sdl blit będzie bardzo szybszy i zoptymalizowany, więc po prostu powtórz powyższe punkty i profil jeszcze raz! Powodzenia!

* Aktualizacja: * Ustawienie klucza koloru jest jak dodanie jednego dodatkowego zaznaczenia podczas blitowania każdego piksela na powierzchni. Niektóre rzeczy takie jak -

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

         }

Więc tutaj, jeśli widzisz, jesteśmy ograniczeni, aby nie używać memcpy, ponieważ musimy sprawdzić poprawność kolorów każdego piksela!

Ayyappa
źródło
Ok, jak się okazuje wezwanie do set_colorkeywślizgnięcia się w teksturę mapy, co daje (drogi) kanał alfa. convertUstalone, że i teraz biegnę 150 FPS stabilne na to gówno PC. Dzięki!
lub
hej edytuje związane z kluczem koloru, nawet zapomniałem dodać trochę informacji o nim: D
Ayyappa 30.09.11
5

sprite.convert() nie robi tego, co myślisz.

sprite = sprite.convert() jest to, czego potrzebujesz.

Kylotan
źródło
Ups, mam jednak sprite = sprite.convert()prawdziwy kod :)
lub
Aha dobrze. :) W takim przypadku nie mam wiele do zaoferowania, oprócz rozważenia użycia Pyglet zamiast Pygame lub bezpośredniego użycia PyOpenGL, jeśli nie masz nic przeciwko OpenGL.
Kylotan
@Kylotan: good catch mate! jeszcze tego nie sprawdziłem :)
Ayyappa,
lub nawet lepiej:sprite = pygame.image.load("Maps/MapTesting.png").convert()
MestreLion