1

Voilà, je veux créer une routine de sprite 32*32 pas clippée et optimisé au maximum en C. Cette routine me sert dans un moteur 2D pour les sprites qui ne sont pas clippés. J'utilises les routines du sdk quand le sprite sort de l'écran et cette routine lorsque le sprite rentre complètement dans l'écran pour gagner en rapidité.
Au début je n'utilisais que des unsigned char pour copier de pixel en pixel et j'ai décidé de passer au unsigned long pour aller 4 fois plus vite.

void Fast_Draw_Sprite_32(unsigned char *sprite, unsigned short x, unsigned short y)
{
	short i,j;
        unsigned long *sprite_long = sprite;
	unsigned long *dest =  ((unsigned long *)gpDraw[nflip].ptbuffer + ((x<<8)-(x<<4) + (239-y-31))/4 );

	i=32;
	while(i--)
	{
             *dest++ = *sprite_long++;
	     *dest++ = *sprite_long++;
	     *dest++ = *sprite_long++;
	     *dest++ = *sprite_long++;
	     *dest++ = *sprite_long++;
	     *dest++ = *sprite_long++;
	     *dest++ = *sprite_long++;
	     *dest++ = *sprite_long++;
																	    dest = dest + ((240-32)/4);
       }
						
}


Mais j'ai un petit problème : les sprites dessinés par cette routines bougent en y de 4 pixels en 4 pixels ce qui donne une impression de saccade lorsque la caméra se déplace verticalement... et puis les sprites sont décalé 3 fois sur 4 par rapport à ceux dessiné par la routine du sdk.

r_sprite.PNG

2

-

3

-

4

Orion_ :
heu question, les sprites que tu affiche en coordonée négative a gauche, s'affiche quand même avec les lib du sdk ?
ou alors tu fait en sorte de ne pas passer de coord négative ?

Ca devrait merder avec le sdk ? Je n'ai pas l'impression d'avoir ce probleme.

5

-

6

ok. je suis en 8bits sans transparence. J'ai pas teste comme toi.

7

et d'une les decalages pour optimiser ta multiplication (((x<<8)-(x<<4)) ne servent a rien avec un compilo arm laisse ça avec une multiplication, le compilo optimisera ça bien mieux que toi une fois en asm.

Je n'arrive pas à compiler, avec les compilateur arm (ads et arm sdt). Il faudra que je commence un projet à 0.
J'utilise toujours devkitadv + le patch gp32. Alors je ne sais pas si GCC le fait lui même ?
de plus tu a du oublier un petit truc des bases de la programmation. quand on copie un long il faut que sont adresse soit aligné sur 4 octets !

Oui j'avais déjà eu le même problème sur Ti pour une routine d'image. Il suffisant de décaler les octets, mais là je ne sais pas trop comment faire.
heu question, les sprites que tu affiche en coordonée négative a gauche, s'affiche quand même avec les lib du sdk ? ou alors tu fait en sorte de ne pas passer de coord négative ?

Avec les routines 8 bits, je n'ai pas de souci de ce côté là.

8

-

9

heu a ce que je sache, devkitadv est un compilo arm

Oui, mais bon c'est gcc qi est un compilo très général.
ils m'est déja arrivé d'optimiser des routines au max avec des decalages, et des pointeurs pour eviter tout calcul, et me rendre compte que une routine avec des multiplications de partout et absolument pas optimisé en C etait bien plus rapide que ma fonction optimisé, et ça, uniquement avec des compilo arm. (exemple: routine de recopie du buffer de yeti vers l'ecran gp32)

Ah bon ?! Il faudrait que je fasse des benchs alors ! Par contre pour les trucs précalculé avec des pointeurs je pense que c'est quand même tout le temps plus efficace... enfin d'après ce que j'ai pu tester jusqu'à maintenant.
(exemple: routine de recopie du buffer de yeti vers l'ecran gp32)

Ah tiens j'aimerais bien voir àq uoi ça ressemble. smile
Et pourquoi ils utilisent une routine de recopie de buffer ? C'est plus rapide que le double buffering du sdk ?

Et pour ma routine de sprites il faut que je fasse comment alors ? Il faut aussi que je fasse un décalage en fonction des pixels à remonter ?


Ps : ah oui et puis je doute que gcc déroule les boucle tout seul. Et puis au niveau des paramètres que ce soit -Os, -O2 ou -O3 ça ne chnage rien avec devkitadv ? Ce n'est pas comme avec TIGCC ?

10

-

11

-

12

Ok, merci bien Orion_ ! Je cherchais plus compliqué que ça. grin

13

Au fait Raph, si tu tiens vraiment a gagner en vitesse et que tu refais tes routines d'affichage, je te conseille gcc 3.4 qui semble etre une tuerie par rapport aux precedents.
Tu compiles avec quoi ? (gcc -v pour voir la version)

14

Au fait Raph, si tu tiens vraiment a gagner en vitesse et que tu refais tes routines d'affichage, je te conseille gcc 3.4 qui semble etre une tuerie par rapport aux precedents. Tu compiles avec quoi ? (gcc -v pour voir la version)

Ca doit être GCC 3.0.2 ou un truc du genre. Mais pour devkitadv c'est encore un truc spécial non ?
Si tu as un lien, je veux bien. grin J'ai déjà voulu mettre GCC 3.4 mais dans devkitadv gcc.exe fait 5 ko.

Sinon pour la routine je galère !

La seule routine avec laquelle j'obtiens un résultat correcte est celle-ci :

void Fast_Draw_Sprite_32(unsigned char *sprite, unsigned short x, unsigned short y)
{
short i,j;
short deca = ((x<<8)-(x<<4) + (239-y-31))-(((x<<8)-(x<<4) + (239-y-31))/4)*4;

unsigned long *sprite_long = sprite;

unsigned long *dest_long = gpDraw[nflip].ptbuffer + ((x<<8)-(x<<4) + (239-y-31));

i = 32;
while(i--)
{


j = 8;
while(j--)
{
*dest_long++ = ((*sprite_long++)<<deca*8);
}

dest_long = dest_long + (240)/4 - 8;

}

}

En fait ça consiste à remplir les longs de la mémoire vidéo en 2 étapes en décalant le sprite :
Là j'ai la première partie :
((*sprite_long++)<<deca*8)
Mais ensuire je ne sais pas comment faire pour remplir l'autre partie de chaque long. Il faudrait que je prennent le long suivant du sprite et que je le décale dans l'autre sens.
Mais pour l'instant je ne suis pas arrivée à grand chose.

15

Raphaël
:
Au fait Raph, si tu tiens vraiment a gagner en vitesse et que tu refais tes routines d'affichage, je te conseille gcc 3.4 qui semble etre une tuerie par rapport aux precedents. Tu compiles avec quoi ? (gcc -v pour voir la version)

Ca doit être GCC 3.0.2 ou un truc du genre. Mais pour devkitadv c'est encore un truc spécial non ?
Si tu as un lien, je veux bien. grin J'ai déjà voulu mettre GCC 3.4 mais dans devkitadv gcc.exe fait 5 ko.

Si t'en est au debut et que c'est pas trop galere de changer, je te conseille le kit de mrmirko. Ca marche et c'est du gcc 3.4
http://www.mirkoroller.de/
Par contre je suis pas sur que les routines d'affichages qu'il a ecrites soient terribles. Mais c'est pas grave puisque tu fais les tiennes. En plus il donne les sources, tu pourras regarder.

Et comme le dit Orion_, c'est pas dit que tes shift a droite et a gauche soient plus rapides. N'ai pas peur de faire confiance au compilateur de temps en temps, il est pas si pourri que ca. Et puis c'est plus lisible.

Demain je vais te coder vite fait un petit programme pour tester l'affichage de sprites. Au moins comme ca on pourra vraiment comparer les fonctions de chacun.

EDIT: et quitte a faire du code pas hyper lisible comme ca, fais le au moins en assembleur. tongue

16

Si t'en est au debut et que c'est pas trop galere de changer, je te conseille le kit de mrmirko.

Je l'ai déjà mais je n'arrive pas à compiler avec : j'utilise GP32IDE et j'ai déjà essayé de copier gcc mais après ça ne compile plus sad
N'ai pas peur de faire confiance au compilateur de temps en temps, il est pas si pourri que ca.

Si tu le dis ! smile

Demain je vais te coder vite fait un petit programme pour tester l'affichage de sprites. Au moins comme ca on pourra vraiment comparer les fonctions de chacun.

Un programme pour bencher ?
Il faudrait que je m'en fasse un aussi mais par contre ma routine ne marche toujours pas.
et quitte a faire du code pas hyper lisible comme ca, fais le au moins en assembleur.

Non, non, sans façon ! grin

17

on peut faire un bench rapide comme ca :

char buffer[0x2A] ;
ulong start, stop ;

while(1)
{
	flipScreen() ; clrScr() ;
	start = GpTickCountGet() ;
	// blit 1000 sprites
	stop  = GpTickCountGet() ;
	
	sprintf(buffer,"time %i",stop-start) ;
	GpTextOut(NULL, &gpDraw[nflip],10,10,buffer,0xB3);
};

18

r043v :
on peut faire un bench rapide comme ca :

char buffer[0x2A] ;
ulong start, stop ;

while(1)
{
	flipScreen() ; clrScr() ;
	start = GpTickCountGet() ;
	// blit 1000 sprites
	stop  = GpTickCountGet() ;
	
	sprintf(buffer,"time %i",stop-start) ;
	GpTextOut(NULL, &gpDraw[nflip],10,10,buffer,0xB3);
};

Ca a finalement ete fait a cote
topics/44897-mon-affichage-de-sprite-a-moi-asm (post ./15)

19

j'avais pas vu :/

je v essayer ma fonction ac ton image.

20

Bon je ne suis toujours pas arriver à faire ma routine de sprite 32*32 non clipée mais je crois que je vais laisser tomber.
N'ai pas peur de faire confiance au compilateur de temps en temps, il est pas si pourri que ca. Et puis c'est plus lisible.

Alors j'ai fairt des tests et ce n'est pas plus rapide avec des multiplication et des divsion qu'avec des shift. Ce qui est certain c'est que le code est plus gros déjà.

Sinon, c'est pas souvent qu'il faut faire confiance au compilateur... sur TI par exemple j'ai voulu faire une routine pour effacer l'écran et je me suis rendu compte que ça allait plus vite avec des 1 qu'avec des 0. Alors il a fallu que je bidouille un peu ma fonction (je déclarais une variable en tant que registre et je lui attribuait la valeur 0).
Parce-que l'instruction utilisé effacait les variable (clr) mais est terriblement plus lent que de déplacer une valeur.

Alors on aurait pu croire que c'était optimisé le "*dest++=0", mais en fait absolument pas et c'était même tout le contraire.
Comme quoi je pense qu'il ne faut jamais avoir confiance au compilateur (ou alors pas souvent).

Et sinon il y a moyen avec GCC de produire un fichier où l'ont peut voir le programme traduit en asm comme avec TIGCC ?

21

-

22

Ah ouoi c'est vrai, merci !
le compilo gcc fait du très très bon boulot de ce coté la, bien mieux que sur n'importe kel autre processeur.

Ah bon. Ca vient du proc ou du boulot fait sur gcc arm ?

23

-

24

Et alors là tu penses que c'est laquelle la plus optimisée ? grin
PutPixel_1:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
ldr r3, .L8
ldr ip, .L8+4
ldr r3, [r3, #0]
mov r1, r1, asl #16
rsb r3, r3, r3, asl #3
ldr r3, [ip, r3, asl #2]
mov r1, r1, asr #16
rsb r1, r1, r1, asl #4
add r3, r3, r1, asl #4
mov r2, r2, asl #16
sub r3, r3, r2, asr #16
@ lr needed for prologue
strb r0, [r3, #239]
mov pc, lr

PutPixel_2:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
ldr r3, .L11
ldr ip, .L11+4
ldr r3, [r3, #0]
mov r1, r1, asl #16
rsb r3, r3, r3, asl #3
ldr r3, [ip, r3, asl #2]
mov r1, r1, asr #16
add r3, r3, r1, asl #8
sub r3, r3, r1, asl #4
mov r2, r2, asl #16
sub r3, r3, r2, asr #16
@ lr needed for prologue
strb r0, [r3, #239]
mov pc, lr

25

-

26

Raphaël :
Alors on aurait pu croire que c'était optimisé le "*dest++=0", mais en fait absolument pas et c'était même tout le contraire.
Comme quoi je pense qu'il ne faut jamais avoir confiance au compilateur (ou alors pas souvent).

Le compilateur sait tres bien optimise le code ecrit de maniere lisible. Les gars qui ont bosse dessus se sont plus penches sur comment optimise "for (int i=0;i<320*240;i++) dest[i]=0;" que sur les "*dest++=0;"
Et comme orion_ le fait remarquer une gepette, c'est pas comme une TI.

27

Le compilateur sait tres bien optimise le code ecrit de maniere lisible. Les gars qui ont bosse dessus se sont plus penches sur comment optimise "for (int i=0;i<320*240;i++) dest=0;" que sur les "*dest++=0;"

Ouais je m'en doute bien mais j'ai perdu l'habitude de programmer comme ça. Quand je vois du code comme ça je me dis que ce n'est pas optimisé du tout.