...  03 juillet 2025

Paré au décollage

La fuite mémoire d’Omeganaut sur Android 64 bits, dans le moteur ZGameEditor, a enfin été localisée et corrigée après presque un an de recherches et de tests. Une sombre histoire de trampoline...

Sur Android 64, Omeganaut plantait de façon complètement aléatoire. Et j'ai démonté le moteur pièce par pièce pour limiter les causes possibles et tenter de cerner le problème. Mais après des mois à essayer d'obtenir un crash dump qui soit un peu plus explicite que :

********** Crash dump: ********** Build fingerprint: 'google/cheetah/cheetah:15/BP1A.250305.019/13003188:user/release-keys' #00 0x0000000000000010

J'ai décidé de noter sur un carnet la situation de mon jeu à chaque plantage. La base pour tout bon rapport de bug :

  • Qu'est-ce qu'il se passe ?
  • Sur quoi j'ai appuyé ?

Ça a pris quelques semaines, à raison d'une ou deux parties de temps en temps...

De ces observations, j’ai constaté que le jeu plantait beaucoup lors des transitions entre niveaux. La seule différence pendant ces transitions étant l’apparition de centaines de lignes de vitesse, façon anime.

Anime Speed Lines
"Comme dans Dragon Ball" - un fan

Après les avoir supprimés et relancé de nouveaux tests, le jeu ne plantait plus durant ces passages, mais il continuait de crasher lors d'un tir ou d'une explosion. Intéressant !

Les lignes de vitesses, les lasers et les explosions partagent tous la même base : l'affichage d'un modèle 3D low poly semi-transparent. Dans mon projet, la transparence n’est pas gérée via les options Materials de ZGameEditor, mais directement avec du code OpenGL :

glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @UseMaterial(Material:BasicMaterial); @RenderMesh(Mesh:SpaceShip); glDisable(GL_BLEND);

J'ai donc créé un test générant 100 cubes colorés par image, chacun avec une durée de vie qui joue sur leur transparence.

Making cubes
"Et Dragon Ball ?" - un fan relou

100 cubes par image, c'est 6000 cubes par seconde, soit énormément plus de chance de déclencher un crash rapidement. Et comme c'était le cas, j'ai pu réduire le nombre d'instructions à une seule et toujours obtenir un crash : glEnable(GL_BLEND);

Alors ça ne veut pas dire que c'est cette instruction spécifique qui est fautive, mais ça confirme que les appels à la librairie OpenGL provoquent une fuite de mémoire.

Ville, le créateur de ZGameEditor, m'a proposé quelques tests supplémentaires pour vérifier le comportement d’OpenGL quand la commande est appliquée sur la scène entière, plutôt que sur chaque objet individuellement. Il a ainsi pu réécrire la gestion des trampolines. Les trampolines ?

ZGameEditor génère à l’exécution un petit bout de code appelé trampoline, qui permet d’appeler des fonctions externes en préparant leurs arguments correctement. Jusqu’ici, un trampoline était généré à chaque appel, même pour des clones de modèles. Des milliers de trampolines pour des milliers de cubes. Cela augmente le risque de bugs, particulièrement sur Android 64 bits, car la mémoire du cache n’est pas toujours correctement nettoyée, contrairement à la version 32 bits. Désormais, un seul trampoline est partagé pour chaque fonction, ce qui rend le système plus stable et efficace. Un seul trampoline pour des milliers de cubes.

Le moteur de mon jeu ronronne, et vous n'avez pas idée à quel point je suis soulagé.





Je remets à disposition la version de décembre dernier pour Android, compatible 32 et 64 bits. La version actuelle a le capot ouvert, prête à partir en production et à recevoir du contenu. Mais avant ça, je vais pouvoir terminer la prochaine version de Dragon Ball Devolution le cœur léger. Ne vous inquiétez pas.