Questions about PPU emulation

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
xem
Posts: 5
Joined: Tue Nov 24, 2020 7:18 am

Questions about PPU emulation

Post by xem »

Hello NesDev!
I started making my own little NES emulator in JavaScript last month, as a hobby.
NesDev's wiki and forums have been my most valuable source of information to get started (especially with the CPU and memory map), thanks a lot!
Anyway, this week I'm starting my PPU and I have a few questions if you don't mind:

1) Color emphasis

If I understood correctly, the PPU has a global palette of 64 colors, and it can emphasize some color channels of the output (R and/or G and/or B) via PPUMASK register's bits 5-7. I also read the wiki's page about NTSC video, and kinda understand it, though as my emulator only works in a browser, with RGB pixels, I'd like to know if there was a rule-of-thumb that I could use to simulate emphasis more or less reliably.
For example, JSNES reduces all the non-emphasized channels by 25%, for example: rgb(255,255,255) + red emphasis => rgb(255,191,191)
Is that very far from the truth? Or can I improve it, for example by including 8 different pre-generated palettes in my code? (one for each bit pattern)
I saw Bisqwit's palette generator but I'm a bit lost, which radio buttons am I supposed to check?

2) Mid-frame updates

I read that the rendering could be altered mid-frame (i.e. between two visible scanlines) in many different ways:
- if PPUCTRL or PPUMASK registers are modified (ex: scrolling, active pattern table, left column visibility, background/sprite visibility, grayscale, color emphasis, etc)
- if the active pattern table is bankswitched or written on
- if the visible name tables / attribute tables are bankswitched or written on
- if the palettes are modified
- if sprites properties are modified
- if nametable mirroring is modified
If I understand correctly, I can render all my scanlines fearlessly until one of these events occurs, and if one of them occurs mid-frame, then I must take into account the new parameters before rendering the rest of my frame. Right?
The thing is, I also read that memory updates "could only be made during forced blanking", in other words, when rendering is disabled.
Does that mean they can't happen in the middle of a visible frame?
Or does it mean that the CPU must disable rendering mid-frame (for example during HBlank), do these changes, then reenable rendering before the next scanline?
And finally, what happens if the VRAM or pattern tables are modified mid-frame while the rendering is NOT disabled? Nothing?

3) Single pixel output

I read that the NES was capable to output single pixels on screen instead of tiles, is that true? or is it a fancy way to say that, theoretically, the PPU could generate kind of "single pixels" on the fly (if the cartridge provides CHR-RAM), by writing the pixel on a blank tile and associating it to a color palette also created on the fly?

4) Sprite limit glitch

I read that the PPU is buggy when it tests that more than 8 sprites are visible on the same scanline, but I'm not sure if this buggy behavior must be emulated (are there games that rely on it? Will some games be glitchy if I don't implement it?), and how it's supposed to be implemented exactly (what does it mean that "the PPU goes in diagonal after the 8th sprite, generating both false positives and false negatives" ? what diagonal? is the glitch active until the end of the scanline, or until the end of the frame? Will the next scanlines also glitch even if they have less than 8 sprites on them?) In other words, is it enough if I "simply" stop rendering sprites on each scanline when the number exceeds 8?

Thanks a lot for your help!
Last edited by xem on Fri Nov 27, 2020 12:01 pm, edited 1 time in total.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Questions about PPU emulation

Post by Quietust »

xem wrote: Tue Nov 24, 2020 9:00 am 1) Color emphasis

If I understood correctly, the PPU has a global palette of 64 colors, and it can emphasize some color channels of the output (R and/or G and/or B) via PPUMASK register's bits 5-7. I also read the wiki's page about NTSC video, and kinda understand it, though as my emulator only works in a browser, with RGB pixels, I'd like to know if there was a rule-of-thumb that I could use to simulate emphasis more or less reliably.
For example, JSNES reduces all the non-emphasized channels by 25%, for example: rgb(255,255,255) + red emphasis => rgb(255,191,191)
Is that very far from the truth? Or can I improve it, for example by including 8 different pre-generated palettes in my code? (one for each bit pattern)
I saw Bisqwit's palette generator but I'm a bit lost, which radio buttons am I supposed to check?
In general, a fixed palette will probably be fine for most users - if you want to get really fancy, then you can use a palette generator. Similarly, dimming the RGB channels for color emphasis will probably be fine for most cases, but if you're allowing hue/saturation adjustments then that'll get tricky.
xem wrote: Tue Nov 24, 2020 9:00 am 2) Mid-frame updates

I read that the rendering could be altered mid-frame (i.e. between two visible scanlines) in many different ways:
- if PPUCTRL or PPUMASK registers are modified (ex: scrolling, active pattern table, left column visibility, background/sprite visibility, grayscale, color emphasis, etc)
- if the active pattern table is bankswitched or written on
- if the visible name tables / attribute tables are bankswitched or written on
- if the palettes are modified
- if sprites properties are modified
If I understand correctly, I can render all my scanlines fearlessly until one of these events occurs, and if one of them occurs mid-frame, then I must take into account the new parameters before rendering the rest of my frame. Right?
The thing is, I also read that memory updates "could only be made during forced blanking", in other words, when rendering is disabled.
Does that mean they can't happen in the middle of a visible frame?
Or does it mean that the CPU must disable rendering mid-frame (for example during HBlank), do these changes, then reenable rendering before the next scanline?
And finally, what happens if the VRAM or pattern tables are modified mid-frame while the rendering is NOT disabled? Nothing?
Some changes take effect immediately, but some are delayed by varying amounts (e.g. by a few pixels, until the next tile, until the next scanline, or even until the next frame). The wiki should document which delays are associated with each setting - if it doesn't, then it's worth pointing it out so that someone (who knows the proper answer) can fix it.

"Forced blanking" does, indeed, mean turning off rendering mid-frame so you can modify video memory. The problem is that HBlank time is too short to do anything meaningful, so you'd typically need to disable rendering for at least a full scanline, which may result in a visible gap on the screen.

If you try to modify VRAM while the PPU is rendering, the data will generally be corrupted and you'll get a corresponding visual glitch.
xem wrote: Tue Nov 24, 2020 9:00 am 3) Single pixel output

I read that the NES was capable to output single pixels on screen instead of tiles, is that true? or is it a fancy way to say that, theoretically, the PPU could generate kind of "single pixels" on the fly (if the cartridge provides CHR-RAM), by writing the pixel on a blank tile and associating it to a color palette also created on the fly?
Not quite - palettes cannot be easily modified on the fly (you'd have to turn off rendering mid-frame, which takes time and results in graphical glitches), and any given tile can only use a single set of colors. Writing custom tiles to VRAM is possible (e.g. see the game "Elite"), but it doesn't work as well on NTSC unless you restrict it to a very small area, because there's not enough memory bandwidth to update the whole screen during a single VBLANK.

If you've got special hardware, though, you can stream custom pattern and attribute data for each scanline of each tile (i.e. 8x1 pixel areas) to the screen in real-time. The MMC5 mapper does some of this - every single tile gets its own palette index and 1KB CHR bank, allowing a single screen to select from 16,384 individual tiles instead of only 256.
xem wrote: Tue Nov 24, 2020 9:00 am 4) Sprite limit glitch

I read that the PPU is buggy when it tests that more than 8 sprites are visible on the same scanline, but I'm not sure if this buggy behavior must be emulated (are there games that rely on it? Will some games be glitchy if I don't implement it?), and how it's supposed to be implemented exactly (what does it mean that "the PPU goes in diagonal after the 8th sprite, generating both false positives and false negatives" ? what diagonal? is the glitch active until the end of the scanline, or until the end of the frame? Will the next scanlines also glitch even if they have less than 8 sprites on them?) In other words, is it enough if I "simply" stop rendering sprites on each scanline when the number exceeds 8?
In general, most games won't break if you fail to emulate the sprite overflow bug, but they might look wrong. If you want to understand how the bug works, you need to understand how the PPU's sprite engine works, and that's explained on the wiki in reasonable detail.

It's not enough to just stop rendering sprites, because the PPU Status register (at $2002) lets you query whether or not 8 sprites have been encountered on a single scanline, and some games do rely on that flag for certain effects (like screen splitting). It's also worth pointing out that while the overflow bug is limited in scope to a single scanline (the logic resets at the beginning of the next scanline), the above-mentioned sprite overflow flag persists until the end of the frame.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
xem
Posts: 5
Joined: Tue Nov 24, 2020 7:18 am

Re: Questions about PPU emulation

Post by xem »

@Quietust Thanks a lot for these answers!
I'm quite mind blown by the MMC5 features you mention in the 3rd answer 🤯
For answer 2, I haven't found any information about these delays for each PPU setting on the Wiki or on Google, any idea here I could point that out?
Post Reply