Getting extra VBLANK

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

tepples
Posts: 22603
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Getting extra VBLANK

Post by tepples »

The vblank code in Battletoads does indeed use tricky-as-hell cycle counting. But there are other substitutes for a scanline counter, such as abuse of DMC IRQ.
User avatar
sonder
Posts: 116
Joined: Wed Jun 26, 2013 12:35 pm
Location: Baltimore
Contact:

Re: Getting extra VBLANK

Post by sonder »

tepples wrote:The vblank code in Battletoads does indeed use tricky-as-hell cycle counting. But there are other substitutes for a scanline counter, such as abuse of DMC IRQ.
When I read about the existence of the DMC IRQ this was my immediate thought - maybe it could be used to count scanlines. Does it actually count as "abuse" though? I mean, I have no idea what the drawbacks are besides the hit to the CPU.
sonder
User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Getting extra VBLANK

Post by ulfalizer »

sonder wrote:
ulfalizer wrote:As no one seemed to mention it: Battletoads does keep rendering disabled for 20 or so (iirc) scanlines into the frame, showing that some commercial games did it at least (maybe lots of games did, but I only know of that one). This is what makes it tricky to emulate, as the current screen position needs to be within a certain interval when rendering is turned on for a sprite zero hit to happen. If that sprite zero hit does not happen, the game freezes.

As others have said, you'd need to set up the scroll yourself via $2006 writes before you turn on rendering if you keep rendering disabled on the pre-render line. The reason is that the "vert(v) = vert(t)" (copy vertical scrolling bits from t to v) operation in http://wiki.nesdev.com/w/images/4/4f/Ppu.svg does not happen with rendering disabled. If you turn off rendering near the end of the frame instead and turn it on before the pre-render line, you would not need to use $2006 writes.
Thanks for adding your explanation ... though despite that I admit I'm still a bit lost.

How does the sprite 0 hit factor into this? It would have to be used strictly to disable rendering at the bottom of the frame, right? So no splitscreen without scanline hardware of some kind, or tricky-as-hell cycle counting, right?
Yeah, if you determine when to disable rendering through a sprite zero hit, it would make most sense if it was for extra VBlank time at the bottom of the frame.

For Battletoads, the sprite zero hit comes after rendering is re-enabled (as it would have to, as no sprite zero hits can happen with rendering disabled) and so is really unrelated to the extra VBlank time. It just happens that messing up the timing related to the extra VBlank time also messes up the sprite zero hit.
sonder wrote:How does Battletoads know when to re-enable rendering at the right scanline? Scanline hardware?
Through tricky-as-hell cycle counting. :P
sonder wrote:Everyone keeps mentioning $2006 writes for setting up the scroll. How does that work? But it only matters if rendering hasn't been enabled by the "first" scanline (the pre-render scanline as you referred to it). If it's not a big deal to do the scroll through $2006 then that's not a detractor.
http://wiki.nesdev.com/w/index.php/The_ ... _scrolling goes over it. Basically, the VRAM address register (often called loopy_v or just v, used for the address during $2007 reads/writes) gets reused during rendering to hold the current nametable position (if you check the red cells in the linked diagram, you can see it getting updated during rendering to move between tiles). On the pre-render line (which is the line before the first visible line), the starting position (which is held in loopy_t/t) is copied over to v, but only if rendering is enabled. If rendering is disabled, v never gets initialized to the starting position, and you have to do it yourself via $2006 writes before you turn on rendering.
sonder wrote:I still don't have a clear idea of what it will take to accomplish this in say, an NROM game. People say cycle counting but it seems to me like I could easily disable rendering at line 200 on sprite 0 hit and just make sure to re-enable it after my vblank routine. Anyone please confirm if my thinking's right on this or not though.
I think that should work, unless there's complications related to OAM (which is very glitchy). If it does, it would be easier than adding extra VBlank at the top of the frame I think. You'd just have to make sure to re-enable rendering before the pre-render line.
User avatar
tokumaru
Posts: 12385
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Getting extra VBLANK

Post by tokumaru »

sonder wrote:How does the sprite 0 hit factor into this? It would have to be used strictly to disable rendering at the bottom of the frame, right? So no splitscreen without scanline hardware of some kind, or tricky-as-hell cycle counting, right?
In your case, yes. But you can also use it to detect the end of VBlank (the hit flag is cleared), for syncing up with the PPU at the top of the frame. Battletoads doesn't disable rendering early though, AFAIK, so it doesn't use sprite 0 with that purpose.
How does Battletoads know when to re-enable rendering at the right scanline? Scanline hardware?
Battletoads uses a very simple discrete mapper (it provides only PRG bankswitching and single screen mirroring selection), meaning there's no help from the hardware. It mostly uses timed code.
Everyone keeps mentioning $2006 writes for setting up the scroll. How does that work?
The normal way of setting the scroll (2 writes to $2005 and 1 write to $2000) only works if done during VBlank, and rendering is enabled at the start of the frame. If those conditions are not met, you need to write to $2005 and $2006 in a certain order to have the same amount of control over the scroll.
If it's not a big deal to do the scroll through $2006 then that's not a detractor.
It's not exactly hard, but since the bits are all "scrambled" a lot of people get confused when preparing the values that need to be written and defining when each one needs to be written.
People say cycle counting but it seems to me like I could easily disable rendering at line 200 on sprite 0 hit and just make sure to re-enable it after my vblank routine.
You are right about disabling rendering at scanline 200, but in order to enable it late you'll need timed code. If you simply re-enable rendering at the end of your VBlank handler rendering will start from the top of the screen. If you really want to blank scanlines at the top of the screen, you'll have to use timed code after detecting the end of VBlank (i.e. wait for the sprite hit flag to be cleared), set the scroll with $2005/$2006 and finally re-enable rendering.
tepples
Posts: 22603
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Getting extra VBLANK

Post by tepples »

DMC playback causes glitches on the controller lines. There are workarounds for standard controllers and the Four Score adapter, but these may not be compatible with some specialty controllers. It can cause problems with the Zapper and the Super NES Mouse, for instance, unless you read them only while playback is turned off. (On the other hand, the IRQ may make Zapper reading easier if you don't need Y precision down to the scanline.) It's also somewhat tricky to time the IRQ exactly, as its period is far greater than a scanline and its underlying timer can't be paused. But I have written a demo with stable blanking regions at the top and bottom of the screen: DPCM Letterbox.

(Two edit conflicts in a row?)
User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Getting extra VBLANK

Post by ulfalizer »

Ah, yeah, you'd have to use $2005 too along with $2006 to set the starting position. The reason is that $2006 can't be used to set the uppermost bit of the fine y scroll (for no good reason. The hardware changes to allow it would have been minimal).

So yeah, it's a bit messy. :|
User avatar
sonder
Posts: 116
Joined: Wed Jun 26, 2013 12:35 pm
Location: Baltimore
Contact:

Re: Getting extra VBLANK

Post by sonder »

tepples wrote:DMC playback causes glitches on the controller lines. There are workarounds for standard controllers and the Four Score adapter, but these may not be compatible with some specialty controllers. It can cause problems with the Zapper and the Super NES Mouse, for instance, unless you read them only while playback is turned off. (On the other hand, the IRQ may make Zapper reading easier if you don't need Y precision down to the scanline.) It's also somewhat tricky to time the IRQ exactly, as its period is far greater than a scanline and its underlying timer can't be paused. But I have written a demo with stable blanking regions at the top and bottom of the screen: DPCM Letterbox.

(Two edit conflicts in a row?)
very interesting demo. thanks for sharing it!

we will just be using standard controllers. we don't care about anything else at the moment. regardless, the way you stuffed the polling code into a block of time that you knew was safe was damn clever and comes as a nice bonus.

so the manner in which this disables just background rendering, obviously we can't do OAM DMA during the top of the screen, but does it allow extended time to update nametables? or is it just visual? and same goes for the bottom "blanked" area?

(p.s.: urr? didn't understand your last statement)
sonder
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: Getting extra VBLANK

Post by thefox »

sonder wrote:but it seems to me like I could easily disable rendering at line 200 on sprite 0 hit and just make sure to re-enable it after my vblank routine. Anyone please confirm if my thinking's right on this or not though.
It's easy only if your game logic is guaranteed to be finished by the time you're supposed to start actively polling for the sprite 0 hit. If the game logic ends up taking more time, you miss the hit.

When blanking the top of the screen, you have a guaranteed interrupt, plus you can poll for the end of the vblank by waiting for sprite 0 hit flag to be cleared (just need to make sure that it gets set somewhere in the frame for this to work).
ulfalizer wrote:As no one seemed to mention it: Battletoads does keep rendering disabled for 20 or so (iirc) scanlines into the frame
The amount of forced blanking it uses depends on the level.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
tokumaru
Posts: 12385
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Getting extra VBLANK

Post by tokumaru »

Thought I'd mention another method for syncing up with the PPU that hasn't been mentioned yet (which you can use along with sprite 0 hits): the sprite overflow flag. Yes, its behavior is a bit mystic, but it seems to work reliably if you place 9 high priority sprites in the same scanline. The drawbacks of this technique are:

1- Wasting 9 sprites. Not such a big deal if you use 8x16 sprites but very wasteful for 8x8 ones.
2- Can't be reliably used to detect the bottom of the screen, because game objects might accidentally line up more than 8 sprites before that point.
3- If used at the top, the high priority sprites will hide any actual game objects that go up there.

I do use the sprite overflow flag to detect the top of the screen in my scrolling engine, so I have to deal with issue number 3. What I do is put the 9 sprites at the very top of the screen and use timed code to wait the whole height of the sprites (I can do useful things during that time, and long as these tasks take a constant number of cycles) before enabling background rendering, so that even though sprites are enabled, the high priority ones will mask any game objects that go up there. Since sprites are enabled the whole time, I don't have to set the scroll the "magical" way and I still visually hide sprites and background at the top of the screen.
User avatar
Bregalad
Posts: 8029
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Getting extra VBLANK

Post by Bregalad »

tokumaru wrote:T
1- Wasting 9 sprites. Not such a big deal if you use 8x16 sprites but very wasteful for 8x8 ones.
Huh ? I don't see how this makes a difference.
3- If used at the top, the high priority sprites will hide any actual game objects that go up there.
[...] I still visually hide sprites and background at the top of the screen.
This is quite an elegant way to hide the top overscan area I have to admit.
User avatar
tokumaru
Posts: 12385
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Getting extra VBLANK

Post by tokumaru »

Bregalad wrote:
tokumaru wrote: 1- Wasting 9 sprites. Not such a big deal if you use 8x16 sprites but very wasteful for 8x8 ones.
Huh ? I don't see how this makes a difference.
On the NES, sprites cover a relatively small portion of the screen. The remaining 55 sprites can still cover quite a lot if each one is 8x16... more than all 64 8x8 sprites actually:

64 x 8 x 8 = 4096 pixels;
55 x 8 x 16 = 7040 pixels;

Giving up 9 8x8 sprites will reduce even further the already small area of the screen you can cover with sprites that size, so the impact is significantly more negative than if you used 8x16 sprites, IMO.
This is quite an elegant way to hide the top overscan area I have to admit.
I like it mainly because it doesn't mess with the rendering process, which means no different dot crawl (which doesn't always look good) and no $2005/$2006 tricks.
User avatar
Bregalad
Posts: 8029
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Getting extra VBLANK

Post by Bregalad »

I'm still not sure what you mean. No matter the sprite size, you loose 9 sprites out of 64, with 55 remaining which means you loose 14% of your sprites. Them being 8x8 or 8x16 doesn't affect this. On the other side you loose twice the area with 8x16 sprites because you're loosing sprites twice as big (but you had more sprite to start with).

If what you mean is that in a game with the same graphics, you are less likely to hit the 64 sprites bar with 8x16 sprite than with 8x8 I agree, so of course this remain true when the bar is lowered to 55. Nothing new here. However, it's not as simple as a calulation of area. For example, if you want to draw a 4x4 pixel bullet, you'll have to use a full 8x16 sprite if you use 8x16 sprites.
User avatar
sonder
Posts: 116
Joined: Wed Jun 26, 2013 12:35 pm
Location: Baltimore
Contact:

Re: Getting extra VBLANK

Post by sonder »

Bregalad wrote:I'm still not sure what you mean. No matter the sprite size, you loose 9 sprites out of 64, with 55 remaining which means you loose 14% of your sprites. Them being 8x8 or 8x16 doesn't affect this. On the other side you loose twice the area with 8x16 sprites because you're loosing sprites twice as big (but you had more sprite to start with).

If what you mean is that in a game with the same graphics, you are less likely to hit the 64 sprites bar with 8x16 sprite than with 8x8 I agree, so of course this remain true when the bar is lowered to 55. Nothing new here. However, it's not as simple as a calulation of area. For example, if you want to draw a 4x4 pixel bullet, you'll have to use a full 8x16 sprite if you use 8x16 sprites.
What he's saying is that, say you were using 8x8 sprites. You need 4 to make a 16x16 sprite, the smallest most common game character sprite size (you don't see 8x16 very often). With 8x16 sprites you only need 2. Therefore losing 9 sprites in 8x16 mode is less of an impact on your sprite budget.

I think it should be assumed, if you are using 8x16 mode that your sprites will generally take advantage of the available space as much as possible and you wouldn't be using 4x4 bullets very often in the first place.
sonder
User avatar
Bregalad
Posts: 8029
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Getting extra VBLANK

Post by Bregalad »

Contra (and it's sqeuel Super C) among with Gradius games (Gradius, Lifefore and Gradius II) uses 8x16 sprites and draws 4x4 bullets everywhere all the time.
User avatar
tokumaru
Posts: 12385
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Getting extra VBLANK

Post by tokumaru »

Bregalad wrote:I'm still not sure what you mean. No matter the sprite size, you loose 9 sprites out of 64, with 55 remaining which means you loose 14% of your sprites.
Relatively, it's the same, yes.
On the other side you loose twice the area with 8x16 sprites because you're loosing sprites twice as big (but you had more sprite to start with).
Exactly, the total area you're subtracting from is much bigger, so even after the subtraction you can still cover a larger area than you could with 8x8 sprites. IMO, this makes the sacrifice of 9 sprites much more acceptable. You might disagree.
If what you mean is that in a game with the same graphics, you are less likely to hit the 64 sprites bar with 8x16 sprite than with 8x8 I agree, so of course this remain true when the bar is lowered to 55.
Wouldn't you say that this explain why the sacrifice of 9 sprites is more meaningful with one sprite size than the other?
However, it's not as simple as a calulation of area. For example, if you want to draw a 4x4 pixel bullet, you'll have to use a full 8x16 sprite if you use 8x16 sprites.
Yes, you gain nothing with bullets and small particles, but you don't loose anything either, as 1 bullet = 1 sprite no matter the sprite size (what you lose is pattern table space, which is irrelevant in this case), but you can still save a lot of sprites on larger objects (and games that use 8x16 sprites often do, otherwise they'd use 8x8), so I maintain my opinion.

I'm not advocating that everyone should use 8x16 sprites (I like them that way, but I can understand if people prefer 8x8), I'm just pointing out that due to the fact that they can cover a larger area of the screen (bullets and small things aside) the sacrifice of 9 sprites is not as bad as if you were using 8x8. If you were to use all 55 8x16 sprites fully, you'd have the equivalent of 110 8x8 sprites. Even if you take all the bullets and partially used sprites out (the ones that are half empty), I'm sure you can pull off more than the equivalent of 64 8x8 sprites in most cases.
Post Reply