dimanche 15 septembre 2013

Encore un tipeu plus vite

Une autre optimisation que je veux ajouter à mon engin graphique pour le jeu de monstre est en fait un vieil ami que j'ai côtoyé il y a plus de 20 ans lorsque je développais sur Mac, et je parle de mon vieux Mac Classic ! Les jeux de l'époque n'arrivait pas à faire plusieurs niveau de parallax puisque le fillrate était bien trop lourd, même en noir et blanc ( 1 bit par pixel ). Comme la plupart des backgrounds était fixes, le blit final pouvait être optimisé pour ne transférer que les parties qui ont été modifiées. Le truc était de séparer l'écran en tuiles, souvent 16 de large par 8 de haut, et masquer les bits correspondant à la tuile lorsque le sprite risque de la modifier. Ensuite suffit de blitter que les tuiles correspondant aux bit assigné C'est rapide et efficace, tant que le nombre de sprites n'est pas trop élevé.

Ici. comme le fillrate est un problème et la composition utilise justement plusieurs blits entre plusieurs images, chacune ayant plusieurs trou puisque ce n'est pas le background, ramener ce petit truc, surtout avec un nombre de sprites qui se veux limité, risque d'avoir un impact. Je ne sais pas à quel point bitshifter et masquer des unsigned short est optimisé en Java sous Dalvik, mais comme c'est le CPU qui va travailler pour aider un peu le GPU par la suite, ce devrait être tout de même gagnant.

À suivre!

C'est sensible ces petites bêtes là!

Outre l'écran tactile, la position de l'appareil est quelque d'intuitif pour tout le monde. Il n'y a qu'a regarder quelqu'un qui n'est pas habitué à un contrôleur de jeu essayer de faire sauter un personnage en levant la manette. C'est justement ce genre de mouvement que l'accéléromètre permet d'interfacer. Ceci-dit, ce n'est si simple. Il y a plusieurs senseurs de disponible sur un appareil et ils ont tous leur particularité.

Pour justement m'amuser avec les senseurs, j'ai commencer une autre application qui va me permettre de lister les senseurs et valider leur utilisation. De plus, je vais lister le plus possible d'info disponible pour l'appareil ( processeurs, mémoire, support d'OpenGL, etc. ). Oui, il y a plusieurs application de disponible sur le PlayStore qui le font mais c'est pour me développer une boîte à outils et non faire un application qui va révolutionner le monde que je fais tout ça. Donc, ma première application sur le PlayStore sera... J'ai pas encore trouver le nom et j'ai pas trop regarder ce qui est nécessaire pour déployer une application, même gratuite, sur le PlayStore.

C'est à suivre.

lundi 9 septembre 2013

Moins beau mais beaucoup plus rapide

Le dernier gros morceau que j'ai optimisé est la résolution de la couche d'objet du centre. Étonnamment, l'optimisation à eu plus d'impact que je ne le pensais. J'ai aussi désactivé le lissage des couches d'ombres et de celle de la couche du milieu lors de la composition. Ici aussi le gain à été plus important que je ne l'aurais pensé. Puis tant qu'à faire, je configuré un scale pour la création des sprites d'ombre, ce qui devrait aider un peu lors du rendering des couches d'ombres. Ici le gains est marginal mais sûrement appréciable en terme d'utilisation de la mémoire.

C'est moins jolie mais une fois animé c'est beaucoup moins apparent.

Donc, après ces derniers essais d'optimisation qui ont ma fois plus que valus la peine, j'arrive à quelque chose de potable sur la Nexus 7 et totalement fluide sur mon Nexus S. Sur le téléphone, je peux augmenter la qualité sans problème, sur la Nexus 7, c'est borderline. Cependant, comme tout est configurable au runtime, je pourrai ajouter une méthode assez simple pour déterminé la qualité par défaut et permettre à l'usager de modifier les paramètres. Très probable qu'avec le temps je découvrirai quelque truc pour encore optimiser le rendering donc je considère que les deux couches d'ombres sont fonctionnelles et font partie du jeu. Je peux donc commencer à implémenter le jeu et faire plaisir à monstre no. 1 !!!

Donc, voici les paramètres modifiable pour le rendering:

  • Résolution de la couche d'ombre supérieure
  • Résolution de la couche d'ombre inférieure
  • Résolution de la couche d'image du centre
  • Lissage des couches d'ombres lors de la composition
  • Lissage de la couche d'image centrale lors de la composition
  • Résolution des sprites d'ombre
Les paramètres utilisés pour générer l'image ci-haut sont des résolution de 320x200 pour les couches d'ombre (25% taille originale), 640x400 (50% taille originale) pour la couche d'image centrale ( les nuages ), sprite d'ombre réduit de 50% et aucun lissage lors de la composition. C'est pas mal le plus cheap comme options.

Toujours trop lent les ombres

J'ai tout de même essayé mais je ne pense pas que ce soit possible d'avoir deux couches d'ombre et de garder des animations fluides sur un Nexus 7, pas de la manière de je l'implémente en tout cas. J'ai retiré une couche de dessin temporaire et réduit du quart la taille des buffers d'ombre mais c'est toujours trop lent.

Même avec du filtering, des buffers temporaire à 1/4 de la résolution, ça parait

Il me reste tout de même quelques optimisations à faire et peut-être j'arriverai à quelque chose d'un peu plus potable mais pour le moment j'ai des doutes. Avec une seule couche d'ombre, c'est parfait mais le fillrate nécessaire pour la couche d'ombrage par dessus la couche du centre demande trop. Est-ce que c'est le setXferMode qui n'est pas optimisé sur le GPU qui ralentie tant que ça? Enfin, je vais laisser de côté le rendering des ombres pour stabiliser l'application et implémenter d'autre truc un peu plus utile. Monstre no. 1 s'impatiente de pouvoir jouer et comme les ombres ne l'intéresse pas trop...

dimanche 8 septembre 2013

Un peu lent

Bon, j'ai un semblant d'engin graphique pour le jeu de monstre. Cependant, c'est un peu lent. En fait, trop lent pour être vraiment jouable. Sur mon téléphone c'est bien correct ( Nexus S ) mais sur un Nexus 7 2012, c'est trop demander. La résolution fait toute la différence. Comme il y a 4 buffers d'images temporaires en plus du rendering final, ça demande trop en fillrate. Il y a moyen de booster le tout en réduisant la taille des buffers d'ombre mais je ne sais pas si ce sera assez pour faire une véritable différence. Ensuite il faudrait limiter l'espace où les objets font de l'ombre ( genre seulement la partie basse de l'écran ) pour la couche la plus rapprochée. Il est aussi possible de tout simplement réduire à seulement deux couches d'objets et un seule couche d'ombre. Comme mon but c'est de développer le tout rapidement, je ne veux pas être obligé de tout recoder en OpenGL ES 2 et faire quelque passe passe en shader.



Enfin, le look dessiné à la main est bien et le calcul des ombres est dynamique. La lumière dans le screenshot est situé en plein centre de l'écran. Les feuilles sont sur la couche supérieure, les nuages au milieu et le soleil dans le fond. Évidemment, c'est beaucoup plus beau lorsque c'est animé.

mardi 3 septembre 2013

Un premier monstre

C'est pas grand chose mais ça me permet d'apprendre Android et ses particularités tout en m'amusant avec monstre no. 1. Il a fait quelques dessins que j'ai scannés et j'ai commencé une structure de rendering en utilisant les appels graphique standard. J'avoue que c'est assez simple et supposément que depuis Android 3.0, tous les appels graphiques sont exécutés sur le GPU. Je n'ai pas fait de benchmark mais sur mon Nexus S, c'est smooth. Reste à voir sur le Nexus 7 2012 comment ça va réagir et surtout combien de sprites je pourrai utiliser.


Vous pouvez admirer mes talents de dessinateur avec le fond de l'image et les pommes! Les pieds, le tronc et la tête proviennent des images que j'ai scannées. Pour le moment, un swipe gauche ou droit permet de changer la tête du monstre. Autrement dit, j'ai du code de test pour le rendering de bitmap avec effet d'ombre et du code de test pour analyser la gestuelle. Ça amuse déjà monstre no. 1 et ça lui donne le goût de continuer à développer le jeu. Nous avons enregistré des sons de monstre avec mon téléphone et la prochaine étape est de faire jouer un son au hasard lorsqu'on tape sur la tête.

Comme la classe SoundPool s'occupe de gérer les effets sonores, ce ne sera pas grand chose à implémenter. Je vais surtout me concentrer à définir les sprites et l'engin de composition. Comme je veux gérer deux couches d'ombrage, il va y avoir des bitmaps offscreen pour le rendering des couches d'ombres et des couches d'images temporaires. Je me demande surtout s'il est plus utile de générer des bitmaps d'ombre pour chaque sprite ou reprendre le bitmap original et utilisant un shader pour ne dessiner que l'alpha. Il est terriblement simple de générer un bitmap d'ombre à partir d'une image. La méthode extractAlpha s"occupe de tout. J'imagine qu'elle retourne un bitmap en format ALPHA_8 ce qui sauve pas mal en mémoire. De plus, les bitmap temporaire pour le rendering d'ombre sont en format ALPHA_8. Je ne connais pas de tablette Android avec de la mémoire vidéo GDDR5, donc limiter l'accès mémoire devrait être un gain même si le processing GPU est le même. Enfin, on verra plus tard.