La Place des Développeurs MSXgl MSX Game Library
Reprise du message précédent
Il est modeste, le "flip" des bits dans un octet est déjà en assembleur7 6 5 4 3 2 1 0 les bits sont dans "l'ordre"
0 1 2 3 4 5 6 7 les bits sont "flippés" Edité par z80 Le 05/11/2023 à 13h17
TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours)
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,...
ericb59
Membre non connecté
Conseiller Municipal
Flip et Rotate sont des functions que j'avais aussi intégré dans Fusion-C 2.0.
J'ai fait en sorte qu'elles puissent s'appliquer à n'importe quel pattern 8x8 en RAM ou en VRAM.
J'ai pas regardé ton code, mais je suis certain qu'il est plus rapide que le mien, sans aucun doutes
J'ai fait en sorte qu'elles puissent s'appliquer à n'importe quel pattern 8x8 en RAM ou en VRAM.
J'ai pas regardé ton code, mais je suis certain qu'il est plus rapide que le mien, sans aucun doutes
aoineko :
Effectivement. C'est une ancienne fonction que j'avais zappé.
C'est sur que la même chose en C serait très lent.
C'est sur que la même chose en C serait très lent.
Serais-tu intéressé par une version commentée de cette partie en assembleur?
Une explication détaillée de ce qu'il se passe aux niveaux des bits, ligne par ligne.
Et puis honnêtement ça serait un bon exercice pour moi de participer à un projet GIT
TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours)
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,...
ericb59
Membre non connecté
Conseiller Municipal
Je serais curieux d'avoir les explication et le code d'un pro du Z80 comme notre ami Z80
Juste pour comparaison voici les routines que j'ai utilisé dans fusion-c 2.0
Pattern Horizontal Flip
Pattern Vertical Flip
Pattern Rotation 90 degrés
Juste pour comparaison voici les routines que j'ai utilisé dans fusion-c 2.0
Pattern Horizontal Flip
Code C :
//----------------------------------------------------------------------------- // Pattern Horizontal Flip. : Flip horizontaly a 8x8 Pixels pattern // *pattern : Address of the 8x8 Pattern // *buffer : address of a 8 Bytes buffer void PatternFlipH (void *Pattern, void *buffer) __naked __sdcccall(0) { Pattern,buffer; __asm ;-------------------------------------------- ;Flip horizontaly 8x8 Pattern ;input: ;DE = 8x8 Pattern ;HL = 8 bytes buffer ; ; Fast byte Fliping routine by John Metcaff ; Push ix ld ix,#0 add ix,sp ld e,4(ix) ld d,5(ix) ld l,6(ix) ld h,7(ix) pop ix ld b,#8 Hloop: push hl ld a,(de) ld l,a rlca rlca xor l and #0xAA xor l ld l,a rlca rlca rlca rrc l xor l and #0x66 xor l pop hl ld (hl),a inc hl inc de djnz Hloop ret __endasm; }
Pattern Vertical Flip
Code C :
//----------------------------------------------------------------------------- // Pattern Vertical Flip. : Flip vertically a 8x8 Pixels pattern // *pattern : Address of the 8x8 Pattern // *buffer : address of a 8 Bytes buffer void PatternFlipV (void *Pattern, void *buffer) __naked __sdcccall(0) { Pattern,buffer; __asm Push ix ld ix,#0 add ix,sp ld e,4(ix) ld d,5(ix) ld l,6(ix) ld h,7(ix) pop ix ld bc,#7 add hl,bc ld b,#8 Vloop: ld a,(de) ld (hl),a inc de dec hl djnz Vloop ret __endasm; }
Pattern Rotation 90 degrés
Code C :
//----------------------------------------------------------------------------- // Pattern Rotation : Rotate a 8x8 pixels pattern to 90° angles, right or left // *pattern : Address of the 8x8 Pattern // *buffer : address of a 8 Bytes buffer // direction : // 0 : Rotate to right 1: rotate to Left void PatternRotation (void *Pattern, void *buffer, char rotation) __naked __sdcccall(0) { Pattern,buffer,rotation; __asm ;-------------------------------------------- ;Rotate 8x8 Pattern ;input: ;DE = 8x8 Pattern address ;HL = 8 bytes buffer ;A = 0 Clockwise (R) ; 1 equals Counter Clockwise (L) ; ;Output: ; Rotates a Pattern 90° left or right into a buffer ; Push ix ld ix,#0 add ix,sp ld e,4(ix) ld d,5(ix) ld l,6(ix) ld h,7(ix) ld a,8(ix) pop ix ld c,#8 and #1 jr z,rotbigloopR ; If direction is right (=0) ; Left Rotation rotbigloopL: ld a,(de) inc de push hl ld b,#8 rotloopL: rra rl (hl) inc hl djnz rotloopL pop hl dec c jr nz,rotbigloopL ret ; Right Rotation rotbigloopR: ld a,(de) inc de push hl ld b,#8 rotloopR: rla rr (hl) inc hl djnz rotloopR pop hl dec c jr nz,rotbigloopR ret __endasm; }
aoineko
Membre non connecté
Conseiller Municipal
Les fonctions en assembleur semble bien optimisée, en dehors du passage des paramètres qui se fait via la pile alors qu'avec la nouvelle convention d’appel de SDCC ils pourraient être tous passé par registre.
Ca donnerait ça :
Les fonctions ne concernent également que les sprites 8x8.
On peut pourraient avoir des fonctions pour les sprites 16x16 qui appellent 4 fois les fonctions sur les 8x8, mais on perdrait un peu en performance. Edité par aoineko Le 06/11/2023 à 13h40
Ca donnerait ça :
Code C :
void PatternFlipV (const void *Pattern, void *Buffer) { Pattern; // -> HL Buffer; // -> DE __asm ld bc,#7 add hl,bc ld b,#8 Vloop: ld a,(de) ld (hl),a inc de dec hl djnz Vloop __endasm; }
Les fonctions ne concernent également que les sprites 8x8.
On peut pourraient avoir des fonctions pour les sprites 16x16 qui appellent 4 fois les fonctions sur les 8x8, mais on perdrait un peu en performance. Edité par aoineko Le 06/11/2023 à 13h40
On est toujours ignorant avant de savoir.
ericb59 :
Je serais curieux d'avoir les explication et le code d'un pro du Z80 comme notre ami Z80
Juste pour comparaison voici les routines que j'ai utilisé dans fusion-c 2.0
Pattern Horizontal Flip
Juste pour comparaison voici les routines que j'ai utilisé dans fusion-c 2.0
Pattern Horizontal Flip
Code C :
ld l,a rlca rlca xor l and #0xAA xor l ld l,a rlca rlca rlca rrc l xor l and #0x66 xor l }
Je note que vous avez tous les deux la même source internet
C'est les commentaires pour cette section dont je parle dans un premier temps.
Dans MSXgl c'est dans MSXgl/engine/src/sprite_tool.c et c'est la fonction :
//-----------------------------------------------------------------------------
// Flip 8 bits value
u8 Sprite_Flip(u8 val) __PRESERVES(c, d, e, h, l, iyl, iyh) Edité par z80 Le 06/11/2023 à 14h22
TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours)
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,...
ericb59
Membre non connecté
Conseiller Municipal
aoineko :
en dehors du passage des paramètres qui se fait via la pile alors qu'avec la nouvelle convention d’appel de SDCC ils pourraient être tous passé par registre.
Oui effectivement, ces fonctions n'étant pas stratégiques pour moi, je ne les aient pas encore converties au nouveau passage de paramètres.
aoineko :
Les fonctions ne concernent également que les sprites 8x8.
J'ai créé des routines en C pour les patterns en 16x16, qui utilisent les routines assembleur ci-dessus.
D'ailleurs je me suis bien pris la tête pour le replacement des patterns 8x8 dans un sprite 16x16 qui fait une rotation ou un flip ! J'ai trouvé une solution mais il y en a sans doute une meilleures...
Rappel un sprite 16x16 est composé de 4 patterns 8x8 dans cet ordre
AC
BD
Je vous laisse juge ...
Socle commun
Code C :
#ifndef __PATTERN_TRANSFORM_H__ #define __PATTERN_TRANSFORM_H__ 1 // Used to replace 8x8 patterns in a 16x16 sprite const char shift[4][4]={{16,0,24,8},{8,24,0,16},{16,24,0,8},{8,0,24,16}}; unsigned char __at(0xF41F) TempBuffer[32]; unsigned char __at(0xF41F+32) DoBuffer[32]; unsigned char rot; unsigned char i; #ifdef BASE_PATTERN_ADRESS #define FUSION_PATTERN_ADDRESS BASE_PATTERN_ADRESS #else #define FUSION_PATTERN_ADDRESS Peekw( 0xF926 ) #endif // void PatternRotation(void *Pattern, void *buffer, char rotation); // 8x8 Pattern rotation. Used for the Rotation sprite pattern's function ( void PatternFlipH(void *Pattern, void *buffer) __sdcccall(0); // Flips Horizontally a 8x8 pixels pattern void PatternFlipV(void *Pattern, void *buffer) __sdcccall(0); // Flips Vertically a 8x8 pixels pattern void Pattern16RotationVram(char pattern, char DestPattern, char rotation); void Pattern16FlipVram(char pattern, char DestPattern, char direction); void Pattern8RotationVram(char pattern, char DestPattern, char rotation); void Pattern8FlipVram(char pattern, char DestPattern,char direction); void Pattern8RotationRam(void *SrcAddr, void *DestAddr, char rotation); void Pattern8FlipRam(void *SrcAddr, void *DestAddr, char direction); #endif
Pattern 16x16 Rotation en VRAM
Code C :
void Pattern16RotationVram(char pattern, char DestPattern, char rotation) { CopyVramToRam(FUSION_PATTERN_ADDRESS + (pattern << 3), &TempBuffer, 32); for (int i = 0; i < 4; ++i) { PatternRotation (TempBuffer+i*8, DoBuffer+shift[rotation][i], rotation); } if (!DestPattern) { DestPattern=pattern; } CopyRamToVramNI(&DoBuffer, FUSION_PATTERN_ADDRESS + (DestPattern << 3), 32); // Copy FlipBuffer to VRAM EnableInterrupt(); }
Pattern 16x16 Flip en VRAM
Code C :
void Pattern16FlipVram(char pattern, char DestPattern, char direction) { CopyVramToRam(FUSION_PATTERN_ADDRESS + (pattern << 3), &TempBuffer, 32); if (direction==0) { for (char i = 0; i < 4; ++i) { PatternFlipH (TempBuffer+i*8, DoBuffer+shift[2][i]); } } else { for (char i = 0; i < 4; ++i) { PatternFlipV (TempBuffer+i*8, DoBuffer+shift[3][i]); } } if (DestPattern!=0) { pattern=DestPattern; } CopyRamToVramNI(&DoBuffer, FUSION_PATTERN_ADDRESS + (pattern << 3), 32); // Copy FlipBuffer to VRAM EnableInterrupt(); }
Edité par ericb59 Le 06/11/2023 à 18h07
aoineko
Membre non connecté
Conseiller Municipal
z80 :
Je note que vous avez tous les deux la même source internet
C'est parce qu'on a le même informateur. Un certain Paul Google.
On est toujours ignorant avant de savoir.
aoineko :
C'est parce qu'on a le même informateur. Un certain Paul Google.
z80 :
Je note que vous avez tous les deux la même source internet
C'est parce qu'on a le même informateur. Un certain Paul Google.
C'est bien à cette conclusion que j'étais arrivé en faisant moi même la même recherche
Il est vrai que l'optimisation en temps CPU est impressionnante parce que avec seulement le double de taille en octet du code assembleur on obtient une division du temps CPU d'un facteur 3,12!
Le mec précise ou du moins laisse entendre qu'après avoir écrit sa première version, il s'est posé la question de comment gagner "quelques" cycle CPU...
Et c'est son analyse statistique sur le nombre de décalages nécessaire à chaque bit pour atteindre sa position finale. Et ça c'est plutôt brillant. Edité par z80 Le 06/11/2023 à 20h43
TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours)
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,...
aoineko
Membre non connecté
Conseiller Municipal
z80 :
Il est vrai que l'optimisation en temps CPU est impressionnante parce que avec seulement le double de taille en octet du code assembleur on obtient une division du temps CPU d'un facteur 3,12!
Son algorithme est vraiment super performant. J'adore le and #0x66 qui fait très magie noire.
ericb59 :
J'ai pas regardé ton code, mais je suis certain qu'il est plus rapide que le mien, sans aucun doutes
Les fonctions en assembleur Flip et Rotate que tu utilises sont très bien. Je les d'ailleurs utilisées comme base pour les miennes. En fait, j'ai surtout retiré le surcout lié à la gestion du passage des paramètres par la pile et j'ai pu retirer une pair de push/pop qui faisait perdre 23 cycles à chaque itération sur les Flip. J'ai créé aussi des fonctions pour l'effet de Mask dont je suis assez fier (pas facile de gérer 3 pointers 16 bits en assembleur dans une boucle de façon performante). Il ne me reste plus que les fonctions Crop à convertir en assembleur (ça sera pour demain).
https://github.com/aoineko-fr/MSXgl/blob/main/engine/src/sprite_tool.c
Tu pourras évidemment récupérer tout ça pour Fusion-C. Edité par aoineko Le 07/11/2023 à 01h13
On est toujours ignorant avant de savoir.
aoineko :
Son algorithme est vraiment super performant. J'adore le and #0x66 qui fait très magie noire.
z80 :
Il est vrai que l'optimisation en temps CPU est impressionnante parce que avec seulement le double de taille en octet du code assembleur on obtient une division du temps CPU d'un facteur 3,12!
Son algorithme est vraiment super performant. J'adore le and #0x66 qui fait très magie noire.
En en fait les AND 0xAA et 0X66, ça va, mais le trio:
xor l
and 0xAA
xor l
Là, c'est de la bombe BB!
Vous comprendrez mieux quand vous aurez les commentaires.
Vous avez peut-être noté que sa version optimisée utilise TRES majoritairement des instructions dont l'OP Code tient sur un unique octet (optimisation des T cycles en réduisant les accès mémoires) sauf pour les AND ou il n'a pas le choix de deux octets.
TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours)
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,...
aoineko
Membre non connecté
Conseiller Municipal
Voilà, j'ai fini de passer toutes les fonctions en assembleur !
J'en ai profité pour renommer mon module qui s'appelle maintenant : Sprite FX.
Y a peut-être encore quelques cycles à gagner ici et là, mais c'est déjà bien plus rapide que la version C qui était déjà relativement rapide.
Si les amateurs d'assembleurs voient des améliorations possible, je suis preneur : https://github.com/aoineko-fr/MSXgl/blob/main/engine/src/sprite_fx.c
Pour ces fonctions, je privilégie la vitesse à la taille ; enfin, jusqu'à un certain niveau. Je n'ai pas été jusqu'à "déroulé" (unroll) les boucles.
J'en ai profité pour renommer mon module qui s'appelle maintenant : Sprite FX.
Y a peut-être encore quelques cycles à gagner ici et là, mais c'est déjà bien plus rapide que la version C qui était déjà relativement rapide.
Si les amateurs d'assembleurs voient des améliorations possible, je suis preneur : https://github.com/aoineko-fr/MSXgl/blob/main/engine/src/sprite_fx.c
Pour ces fonctions, je privilégie la vitesse à la taille ; enfin, jusqu'à un certain niveau. Je n'ai pas été jusqu'à "déroulé" (unroll) les boucles.
On est toujours ignorant avant de savoir.
aoineko
Membre non connecté
Conseiller Municipal
@ericb59 un utilisateur de MSXgl a porté mon outil de conversion d'image MSXimg sur Linux: https://github.com/aoineko-fr/MSXgl/tree/main/tools/MSXtk/bin
Ca aura mis le temps, mais toute la suite d'outils est (enfin) compatible Linux.
Pour macOS, il suffit de les recompiler j'imagine. Edité par aoineko Le 31/12/2023 à 16h02
Ca aura mis le temps, mais toute la suite d'outils est (enfin) compatible Linux.
Pour macOS, il suffit de les recompiler j'imagine. Edité par aoineko Le 31/12/2023 à 16h02
On est toujours ignorant avant de savoir.
aoineko
Membre non connecté
Conseiller Municipal
Hello,
Il y a 2 ans jour pour jour, sortais officiellement la première version de MSXgl, ma librairie pour créer des jeux MSX en langage C.
Apres la sortie des premiers jeux basés sur MSXgl en 2023, plein de nouvelles fonctionnalités et un gros travail de clean et de documentation, je considère que la librairie est maintenant suffisamment complète et stable pour passer son numéro de version en 1.0.0 !
Merci à tous ceux qui m'ont aidé ici à mieux comprendre le fonctionnement du MSX et à pouvoir créer du code qui exploite au mieux ses capacités.
La librairie et tous les outils nécessaires pour créer un programme final en ROM ou en disquette, sont disponible sur le GitHub du projet.
Pour en savoir plus :
- Documentation Wiki
- Documentation du code source
- Serveur Discord (avec plein de développeurs sympas toujours prêt à aider)
Et pour la suite, j'ai encore plein de chose à ajouter (notamment de nouveaux formats de musique) ou à optimiser.
Y a aussi pas mal de projets en cours donc on verra en fonction des besoins des uns et des autres.
J'espère qu'il y a encore plein de nouveaux jeux MSX à venir !
Edité par aoineko Le 17/01/2024 à 01h51
Il y a 2 ans jour pour jour, sortais officiellement la première version de MSXgl, ma librairie pour créer des jeux MSX en langage C.
Apres la sortie des premiers jeux basés sur MSXgl en 2023, plein de nouvelles fonctionnalités et un gros travail de clean et de documentation, je considère que la librairie est maintenant suffisamment complète et stable pour passer son numéro de version en 1.0.0 !
Merci à tous ceux qui m'ont aidé ici à mieux comprendre le fonctionnement du MSX et à pouvoir créer du code qui exploite au mieux ses capacités.
La librairie et tous les outils nécessaires pour créer un programme final en ROM ou en disquette, sont disponible sur le GitHub du projet.
Pour en savoir plus :
- Documentation Wiki
- Documentation du code source
- Serveur Discord (avec plein de développeurs sympas toujours prêt à aider)
Et pour la suite, j'ai encore plein de chose à ajouter (notamment de nouveaux formats de musique) ou à optimiser.
Y a aussi pas mal de projets en cours donc on verra en fonction des besoins des uns et des autres.
J'espère qu'il y a encore plein de nouveaux jeux MSX à venir !
Edité par aoineko Le 17/01/2024 à 01h51
On est toujours ignorant avant de savoir.
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie