Getting extra VBLANK
Moderator: Moderators
Re: Getting extra VBLANK
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.
Re: Getting extra VBLANK
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.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.
sonder
Re: Getting extra VBLANK
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.sonder wrote:Thanks for adding your explanation ... though despite that I admit I'm still a bit lost.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.
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?
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.
Through tricky-as-hell cycle counting.sonder wrote:How does Battletoads know when to re-enable rendering at the right scanline? Scanline hardware?
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: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.
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.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.
Re: Getting extra VBLANK
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.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?
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.How does Battletoads know when to re-enable rendering at the right scanline? Scanline hardware?
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.Everyone keeps mentioning $2006 writes for setting up the scroll. How does that work?
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.If it's not a big deal to do the scroll through $2006 then that's not a detractor.
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.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.
Re: Getting extra VBLANK
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?)
(Two edit conflicts in a row?)
Re: Getting extra VBLANK
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.
So yeah, it's a bit messy.
Re: Getting extra VBLANK
very interesting demo. thanks for sharing it!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?)
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
Re: Getting extra VBLANK
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.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.
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).
The amount of forced blanking it uses depends on the level.ulfalizer wrote:As no one seemed to mention it: Battletoads does keep rendering disabled for 20 or so (iirc) scanlines into the frame
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
Re: Getting extra VBLANK
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.
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.
Re: Getting extra VBLANK
Huh ? I don't see how this makes a difference.tokumaru wrote:T
1- Wasting 9 sprites. Not such a big deal if you use 8x16 sprites but very wasteful for 8x8 ones.
This is quite an elegant way to hide the top overscan area I have to admit.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.
Re: Getting extra VBLANK
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:Bregalad wrote:Huh ? I don't see how this makes a difference.tokumaru wrote: 1- Wasting 9 sprites. Not such a big deal if you use 8x16 sprites but very wasteful for 8x8 ones.
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.
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.This is quite an elegant way to hide the top overscan area I have to admit.
Re: Getting extra VBLANK
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.
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.
Re: Getting extra VBLANK
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.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.
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
Re: Getting extra VBLANK
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.
Re: Getting extra VBLANK
Relatively, it's the same, yes.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.
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.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).
Wouldn't you say that this explain why the sacrifice of 9 sprites is more meaningful with one sprite size than the other?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.
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.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.
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.