Posté le 20/02/2022 16:00
Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 220 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements
Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd
Citer : Posté le 20/02/2022 21:52 | #
Addition du tout premier morceau de traffic ce soir :
Ciao
Sly
Citer : Posté le 20/02/2022 21:55 | #
P'tit problème avec la vidéo si je ne m'abuse, j'ai quote je crois que c'est à cause d'une balise vidéo mal fermée.
Sinon c'est franchement cool, bravo !
Les changements de vitesse et arrêts sont contrôlés, ce ne sont pas des bugs (?)
Citer : Posté le 20/02/2022 22:01 | #
Oui je viens de corriger, il manquait un crochet à la balise de vidéo
oui c'est contrôlé en effet, je fais des aller-retours marche avant/arrière pour voir si tout est OK, et je fais divers freinages/ré-accélérations.
Par contre je me suis rendu compte qu'à une certaine vitesse, le refresh de l'écran tombe pile synchrone avec l'update de position et on a un superbe effet stroboscopique qui fait qu'on dirait qu'on avance plus/pas. j'ai donc mis une valeur de vitesse maxie différente pour ne pas avoir l'impression d'une image figée
Citer : Posté le 20/02/2022 22:03 | #
Ah oui ok.
En tout cas franchement bravo, c'est super fluide !
Citer : Posté le 20/02/2022 22:07 | #
Merci
Faudra certainement à un moment que je demande qq conseils à Lephé pour transposer mes routines de calculs en virgule flottante vers du fixed point et aussi pour optimiser le tracé. Il va certainement falloir ruser un peu pour accélérer tout ça quand il y aura tout (décors, traffic, HUD ...).
Plus il y a de FPS dans ce genre de jeux, mieux on se porte. Mais globalement pour le moment je suis assez content du résultat, vu le peu de temps que j'ai passé dessus ...
Ajouté le 21/02/2022 à 10:17 :
Up !!
traffic en cours d'implémentation...
Bon, le soucis c'est que j'ai programmé des chauffards qui tournent pas dans les virages
Faut que je débug car j'ai un framerate hyper pas constant : ça oscille entre un loop time de ~35ms à ~80/90ms avec parfois des coups à ~170/180ms sans que je comprenne ce qui se passe.
Bizarre ...
@+
Sly
Ajouté le 21/02/2022 à 16:31 :
qq arbres, bon c'est un peu vilain, il faudra bien trouver le bon étagement des tailles de sprites car là ca tremblotte et ça "pop"
et toujours ce framerate inconsistant ... Ça commence à m'interroger fortement.
Citer : Posté le 21/02/2022 16:35 | #
Pour ce qui est du framerate, déjà vérifie que ton dupdate() est synchrone, sinon tu as jusqu'à 11 ms de jeu asynchrone :
dupdate();
// Par :
#include <gint/drivers/r61524.h>
r61524_display(gint_vram, 0, DHEIGHT, R61524_DMA_WAIT);
// Note : ça contourne le hook dupdate et l'interversion des VRAMs
Et sinon mesure les parties individuelles de ta boucle, tu y verras plus clair.
Citer : Posté le 21/02/2022 16:54 | #
Merci Lephe, je vais prendre déjà ça et regarder si ça aide.
Oui faut que je me mette une série de mesures car il se passe des trucs étranges.
J'ai l'impression notamment (mais à confirmer car j'ai pas eu le temps d'analyser en détail) que lorsque j'ai des sprites trop près des bord de l'écran, le loop_time explose.
Ok leur taille augmentent, mais pas dans cette proportion car je passe globalement à X2 en surface à afficher tandis que le temps de rendu se prend ~X10.
Bref, faut que j'analyse mieux le schmilblick.
Ajouté le 26/02/2022 à 08:39 :
De retour gentiment sur OutRun, je cherche la bonne taille des sprites :
Il faut trouver le bon compromis visibilité (aspect) / performance ...
et c'est pas de la tarte ...
Citer : Posté le 26/02/2022 10:30 | #
Normalement tu devrais pas être limité par ça... je veux dire ça compte, mais là 163 ms c'est beaucoup trop. À vue de nez, en supposant que les algos pour le sol sont bien par ligne et calculent "rapidement" la position, on s'attend plutôt à 35-40 ms pour ça
Si tu peux identifier quels appels exactement prennent le plus de temps, ça serait utile.
Citer : Posté le 26/02/2022 10:56 | #
A vue de nez le plus gros sprite me paraît être le plus adapté mais je n’ai aucune idée des perfs.
Citer : Posté le 26/02/2022 10:57 | #
vous inquiétez pas, c'est sur l'émulateur, le temps de rendu n'est pas à prendre en compte ;-)
sinon effectivement je suis plutôt vers 40ms sur la machine réelle
Ajouté le 26/02/2022 à 11:51 :
A vue de nez le plus gros sprite me paraît être le plus adapté mais je n’ai aucune idée des perfs.
oui je suis assez d'accord, le gros me semble être le meilleur compromis par rapport à la taille de l'écran. Je vais partir là dessus, quitte à modifier un peu la taille de la route pour que la voiture soit correctement proportionnée par rapport aux bandes blanches et à la largeur des voies ...
Ajouté le 26/02/2022 à 21:47 :
Et un gros merci à Lephe pour sa routine de scaling de sprites :
Ca marche tip-top, et ça permet de tout faire tenir dans un Addin vraiment petit
Citer : Posté le 27/02/2022 01:40 | #
Tes voitures sont très jolies, bonne chance
Citer : Posté le 27/02/2022 08:02 | #
Merci Massena.
Les sprites viennent de là : https://www.spriters-resource.com/
On y trouve pas mal de choses sympa.
N'étant pas graphiste pour deux sous, je dois ma rabattre sur les ressources libres
Citer : Posté le 03/03/2022 14:22 | # | Fichier joint
Crash :
L'archive de build complète est en PJ, avec le fichier map
Citer : Posté le 03/03/2022 18:27 | #
Regardons ça ensemble. La solution était triviale, mais je te fais le speech complet, ça peut aider. Dans le fichier map, 0x300458 c'est dans main :
0x0000000000300260 _main
.text.exit 0x0000000000300618 0x10 CMakeFiles/myaddin.dir/src/main.cc.obj
Et 0x301cec, qui n'est pas l'adresse du problème mais on sait jamais, c'est le début de __floatsisf() :
0x0000000000301cec ___floatsisf
Dans le manuel des fonctions internes de GCC, il est indiqué que float __floatsisf(int i) convertit l'entier i en flottant.
gint a affiché les contenus de la mémoire au voisinage de PC : on a 0x6403 0x1905 0x0300 0x0085, sachant que le PC qui a planté c'est le 0x0300. Désassemblons à l'adresse indiquée pour voir si c'est les données d'origine ou si elles ont été modifiées :
... recherche de 300458 ...
300454: 64 03 mov r0,r4
300456: 19 05 mov.l r0,@(20,r9)
300458: 03 00 .word 0x0300
30045a: 00 85 mov.w r8,@(r0,r0)
Les données sont bien comme annoncées, donc ce n'est pas un problème de modification du code ; c'est juste que le code n'aurait jamais dû sauter là en premier lieu.
En cherchant on remarque qu'il y a une autre occurrence de 300458 dans le code, qui est en fait un moment où la valeur à cette adresse (0x0300) est chargée en mémoire :
3002e8: 98 b6 mov.w 300458 <_main+0x1f8>,r8 ! 300
3002ea: 49 0b jsr @r9
3002ec: 00 09 nop
On est toujours en plein milieu de main(), et on voit que la valeur est chargée dans r8, juste avant d'appeler la fonction indiquée dans r9, qui par chance a été chargée juste avant et est... pollevent(). Ça, ça peut pas être un hasard.
On va voir dans les sources ; pollevent() est appelée en fait dans une sous-fonction get_inputs(), mais comme ladite sous-fonction est static et appelée une seule fois elle est inlinée dans le main(). On peut voir aussi qu'elle prend en paramètre un float qui est initialisé par la valeur d'un int. Nul doute que c'est de là que vient l'adresse de __floatsisf().
Retournons voir le code assembleur ; la valeur en question, le 0x0300, est en fait utilisé pour tester le .type de l'événement (c'est comme ça que c'est structuré le champ de bits). On commence à voir où on va.
Il est temps de recompiler et de tester. Ça crashe toujours, ce qui est bien ; le bug est toujours reproductible. Je note qu'il y a un warning sur get_inputs() parce que t'as pas mis la valeur de retour. Bon le premier truc que je veux faire c'est virer le static pour garder get_inputs() sous sa forme de fonction et voir ce qui se passe dans le code assembleur. Cette fois ça crashe avec comme TEA l'adresse de ustl::cmemlink::link(void const*, unsigned int). Conclusion, ni cette fonction ni __floatsisf() ne sont probablement responsables, elles ont juste été appelées "récemment" et leur adresse est donc restée dans TEA. Après tout, le CPU dit que dans TEA il y a l'adresse problématique quand une erreur d'accès mémoire se produit, mais il ne dit pas ce qu'il y a dans les autres situations.
Le problème n'est pas évident à première vue, donc je commence à bisect le code à coup de commentaires/return. Avec un peu d'efforts je minimise à un truc comme ça. Et là le bug est visible dans le moindre doute dans le code assembleur.
{
}
int main(void)
{
__printf_enable_fp();
__printf_enable_fixed();
prof_t perf_create, perf_project, perf_render;
uint32_t time_create=0, time_project=0, time_render=0;
uint8_t nbInterestingSegments = (MAX_RENDER_DISTANCE / SEGMENT_LENGTH) + 10;
initData( );
get_inputs(0);
return 1;
}
Ça crashe en 0x300274 :
300260: 4f 22 sts.l pr,@-r15
300262: d1 04 mov.l 300274 <_main+0x14>,r1 ! 30bea8 <___printf_enable_fp>
300264: 41 0b jsr @r1
300266: 00 09 nop
300268: d1 03 mov.l 300278 <_main+0x18>,r1 ! 30b858 <___printf_enable_fixed>
30026a: 41 0b jsr @r1
30026c: 00 09 nop
30026e: d1 03 mov.l 30027c <_main+0x1c>,r1 ! 3006d8 <__Z8initDatav>
300270: 41 0b jsr @r1
300272: 00 09 nop
300274: 00 30
300276: be a8
300278: 00 30
30027a: b8 58
30027c: 00 30
30027e: 06 d8
Et omg la fonction fait trois sous-appels avec jsr et ensuite fonce droit dans le mur, y'a plus de code, juste des données là où l'appel à get_inputs() devrait se trouver. Pas de fin de fonction, pas de return, juste les adresses constantes des trois fonctions qui ont appelées plus haut (dont j'ai caché le disassembly pour clarifier).
Le compilateur ne génère pas du code comme ça normalement, donc voyons si c'est un problème de link. Le fichier .o du main nous dit :
...
00000000 <_main>:
0: 4f 22 sts.l pr,@-r15
2: d1 04 mov.l 14 <_main+0x14>,r1 ! 0 <_main>
4: 41 0b jsr @r1
6: 00 09 nop
8: d1 03 mov.l 18 <_main+0x18>,r1 ! 0 <_main>
a: 41 0b jsr @r1
c: 00 09 nop
e: d1 03 mov.l 1c <_main+0x1c>,r1 ! 0 <_main>
10: 41 0b jsr @r1
12: 00 09 nop
...
Et bah si la fonction est compilée n'importe comment. Note que c'était le cas depuis le début mais quand la fonction est compliquée avec des boucles/sauts/etc c'est difficile de savoir où il saute et comment, donc on peut rarement voir ce problème clairement (et puis ça arrive jamais).
Il n'y a vraiment que deux scénarios dans lesquels ça peut se produire : (1) le compilateur est buggé, (2) il y a un comportement indéfini qui se fait optimiser la face tellement violemment qu'il ne reste plus rien à la fin.
Quel comportement indéfini peut-il y avoir avec une fonction comme ça ? Et bien il se trouve que le compilateur n'arrête pas de nous harceler pour qu'on corrige un subtil détail :
/tmp/CppOutRun/src/main.cc:104:1: warning: no return statement in function returning non-void [-Wreturn-type]
104 | }
| ^
Mettons la valeur de retour, à quoi ressemble main() maintenant ?
300264: 4f 22 sts.l pr,@-r15
300266: d1 06 mov.l 300280 <_main+0x1c>,r1 ! 30beb8 <___printf_enable_fp>
300268: 41 0b jsr @r1
30026a: 00 09 nop
30026c: d1 05 mov.l 300284 <_main+0x20>,r1 ! 30b868 <___printf_enable_fixed>
30026e: 41 0b jsr @r1
300270: 00 09 nop
300272: d1 05 mov.l 300288 <_main+0x24>,r1 ! 3006e4 <__Z8initDatav>
300274: 41 0b jsr @r1
300276: 00 09 nop
300278: e0 01 mov #1,r0
30027a: 4f 26 lds.l @r15+,pr
30027c: 00 0b rts
30027e: 00 09 nop
300280: 00 30
300282: be b8
300284: 00 30
300286: b8 68
300288: 00 30
30028a: 06 e4
Oh... ça marche maintenant.
Je reviens sur ta version initiale, je mets la valeur de retour, boum ça marche.
Morale : LISEZ VOS WARNINGS. x)
J'ai pas commencé par là non plus, parce que j'ai vu le warning et je savais pertinemment qu'en C ça poserait pas de problème. Donc je l'ai ignoré. Erreur, parce que le compilateur C++ est plus fourbe encore.
Citer : Posté le 03/03/2022 22:38 | # | Fichier joint
Hello,
voici une première version en PJ, loin d’être finale, après réécriture pour fonctionner avec la µSTL (ça va servir pour la génération des circuits) et optimisée pour les calculs de projections en arithmétique point fixe.
Les touches :
[SHIFT] pour accélérer
[ALPHA] pour freiner/reculer
[EXIT] pour quitter
[<- / ->] aller à gauche / droite
Çà tourne à grosso modo 25ips, faut que j'optimise le rendu (c'était prévu, mais avec le bug de la journée, c'est pas fait )
D'ailleurs merci Lephé pour m'avoir sorti de l'ornière !! La démarche explicitée dans le post précédent est très instructive (bon je serais bien incapable d'en faire autant)
Pour info, il y a encore un bug quand on arrive vers les segments 4300+, la route s’arrête. Je pense que je dépasse la capacité max de quelque chose. Reste à identifier le quelque chose. Mais au moins ça plante pas et ça crash pas.
Amusez vous bien.
Sly
PS pour Lephe: du coup mon get_input() est passé en void
Ajouté le 05/03/2022 à 12:25 :
Bon j'ai encore mon problème avec mon ustl::vector dont les valeurs après l'indice 4311 deviennent toutes égales à 0.
J'ai d'abord cru à un problème de capacité maxie des éléments du tableau, j'ai donc ajusté tout en interne pour etre sur de ne pas avoir de valeurs au delà de la capacité du type utilisé).
on voit par exemple sur la capture suivante que j'ai mis dans les coordonnées (ligne > (Wxyz)=( , , , ) ) en coordonnées X l'indice de l'élément en question. Donc quand tout va bien on a ça :
La taille de l'élément est bien de 72 bytes, l'adresse de l'éléments en cours (#2680) est x08c1b5454 (ligne CAdr=... )
si on s'approche de cette "frontiere" à 4311, on voit ce qui se passe. Dernier point valide :
et si on dépasse la frontière : boom, tout passe à zéro (cf ligne Iend: 4312). A noter que l'adresse CAdr est celle de Istr, soit le 4294eme élément:
En se mettant à Istr = 4311 (éléments 4311 est encore bien rempli des bonnes valeurs)
et si Istr = 4312 (donc là on est complètement dans les choux) tout est à zéro:
mais l'adresse de l'élément du vecteur est encore OK : 0x8c1b6dd4
Considérant que le contenu du vector est un objet de type Segment ont la taille fait 72 bytes.
4311 éléments de ce type "pèsent" donc ~300Ko (310392 bytes pour etre précis).
Donc mon vector de Segment* me semble bon, par contre j'ai l'impression que à partir de 4312élément, faire un new Segment() et le mettre dans le vecteur ne fonctionne pas.
La limite a 300Ko d'allocation correspond t elle à qqchose ?
Je bug sur ce truc
Sly
Citer : Posté le 05/03/2022 12:29 | #
Tu as 500 ko environ pour les données statiques et le tas. En tenant compte du fait que ton vecteur doit être continu et qu'il y a d'autres allocations, ouais, c'est très probable que tu arrives àc ourt de mémoire. Ce qui m'étonne c'est que le C[i]adr, qui je suppose est l'adresse d'un des éléments du tableau (pas du vecteur lui-même !) n'est pas au voisinage de NULL. Tu peux toujours essayer d'afficher &ton_vecteur[0].
Mais à mon humble avis, le problème fondamentalement c'est que tu aies besoin de 4000 instances d'un objet de 72 octets. Si c'est un segment de route court, pourquoi 72 octets ? Et si c'est pas un segment court, pourquoi t'en veux 4000 ?
Citer : Posté le 05/03/2022 13:02 | #
Oui effectivement l'adresse que j'affiche, je me rends compte, n'est pas celle du contenu, mais du contenant. Faut que je regarde ça mieux pour récupérer l'adresse du Segment* contenu dans le vecteur et non pas l'adresse du pointeur vers cet élément. L'erreur de débutant
En fait ma route est construite de plein de micro-segments de taille fixe, ce qui permet d’accélérer la recherche de l'indice du début des segments à afficher sans avoir à parcourir les éléments du std::vector.
Par exemple si la taille des segments fait 200 et que la voiture est en position 4000, ça veut dire que je suis dans le segment 20 et que je doit traiter les infos des segments 20 à 35 par exemple si la portée de la vue est de 15 segments.
Je vais essayer de rendre la structure plus légère pour voir si cette limite à 4311 disparaît ou bouge en fonction de la taille. Ça pourrait m'orienter sur la source du problème, car à ce stade je sais pas si ça vient de l'allocation du contenu ou d'autre chose. On va essayer d’être méthodique.
Citer : Posté le 05/03/2022 13:07 | #
Et pourquoi un micro-segment fait 72 octets ? C'est énorme.
uint8_t Curve=0;
fixed_t wX=0, wY=0, wZ=0;
fixed_t sX=0, sY=0, sW=0;
fixed_t Scale=0;
int X=0,Y=0,W=0;
Tu es sûr que t'as besoin d'un Scale avec 64 bits de précision ? Pareil pour les autres en fait. Même si tu fais tes calculs intermédiaires en 64 bits t'as certainement pas besoin de stocker les valeurs initiales avec autant de précision.
Citer : Posté le 05/03/2022 13:14 | #
oui, c'est justement ce que je vais faire sauter pour revenir à un fixed_t sur 32bits.
Je vais aussi virer wX et wY que ne me servent pas pour le moment (pas de virages et pas de bosses sur ma route).
Je vais ainsi gagner pas mal sur la taille de l'objet et voir si du coup ca change.
Mais avant je regarde du cote de ma creation de segment. Je vais pas faire le push_back() sur le vector si new echoue est retrourne un pointeur nul. Ainsi en traçant la taille du vector, je vais voir ce que ça dit.
void createCircuit( void )
{
for( int i=0; i<MAX_SEGMENT; i++)
{
Segment *s=new Segment( i );
if (s!=nullptr) circuit.push_back( s );
}
};
Next coming soon ...
Citer : Posté le 05/03/2022 13:18 | #
Ouuuf mais oui tu as un tableau de pointeurs. Donc non seulement tu as encore 4 octets par élement (pour le pointeur dans le vecteur) mais en plus tu as d'autres allocations donc tu augmentes la fragmentation du tas. Ne cherche pas, ton tas est juste plein. C'est pas s qui échoue l'allocation mais bien le vecteur.