Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Vos tutoriels et astuces


Index du Forum » Vos tutoriels et astuces » [Prizm] - Rafraichissement de l'écran
Nemhardy Hors ligne Grand maître des Traits d'Esprit Points: 1243 Défis: 54 Message

[Prizm] - Rafraichissement de l'écran

Posté le 16/04/2014 18:50

Un petit post pour vous exposer pour l'instant quelques réflexions et pistes de recherche par rapport au rafraichissement de l'écran sur Prizm, qui est un des facteurs rendant l’exécution de programmes "lente". Rien de bien concret pour l'instant, mais je partage juste des idées/explications pour avoir des éventuels retours.

Il y a quelques temps, avec Lancelot, nous avions discuté de la faisabilité d'une fonction équivalente à Bdisp_PutDisp_DD() (ou la fonction permettant de transférer le contenu de la VRAM à l'écran et donc de l'afficher). Le "truc" c'est que la quantité d'informations à envoyer à l'écran est assez énorme : la VRAM est un buffer de 165ko environ (au passage plus que ce qu'un malloc peut allouer comme espace ). Le syscall évoqué plus haut pratique donc une copie en utilisant le principe de DMA, soit un accès direct à la mémoire. Cela permet de "décharger" le processeur qui ne s'occupe que de lancer le transfert (et éventuellement de contrôler le bon déroulement de celui-ci). Cependant, ce syscall est en quelque sorte bloquant, c'est à dire que tant que le transfert n'est pas terminé, et bien, le programme est en pause. Ce n'est pas une ineptie totale de Casio, mais quelque chose d'assez logique/sécuritaire car il serait fâcheux de ré-entrer dans des fonctions de dessin qui modifieraient le contenu de la VRAM avant même que celle-ci ait fini d'être transférée, ou même de relancer un transfert alors qu'un autre est déjà en cours... Cela peut néanmoins s'avérer gênant car le temps de transfert est assez conséquent.

ProgrammerNerd, auteur notamment du port d'Open JackRabbit ou du lecteur Mpeg2 que vous pouvez voir dans cette news, a développé une fonction permettant de résoudre quelque-peu ce problème. Il a écrit un "set" de fonctions (qui est d'ailleurs une sorte de "traduction" en C de la fonction en ASM que l'on peut voir dans la doc de SimLo, donc plus simple à mettre en place) qui se décompose en deux fonctions : l'une permettant simplement de lancer le transfert, et l'autre permettant de bloquer le programme en attendant la fin du transfert. Le transfert n'est donc théoriquement pas plus rapide, car utilisant la même unité de DMA, mais... enfin, j'explique ça dans la suite.

Je vous mets ici le code tel qu'il est dans le lecteur Mpeg2

[green]// Module Stop Register 0[/green]
[brown]#define MSTPCR0 (volatile unsigned *)0xA4150030[/brown]
[green]// DMA0 operation register[/green]
[brown]#define DMA0_DMAOR (volatile unsigned short*)0xFE008060[/brown]
[brown]#define DMA0_SAR_0 (volatile unsigned *)0xFE008020[/brown]
[brown]#define DMA0_DAR_0 (volatile unsigned *)0xFE008024[/brown]
[brown]#define DMA0_TCR_0 (volatile unsigned *)0xFE008028[/brown]
[brown]#define DMA0_CHCR_0 (volatile unsigned *)0xFE00802C[/brown]
/* DMA register offsets
destination address register_0*/
[green]//[brown]#define DAR_0 0x04[/brown][/green]
[green]// transfer count register_0[/green]
[green]//[brown]#define TCR_0 0x08[/brown][/green]
[green]// channel control register_0[/green]
[green]//[brown]#define CHCR_0 0x0C[/brown][/green]
[brown]#define LCD_BASE 0xB4000000[/brown]
[brown]#define VRAM_ADDR 0xA8000000[/brown]
[brown]#define SYNCO() __asm__ volatile([gray]"SYNCO\n\t":::"memory"[/gray]);[/brown]
[brown]#define PRDR *(volatile unsigned char*)0xA405013C[/brown]
[brown]#define LCDC *(volatile unsigned short*)0xB4000000[/brown]

[brown]#define LCD_GRAM_X 0x200[/brown]
[brown]#define LCD_GRAM_Y 0x201[/brown]
[brown]#define LCD_GRAM 0x202[/brown]
[brown]#define LCD_WINDOW_LEFT 0x210[/brown]
[brown]#define LCD_WINDOW_RIGHT 0x211[/brown]
[brown]#define LCD_WINDOW_TOP 0x212[/brown]
[brown]#define LCD_WINDOW_BOTTOM 0x213[/brown]

void DmaWaitNext(void)
{
    [b][blue]while[/blue][/b](1){
    [b][blue]if[/blue][/b]((*DMA0_DMAOR)&4)[green]//Address error has occured stop looping[/green]
    [b][blue]break[/blue][/b];
    [b][blue]if[/blue][/b]((*DMA0_CHCR_0)&2)[green]//Transfer is done[/green]
    [b][blue]break[/blue][/b];
    }
    SYNCO();
    *DMA0_CHCR_0&=~1;
    *DMA0_DMAOR=[maroon]0[/maroon];
}
void DoDMAlcdNonblock(void)
{
    Bdisp_WriteDDRegister3_bit7(1);
    Bdisp_DefineDMARange(6,[maroon]389[/maroon],[maroon]0[/maroon],[maroon]215[/maroon]);
    Bdisp_DDRegisterSelect(LCD_GRAM);

    *MSTPCR0&=~(1<<21);[green]//Clear bit 21[/green]
    *DMA0_CHCR_0&=~1;[green]//Disable DMA on channel 0[/green]
    *DMA0_DMAOR=[maroon]0[/maroon];[green]//Disable all DMA[/green]
    *DMA0_SAR_0=VRAM_ADDR&0x1FFFFFFF;[green]//Source address is VRAM[/green]
    *DMA0_DAR_0=LCD_BASE&0x1FFFFFFF;[green]//Desination is LCD[/green]
    *DMA0_TCR_0=(216*384)/16;[green]//Transfer count bytes/32[/green]
    *DMA0_CHCR_0=[maroon]0[/maroon]x00101400;
    *DMA0_DMAOR|=[maroon]1[/maroon];[green]//Enable DMA on all channels[/green]
    *DMA0_DMAOR&=~6;[green]//Clear flags[/green]
    *DMA0_CHCR_0|=[maroon]1[/maroon];[green]//Enable channel0 DMA[/green]
}


C'est pas très joli je vous l'accorde (en mettant en parallèle avec la doc de SimLo et les commentaires, on arrive à comprendre quelques trucs, mais après, le principe est juste de lancer un transfert, donc rien de bien passionnant). Quoi qu'il en soit, la fonction DoDMAlcdNonblock(); permet de lancer le transfert et DmaWaitNext() comme son nom l'indique permet de "bloquer" le programme jusqu'à la fin du transfert précédent.

Présentée comme ça, la fonction n'est pas très intéressante, car elle se base uniquement sur la VRAM et oblige donc à attendre la fin du transfert précédent pour pouvoir dessiner dedans. Néanmoins, on voit clairement que l’adresse de la VRAM est juste mise dans un registre comme adresse de source pour la copie : il me semble donc envisageable d'utiliser 2 buffers et de les copier en alternance : ainsi, l'un est en train d'être copié tandis que l'autre est en train d'être remplis. Le soucis majeur serait la taille de ce buffer relativement conséquente, mais il faut savoir qu'il existe une zone de la mémoire destinée à contenir la copie de la VRAM (donc de même taille que cette dernière) crée suite à l'appel de SaveVRAM_1() qui est potentiellement exploitable (j’attends une réponse sur Cemetech pour en savoir plus et confirmer/infirmer la chose). Cela aurait quelques inconvénients (comme le fait de devoir travailler en (char*) et non plus en (short*), l'adresse 0 de la zone étant impaire) mais je pense que le potentiel semblant de "multithreading" (on copie d'un côté et dessine de l'autre) peut être assez "rentable" pour faire abstraction de ces défauts.

On peut envisager un programme fonctionnant ainsi :

while(jeu) {
    calcul()
    dessin()
    DmaWaitNext()
    DoDMAlcdNonblock()
}


Où les adresses des buffers vidéos utilisées dans la fonction de dessin et de rafraichissement seront alternativement échangées : calcul() et dessin() seront donc potentiellement appelée alors que le transfert est toujours en cours, ce qui n'est pas possible avec le syscall de base !
Le DmaWaitNext() reste important car empêchant les transferts de se chevaucher .

Une autre piste que l'on peut envisager est le fait de pouvoir restreindre la zone de la VRAM à copier pour, par exemple, dans le cadre d'un RPG, actualiser uniquement les zones qui doivent être actualisées (mouvement des persos) et ne pas toucher au décor par exemple (je n'ai pas fait de tests à ce niveau là, donc plus hypothétique peut être), ce qui aurait, je pense le mérite d’accélérer à nouveau les transferts.





Nemhardy Hors ligne Grand maître des Traits d'Esprit Points: 1243 Défis: 54 Message

Citer : Posté le 01/05/2014 00:19 | #


Oups, s'cusez moi, j'ai peut-être parlé peu tôt ... En fait, jusqu'à présent, tout mes tests se faisaient sur émulateur (plus pratique et censé bien émuler la calto, même à un niveau un peu plus bas), et là, au moment de faire des tests sur la vraie... ben ce qui marche niquel sur émulateur ne marche pas du tout comme escompté sur la vraie (ça marche un peu, mais le comportement est ... étrange)... Donc je continue de creuser et tiendrai le topic au courant .

Ajouté le 22/02/2015 à 19:19 :
Hop, du nouveau ! On a trouvé récemment un syscall permettant de récupérer de manière propre l'adresse de la seconde VRAM dont on parlait plus tôt (celle utilisée avec les Save_VRAM), et apparemment ça à l'air plutôt stable avec. Je n'ai pas testé sur vraie machine car j'ai le bac blanc cette semaine et au cas où il se passerait quelque chose.

Il y a juste un petit "problème" mais qui se règle(ra) facilement c'est que l'adresse renvoyée n'est pas toujours alignable sur un short (et encore moins un int), donc ça impliquera peut être de "manger" un pixel à l'une des extrémités de l'écran pour rester propre...

Quoi qu'il en soit, si ça me refait pas le coup du *ça marche sur émulateur mais pas sur la machine*, je pense qu'on pourra enfin avoir quelque chose de bien sans consommer plus de mémoire ! (enfin quasiment, car pas grand monde utilise les sauvegardes de VRAM ).
Lephenixnoir En ligne Administrateur Points: 24699 Défis: 170 Message

Citer : Posté le 22/02/2015 19:23 | #


S'il y a des save_vram() y'a moyen d'utiliser l'écran en full resolution, non ?
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Nemhardy Hors ligne Grand maître des Traits d'Esprit Points: 1243 Défis: 54 Message

Citer : Posté le 22/02/2015 19:23 | #


C'est à dire ?
Lephenixnoir En ligne Administrateur Points: 24699 Défis: 170 Message

Citer : Posté le 22/02/2015 19:29 | #


Ben y'a pas assez de ram pour faire un buffer complet. Mais les save_vram() ils sont bien obligés de tout sauvegarder, du coup leur buffer à eux doit être complet. Pourquoi ne pas l'utiliser ?
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
-florian66- Hors ligne Ancien rédacteur Points: 2384 Défis: 20 Message

Citer : Posté le 22/02/2015 19:30 | #


sinon quand j'ai lu le titre faudrait faire une gestion des pixels différentes c-a-d ne changer que les pixels qui sont modifiés ( comme la TNT)

L'image prendrait moins de temps à être chargée
In Arch, I trust ! And you ?
Nemhardy Hors ligne Grand maître des Traits d'Esprit Points: 1243 Défis: 54 Message

Citer : Posté le 22/02/2015 19:38 | #


Y'a pas assez de heap* pour gérer ça dynamiquement, mais tu peux charger un buffer complet dans la stack, du moment qu'il reste de la place (on est à ~500ko disponibles avec la stack, pour une VRAM de grosso modo 165ko de mémoire) ^^. Ensuite c'est sûr que l'on peut utiliser ce buffer (car on a qu'un emplacement de sauvegarde) (enfin, j'aimerai d'abord être sûr que c'est assez stable avant de l'affirmer, mais à priori ça devrait aller) pour manipuler des grosses données.

@-Florian66- : Raisonner au pixel près pour les transferts ne doit pas être plus rapide que de tout rafraîchir à mon avis, en tout cas avec ce qui est possible actuellement. En revanche tu peux raisonner avec les zones où "il y a eu du mouvement" et là effectivement il y a moyen de gagner pas mal d'ips. Sur notre projet avec TheProg pour le grand concours on tournait à facilement 22-25fps quand on n'avait qu'une partie de l'écran à rafraîchir. Je te renvoie ici, sur "L'astuce 2" qui décrit ça.
Après c'est à toi de réfléchir quand tu remplis la VRAM pour ne pas tout redessiner si il n'y a pas besoin par exemple.
-florian66- Hors ligne Ancien rédacteur Points: 2384 Défis: 20 Message

Citer : Posté le 22/02/2015 19:42 | #


oui entièrement d'accord à développer
In Arch, I trust ! And you ?
Eiyeron Hors ligne Ancien modérateur Points: 5525 Défis: 57 Message

Citer : Posté le 04/03/2015 19:57 | #


Heh, quand on overclock à fond, Gravity Duck atteint les 50 fps et Bust-a-move est sacrément fluide. j'dis ça, j'dis rien.
Nemhardy Hors ligne Grand maître des Traits d'Esprit Points: 1243 Défis: 54 Message

Citer : Posté le 04/03/2015 20:59 | #


Certes, mais si on peut atteindre le même framerate sans overclocker autant, c'est plus intéressant je pense ^^… Et puis on a pas trop de retours sur l'overclock à de telles fréquences pour l'instant (genre influence sur la durée de vie du matos, stabilité…), Gbl08ma est d'ailleurs assez convaincu que l'overclock peut être responsable de certain brick recensés, après c'est possible qu'au final on ait quand même quelque chose utilisable, mais j'aime bien l'idée de n'utiliser l'overclock "qu'en dernier recours". Et puis on peut se dire qu'avec ça ça pourra tourner à plus de FPS de toute manière ^^…
Eiyeron Hors ligne Ancien modérateur Points: 5525 Défis: 57 Message

Citer : Posté le 04/03/2015 22:00 | #


Oui, c'est certains, les précédents overclocks étaient très instables finalement car ils ne faisaent qu'augmenter le PLL. F/Ptune a l'air de jouer avec les autres paramètres pour réguler les vitesses de lecture/écriture pour la jouer safe. Sur PTune t'as carrément un benchmark de fait pour vérifer quelles fréquences ont l'air convenables.

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 80 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