Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[True Pinball] Affichage des tables des flippers incorrect #520

Open
fafling opened this issue May 27, 2019 · 11 comments
Open

[True Pinball] Affichage des tables des flippers incorrect #520

fafling opened this issue May 27, 2019 · 11 comments

Comments

@fafling
Copy link

fafling commented May 27, 2019

Dans la dernière WIP (bios réel ou émulé), l'affichage des tables des flippers est toujours corrompu de cette manière :
Capture_true_pinball_table_20190523

Le même problème est présent dans les version européenne et japonaise (les copies d'écran sont faites avec la version japonaise).
Il existait déjà en v1.5.0 et v1.6.0 mais avec un affichage un peu différent.

Les tables de flipper sont affichées sur la couche NBG0 avec des pixels 16 bits sur un bitmap de 1024x256.
Capture_true_pinball_table_20190523_VDP2

Ce bitmap fait donc 512 ko et occupe toute la VRAM du VDP2. Or il est insuffisant pour contenir toute l'image du flipper car l'affichage est en double-interlaced, et comme le montre cette capture de la console, la résolution verticale du flipper est effectivement doublée. L'image complète de la table est donc affichée sur 2 champs successifs. Même en excluant le tableau à LED affiché par le VDP1 en haut sur 64 lignes, il reste 416 lignes de l'écran occupées par la table en NTSC.
Capture_true_pinball_table_20190523_youtube

Chaque champ nécessite donc une image de 416/2=213 lignes dans la VRAM du VDP2, et elles doivent donc être chargées au moins en partie à chaque frame : il est possible de stocker en permanence 256-213=43 lignes de chaque champ en permanence dans la VRAM (des lignes du milieu de l'image qui sont toujours à l'écran), et il reste à transférer 213-43=170 lignes à chaque frame. En supposant qu'il n'y ait pas d'autre optimisation, cela fait 170x2x1024=348160 octets à transférer à chaque frame vers la VRAM du VDP2.

L'intervalle du VBLANK ne peut pas suffire à un tel transfert, il doit donc déborder sur la période d'affichage actif du VDP2, probablement au moins sur les lignes du tableau à LED. Une telle copie pendant la période active doit nécessiter soit de n'activer le NBG0 qu'en bas du tableau à LED par un interrupt, voir de désactiver en haut de l'écran l'accès au VDP2 à une de ses 2 moitiés de VRAM pour ne l'activer par interrupt que quand le transfert de l'image est fini (voir p. 36 de la doc du VDP2). Une telle manip sur les timings peut être nécessaire si la copie du bas de l'image de la table n'est pas terminée quand le VDP2 arrive en bas du tableau à LED. En effet, le NBG0 occupe les 4 temps d'accès à la VRAM disponibles par cycle en haute résolution, donc quand le NBG0 est actif, aucun transfert vers la VRAM n'est possible sur les banks utilisés par le VDP2 pour lire les pixels à afficher sur cette couche.

La combinaison des éléments suivants rend nécessaire des changement des coordonnées de scrolling par interrupt à chaque ligne de l'écran sur le NBG0 :

  • Taille verticale insuffisante du bitmap.
  • Absence d'upscale vertical (le coordinate increment y est à 1).
  • Pas d'utilisation du line scrolling du NBG0.
  • Probable présence de lignes stockées en permanence dans la VRAM pour chaque champ.
  • Possible manipulation des timings d'accès à la VRAM en cours d'affichage.

L'affichage incorrect dans Kronos peut donc venir :

  • D'un problème de transfert des données vers la VRAM.
  • D'une mauvaise gestion des interrupts nécessaires en cours d'affichage.
@fafling
Copy link
Author

fafling commented May 28, 2019

Si on règle l'option View à top (l'option par défaut est invisible, voir #519 , appuyer sur gauche ou droite pour la changer), l'affichage des tables en vue de dessus est presque correct dans Kronos, il n'y qu'un effet de cisaillement horizontal au milieu de l'écran qui n'existe pas sur console.

C'est curieux car les mêmes problèmes se posent qu'en vue 3D (taille du bitmap insuffisante, quasiment le même paramétrage du NBG0, il n'y a que le scroll y qui change). La seule différence, c'est qu'il n'est pas rentable d'avoir des lignes stockée en permanence dans la VRAM car aucune n'est en permanence à l'écran.

@fafling
Copy link
Author

fafling commented May 28, 2019

Si le jeu manipule les timings d'accès à la VRAM, possible aussi qu'il change l'adresse du bitmap par un interrupt. Ce changement ne semble pas bien géré par Kronos, voir #417 .

@FCare
Copy link
Owner

FCare commented Jun 4, 2019

voila les registres qui changent en fonction des lignes;
Ox118=0 0
Ox116=0 0
Ox114=0 0
Ox10=4444 29
Ox18=ffff 29
Ox18=4444 95
Ox10=ffff 96
Ox10=4444 159
Ox18=ffff 160
Ox18=4444 223
Ox10=ffff 224
Ox10=ffff 256
Ox18=ffff 256
Ox70=0 256
Ox80=1 256

@fafling
Copy link
Author

fafling commented Jun 5, 2019

Les 3 premiers c'est le color offset A.
Le Ox10 c'est VRAM cycle pattern (bank A car je ne pense pas qu'il partitionne les banks en 2) timings T0 à T3.
Le Ox18 même chose mais pour le bank B.
Les 2 derniers sont les registres de scroll horizontal des NBG0 et 1.

Quand les cycle pattern valent 4444, ça donne 4 timings pour afficher le bitmap du NBG0 (p. 40 de la doc du VDP2). Quand ils valent FFFF, l'accès au bank est désactivé pour le VDP2, ce qui donne l'accès complet au CPU/SCU et permet le transfert de données graphiques vers ce bank.

Là, le jeu alterne :

  • Affichage du NBG0 sur le bank A, accès CPU/SCU sur le bank B.
  • Affichage du NBG0 sur le bank B, accès CPU/SCU sur le bank A.
    Cela peut indiquer qu'il copie un paquet de lignes du bitmap sur un des banks pendant qu'il affiche le paquet précédent sur l'autre bank.

La copie semble avoir lieu pendant une bonne partie de la période d'affichage car la dernière alternance entre banks a lieu aux lignes 223-224.

Je ne vois pas comment il peut s'en sortir sans modifier au moins à chaque alternance le registre de scroll vertical du NBG0 (0x74) et peut-être l'adresse de début du bitmap (0x3C).

@FCare
Copy link
Owner

FCare commented Jun 5, 2019

Est ce que tu as une idée de ce que fait la console si on demande a afficher un layer a partir d'un bank non accessible? Ca affiche du noir ou ca affiche a nouveau ce qu'il y avait la trame precedente?

@FCare
Copy link
Owner

FCare commented Jun 5, 2019

Ca doit etre une simple histoire de synchro.
Le VDP2 de la console calcule ligne par ligne, le CPU peut donc changer le contenu de la VRAM utilisée à la ligne precedente des qu'on passe une ligne.

Dans le cas de kronos, on enregsitre des parametres de registres ligne par ligne et a la fin d'une trame, on evalue le contenu des NBGx pour affichage. Dans le cas de kronos, le contenu de la memoire VRAM est donc considéré comme fixe (comme si le CPU ne pouvait pas acceder la VRAM pendant la periode d'affichage). Donc je pense que dans ce cas la, on se retrouve avec le contenu de l'image suivante sur un mapping registre de l'image courante. Il faut donc bufferiser la VRAM ligne par ligne potentiellement...
Je vais essayer de creuser ca.

@FCare
Copy link
Owner

FCare commented Jun 5, 2019

Une trace plus complete avec les lignes sur lesquelles les Bank de VRAM sont modifiées:

Ox118=0 0
Ox116=0 0
Ox114=0 0
Ox10=4444 29
Ox18=ffff 29
B0_Updated 29
B1_Updated 29
Ox18=4444 95
Ox10=ffff 96
A0_Updated 96
A1_Updated 96
Ox10=4444 159
Ox18=ffff 160
B0_Updated 160
B1_Updated 160
Ox18=4444 223
Ox10=ffff 224
A0_Updated 224
A1_Updated 224
Ox10=ffff 256
Ox18=ffff 256
Ox70=0 256
Ox80=1 256
Ox118=0 0
Ox116=0 0
Ox114=0 0
Ox10=4444 29
Ox18=ffff 29
B0_Updated 29
B1_Updated 29
Ox18=4444 95
Ox10=ffff 96
A0_Updated 96
A1_Updated 96
Ox10=4444 159
Ox18=ffff 160
B0_Updated 160
B1_Updated 160
Ox18=4444 223
Ox10=ffff 224
A0_Updated 224
A1_Updated 224
Ox10=ffff 256
Ox18=ffff 256
Ox70=0 256
Ox80=1 256
Ox118=0 0
Ox116=0 0
Ox114=0 0
Ox10=4444 29
Ox18=ffff 29
B0_Updated 29
B1_Updated 29
Ox18=4444 95
Ox10=ffff 96
A0_Updated 96
A1_Updated 96
Ox10=4444 159
Ox18=ffff 160
B0_Updated 160
B1_Updated 160
Ox18=4444 223
Ox10=ffff 224
A0_Updated 224
A1_Updated 224
Ox10=ffff 256
Ox18=ffff 256
Ox70=0 256
Ox80=1 256
Ox118=0 0
Ox116=0 0
Ox114=0 0
Ox10=4444 29
Ox18=ffff 29
B0_Updated 29
B1_Updated 29
Ox18=4444 95
Ox10=ffff 96
A0_Updated 96
A1_Updated 96
Ox10=4444 159
Ox18=ffff 160
B0_Updated 160
B1_Updated 160
Ox18=4444 223
Ox10=ffff 224
A0_Updated 224
A1_Updated 224
Ox10=ffff 256
Ox18=ffff 256

@fafling
Copy link
Author

fafling commented Jun 6, 2019

Si le VDP2 se retrouve à chercher une donnée sur bank inaccessible pour la couche concernée, je pense que la console n'affiche rien pour cette couche, comme si elle était désactivée.

Effectivement la VRAM du VDP2 peut être modifiée pendant la période d'affichage si les cycle pattern autorise l'accès au CPU/SCU, même si rares sont les jeu qui s'amusent à le faire.

En toute rigueur, il faudrait même travailler pixel par pixel sur le VDP2 : d'une part, je pense que le VDP2 consulte ses registres à chaque pixel, et d'autre part le SCU comporte un timer qui permet de générer un interrupt sur une colonne donnée de l'écran, ce qui permet de modifier le comportement du VDP2 en cours de ligne. Mais les jeux qui se sont lancés là-dedans doivent être encore plus rares !

La trace plus complète confirme la mise à jour du bank dont l'accès est interdit au VDP2. Le comportement est le même sur plusieurs frames.

Je crois que le jeu se sert en fait de la répétition verticale du bitmap car il ne fait que 256 lignes pour un écran de 512 en double interlaced en PAL (en comptant 2 champs successifs). Si le jeu ne modifiait pas la VRAM, le même bitmap serait répété 2 fois verticalement par le VDP2.

D'après les traces, pour chaque champ, il y a 64 lignes de champ entre les désactivations de bank (la 1ère est à la ligne 29, mais la table n'est visible qu'à partir de la ligne 32). Or cela correspond au nombre de lignes d'un champ affichables à partir de la portion du bitmap comprise dans un bank : il contient 128 lignes du bitmap, mais seule une ligne sur 2 est affichée par un champ en double interlaced.

Le VDP2 change automatiquement de bank source toute les 64 lignes de champ sans avoir à modifier de registre pour cela. Il suffit que le jeu lui donne l'accès à ce bank dans les cycle pattern au bon moment pour l'affichage fonctionne. La répétition verticale du bitmap fait que le VDP2 repasse automatiquement au bank A qui contient la 1ère moitié du bitmap après avoir fini de lire la 2ème moitié dans le bank B.

Donc si le jeu copie les 64 prochaines lignes à afficher par le champ courant dans le bank non utilisé par le VDP2, pendant que celui-ci utilise le bank accessible pour les 64 lignes du champ en cours d'affichage, il n'y a pas besoin de modifier d'autres registres contrairement à ce que je pensais au départ.

Mais cela suppose que le jeu scrolle le bitmap pour que le contenu du bank A corresponde aux lignes de champ 32 à 95, puisque c'est lui qui est accessible par le VDP2 dans cet intervalle. Or, d'après l'écran debug du VDP2, le NBG0 à un scroll vertical à -448, et comme la ligne de champ 32 a un V count à 64 (sur le champ pair, 65 sur l'impair). la formule de calcul de la coordonnée de la donnée graphique donne (p. 126 de la doc du VDP2) :

Display coordinate value Y = 1 * 64 - 448 = -384

Ce qui correspond au début du bank B au lieu du A. En fait, je m'attendrais plutôt à voir -64 comme scroll Y, ce qui correspond au décalage nécessaire pour placer les données du début du bank A juste sous le tableau à LED.

@FCare
Copy link
Owner

FCare commented Jun 7, 2019

L'implementation va etre complexe du coup. Je regarderais plus tard.

@fafling
Copy link
Author

fafling commented Dec 10, 2019

Toujours présent en WIP du 10/12 dans les 2 noyaux.

@fafling
Copy link
Author

fafling commented May 4, 2021

En conséquence du bug #1007 , le registre de scroll vertical vaut en fait 448 modulo 512, et non -448.
Vu que le bitmap du NBG0 fait 256 lignes, le modulo 512 n'est pas problématique car le bitmap est répété toutes les 256 lignes : on tombe sur la même ligne du bitmap quelque soit le multiple de 512 qu'on utilise.
Or 448 - 512 = -64
Et donc à la ligne de champ 32, on a : Display coordinate value Y = 1 * (2 * 32) - 64 = 0
La ligne de champ 32 correspond donc bien au début du bank A, dont l'accès est permis par le cycle pattern sur l'intervalle des lignes de champ 32 à 95 (64 à 190 en lignes d'écran).
Cela confirme l'hypothèse d'un chargement du bitmap dans la vram par paquets de 64 lignes pendant la période d'affichage, avec alternance du cycle pattern
En l'occurrence, l'émulation du cycle pattern n'est pas nécessaire (il sert à permettre le chargement sur un bank qui n'est pas affiché).
Par contre il faut une lecture par ligne de champ de la vram par le VDP2. Et il faut que chargement du bitmap en vram soit correctement synchronisé avec le numéro de la ligne de champ en cours d'affichage (faudrait voir quel est l'élément déclencheur de ces transferts, probablement les interrupts au hblank).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants