This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Should I disable rendering during vblank?

Should I disable rendering during vblank?
by on (#127154)
Another discussion got sidetracked by whether to explicitly disable rendering when updating video memory during vertical blanking.

In this post, rainwarrior wrote:
You should only turn the PPU off when you need to take rendering down for multiple frames so you can place a lot of data into the PPU. For an update that happens every frame, do not turn the PPU off

tepples wrote:
A little strong. Turning off rendering frees up the first 100 CPU cycles on the prerender scanline. I'd have said you usually don't need to.

tokumaru wrote:
There's no performance boost, you just get a little extra time for PPU memory accesses because the PPU itself won't be accessing memory during the pre-render scanline when rendering is off.

tepples wrote:
The difference between enabling during prerender and enabling after start of picture is that as long as rendering is reenabled before x=304 of the pre-render line, no special "skinny" address write sequences are needed to set the scroll position.


The pre-render scanline precedes the active picture. The rendering circuitry needs from x=321 to x=336 of this line to fetch the first two slivers of line 0 of the background, but it uses the bus the whole time if rendering is enabled. During the prerender scanline, if rendering is enabled, the PPU copies some bits from the scroll position (address t in Loopy's "The skinny on NES scrolling") to the video memory address (address v) to set up scrolling:
  • At x=257 (right side of picture), it copies the horizontal bits (0-4 and 10). This happens on the pre-render scanline and the active picture.
  • From x=280 through x=304 (the vsync pulse), it repeatedly copies the vertical bits (5-9 and 11-14). This happens only on the prerender scanline.
So as long as rendering is reenabled before x=304, the game still sees normal scrolling operation. The horizontal copy might be delayed by a scanline if rendering is disabled at x=257, causing wrong horizontal scrolling on the first scanline of the picture (which is well within NTSC's overscan). But it'll fix itself by the second scanline, and in any case, it overwhelmingly likely won't affect sprite 0 overlap detection.

It takes 6 cycles to disable rendering (LDA #$00 STA $2001 and 6 to reenable it (LDA #$1E STA $2001), yet it adds about 100 cycles (x=1 to x=300, 1 cycle per 3 dots) of usable video memory access time. I had to hack NES15, a game on the STREEMERZ multicart, to disable rendering while updating video memory because the multicart's NMI dispatch routine pushed updates just barely into the prerender line, causing visible artifacts on my NES.

Anyone have a specific test ROM demonstrating when video memory becomes inaccessible?
Re: Should I disable rendering during vblank?
by on (#127156)
You've taken my comment out of context again. :( My statement "do not turn the PPU off" means specifically with shiru's neslib library where the routines ppu_off and ppu_on_all have undesired consequences.
Re: Should I disable rendering during vblank?
by on (#127158)
Quote:
You've taken my comment out of context again.

Taking things out of their context is what makes mass media and opinion manipulating work. Tepples would do an excellent politician.
Re: Should I disable rendering during vblank?
by on (#127160)
It's good to have a clear explanation of this. Thanks tepples. Sorry for the misunderstanding in the other thread rainwarrior.

The game I was working on does a lot of nametable writes for smooth animation of the blocks falling. It is an attempt to port Jack Attack for the C64. Right now it just displays and animates the levels (up and down to change level). Platform colors are not correct.

It will delay adding more blocks from the top if the vram write time is reached, so I could benifit from more time, but I can ignore the issue without much consequence. (I can say that the animation looks a lot better than the C64 version.)
Re: Should I disable rendering during vblank?
by on (#127161)
tepples wrote:
The horizontal copy might be delayed by a scanline if rendering is disabled at x=257, causing wrong horizontal scrolling on the first scanline of the picture (which is well within NTSC's overscan). But it'll fix itself by the second scanline, and in any case, it overwhelmingly likely won't affect sprite 0 overlap detection.


Why stop there? Given the usual "224 visible lines" rough guideline, leave rendering off for as long as you need to make your vram updates, and anything up to 8 or so scanlines into the picture shoulnd't be a problem
Re: Should I disable rendering during vblank?
by on (#127162)
Sure, you can do this, but then the behavior of the PPU changes from what would normally be expected coming out of vblank. If I understand correctly, "So as long as rendering is reenabled before x=304" the PPU should behave the same as normal. And you need timed code, etc.
Re: Should I disable rendering during vblank?
by on (#127163)
natt wrote:
Why stop there?

Several reasons.

Quote:
Given the usual "224 visible lines" rough guideline, leave rendering off for as long as you need to make your vram updates, and anything up to 8 or so scanlines into the picture shoulnd't be a problem

Here are the problems with this approach:
1 - Alternate dot crawl pattern: the NTSC artifacts change significantly when rendering is disabled at the end of VBlank, and this affects how graphics look when an NTSC TV or emulator filter is used.
2 - Setting the scroll: the usual method for setting the scroll ($2000, $2005 x 2) doesn't work after VBlank ends, so you have to resort to $2005/$2006 trickery in order to set the scroll.
3- Jumping picture: "anything up to 8 or so scanlines" doesn't cut it, you have to enable rendering at the same point every frame, otherwise the picture will jump up and down. Timing a fixed amount of scanlines while rendering is off is not trivial.

While none of the above problems are definite deal breakers, they show that your suggestion isn't as trivial to implement as it may seem at first. A programmer has to know a lot about frame timing and scrolling, and account for differences between PAL and NTSC systems.
Re: Should I disable rendering during vblank?
by on (#127168)
tokumaru wrote:
While none of the above problems are definite deal breakers, they show that your suggestion isn't as trivial to implement as it may seem at first. A programmer has to know a lot about frame timing and scrolling, and account for differences between PAL and NTSC systems.


We're talking about a trick that only gets you ~100 extra cycles of time, i.e. about 5%. So... you're talking about a person who is capable of making use of 5% more efficiency in their vblank, but isn't capable of writing timed code? Don't forget if you go even slightly over you have to fall back to the more advanced technique. If you're using this 5% for a safety buffer for sloppy code, you'd better not be too sloppy then!

I kinda think either simple rule to "always turn off rendering during vblank" or "always leave rendering on during vblank" is a non-issue for a novice NES programmer. If you need to do it, you probably know something about what you're doing. Writing an NMI is probably the trickiest task a novice NES programmer might have on their plate, I don't think general-purpose advice about the sprite rendering flag will really make it easier.

An application to PAL seems even less relevant, given its vastly longer vblank period. Also, there's a caveat there that OAM DMA should be done last if rendering is going to be turned on late (since its data isn't stable much longer than a vblank). That's a bit of a silent killer, since nobody seems to emulate OAM decay.

What did we determine about the PAL vblank and OAM before, I can't quite remember. Does it force an OAM refresh midway through its vblank? (Was there a conflict if you try to OAM DMA too late?) Does it require the sprite rendering flag to be set in $2001 by that point? There's some hariy details here.
Re: Should I disable rendering during vblank?
by on (#127171)
rainwarrior wrote:
What did we determine about the PAL vblank and OAM before, I can't quite remember. Does it force an OAM refresh midway through its vblank? (Was there a conflict if you try to OAM DMA too late?)
Yeah, those were the problems. Even worse, the PAL NES never fully disables sprite evaluation: you must OAM DMA during the 21 scanlines after NMI. (thefox's post about this)
Re: Should I disable rendering during vblank?
by on (#127173)
rainwarrior wrote:
tokumaru wrote:
While none of the above problems are definite deal breakers, they show that your suggestion isn't as trivial to implement as it may seem at first. A programmer has to know a lot about frame timing and scrolling, and account for differences between PAL and NTSC systems.


We're talking about a trick that only gets you ~100 extra cycles of time, i.e. about 5%. So... you're talking about a person who is capable of making use of 5% more efficiency in their vblank, but isn't capable of writing timed code? Don't forget if you go even slightly over you have to fall back to the more advanced technique. If you're using this 5% for a safety buffer for sloppy code, you'd better not be too sloppy then!

Tokumaru was explicitly talking about the case where rendering is kept off for more than 1 scanline.

lidnariq wrote:
rainwarrior wrote:
What did we determine about the PAL vblank and OAM before, I can't quite remember. Does it force an OAM refresh midway through its vblank? (Was there a conflict if you try to OAM DMA too late?)
Yeah, those were the problems. Even worse, the PAL NES never fully disables sprite evaluation: you must OAM DMA during the 21 scanlines after NMI. (thefox's post about this)

Just to clarify, I never tested exactly where the refresh period landed and how long it was. I only noticed that the first ~20 or so scanlines were safe. So there might be other safe time slots after NMI where the sprite uploading could be placed. I'm also not sure at all how it does the refresh (whether it uses the normal sprite evaluation logic).