Augmentez la vitesse de blitting?

9

Je travaille sur un sidecroller 2D dans PyGame. Pour chaque carte, nous utilisons une texture (c'est la taille réelle de la texture):

texture de la carte

Ensuite, nous chargeons l'image avec ce code:

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

Comme vous pouvez le voir, la texture est gonflée 6 fois pour créer la texture réelle de la carte. En moyenne, cette texture est d'environ 4500x800. Cette texture doit être fusionnée à l'écran à chaque image , car tout l'écran est sale (grâce au défilement latéral). Nous faisons cela en utilisant ce code:

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

Et il fonctionne. Le problème est qu'il est assez lent: j'obtiens un maigre 40 FPS sur un PC peu décent, et cela sans aucun véritable AI / objets en cours, alors que nous visons 60 FPS. Comment pouvons-nous accélérer cela?


Notez que le code ci-dessus est nettoyé et sorti de son contexte. Le code complet peut être trouvé ici: https://github.com/nightcracker/PyGG2

Enfin et surtout, bien que l'image ci-dessus puisse ressembler à 8 bits, il existe des éléments dans le jeu qui nécessitent plus de profondeur de bits.

orlp
la source
Divisez en une taille saine par texture, disons 1024 de large par bloc, et ne blit que les deux qui sont pertinentes à la fois.
Jari Komppa
@JariKomppa: J'ai essayé, cela n'a aucun effet sur le blitting (pygame est assez intelligent pour blit seulement le recto auquel je le dis), seulement l'utilisation de la mémoire.
orlp
Vous pourriez ... ne pas utiliser pygame (trollface.jpg) .... jkjk, dans ce cas, je suppose que ce n'est pas là que se produit votre ralentissement, l'avez-vous testé de manière approfondie?
ultifinitus
@ultifinitus: Oui, je l'ai profilé avec cProfile.
orlp
Quelle est la différence de vitesse si vous l'affichez à sa résolution réelle? Et si vous précalculez l'image plus grande?
ultifinitus

Réponses:

7

Permettez-moi d'énumérer quelques optimisations comparées générales liées au pixelage de pixels sur une surface (d'après mon expérience).

1) Habituellement, les images de palette (images indexées) lorsqu'elles sont mélangées, subissent un niveau supplémentaire de redirection (pour obtenir la couleur) .Ainsi, elles seront lentes lors du blitting par rapport aux images en couleurs vraies.

2) Les données de pixels en couleurs vraies (supposons sans Alpha - disons des données de 24 bits) peuvent être fusionnées très rapidement car nous pouvons faire une memcpy pour chaque ligne de balayage de l'image (si nous copions une partie de l'image) sur le tampon de trame de l'appareil .Si les données à fusionner sont une image complète, nous pouvons directement mémoriser toutes les données, ce qui est beaucoup plus rapide!

3) Blitting Alpha pixel data sera le plus coûteux car il comprendra le calcul de la résultante de chaque composant et nous devons les recompresser en données RGB. En termes simples, plus d'opérations pour chaque pixel pour obtenir la couleur finale!

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.

Je n'ai jamais travaillé sur pyGame auparavant, mais, un rapide coup d'œil sur le code de souce, m'amène à supposer qu'il utilise les fonctions Blit de 'sdl' sous le capot. Habituellement, le bld Sdl sera très rapide et optimisé, alors ne faites pas une fois de plus les points et le profil ci-dessus! Bonne chance!

* Mise à jour: * La définition de la clé de couleur revient à ajouter une vérification supplémentaire lors du collage de chaque pixel à la surface.

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

         }

Donc, ici si vous voyez, nous sommes limités à ne pas utiliser memcpy car nous devons vérifier la validité des couleurs de chaque pixel!

Ayyappa
la source
D'accord, car il s'avère qu'un appel set_colorkeys'est glissé dans la texture de la carte, lui donnant un canal alpha (cher). Un convertproblème corrigé, et maintenant j'utilise 150 FPS stables sur ce PC de merde. Merci!
orlp
hey éditera concernant la touche de couleur a même oublié d'ajouter quelques informations: D
Ayyappa
5

sprite.convert() ne fait pas ce que vous pensez qu'il fait.

sprite = sprite.convert() est ce dont vous avez besoin.

Kylotan
la source
Woops, j'ai quand même sprite = sprite.convert()dans le vrai code :)
orlp
AHA bien. :) Dans ce cas, je n'ai pas grand-chose à vous offrir, si ce n'est d'envisager d'utiliser pyglet au lieu de pygame, ou d'utiliser pyOpenGL directement si vous êtes à l'aise avec OpenGL.
Kylotan
@Kylotan: bon compagnon de pêche! je ne l'ai pas vérifié :)
Ayyappa
ou encore mieux:sprite = pygame.image.load("Maps/MapTesting.png").convert()
MestreLion