The fceux widget telling how many frames the controller was not polled since power-on.
Count of frames with no input poll is one way to measure a game's slowdown, as TAS authors need to minimize lag to save frames. Is it a good or bad practice to skip polling input during bulk data loads? I know a Vs. System game needs to poll each frame because the coin mech presses the coin drop button for only about 3 frames if I remember correctly. But is there a reason to do so outside Vs.?
If you want to process a edge transition at the first frame after the bulk load it's probably a good idea to always poll, or at least poll on the very last frame of the load, before the first active game fame. Not polling would make those long time gaps act as a button buffer, which is actually good thing for genuine game lag.
In my game engine, I only poll input when I process the player action (or in other cases such as the menu) and do *not* do this in i.e. the VBlank NMI routine systematically. In particular if I do not use the input I do not poll it, however some games polls controller in the NMI routine. (There is several reason it's a bad idea, yet they still did it that way).
Bregalad wrote:
In my game engine, I only poll input when I process the player action (or in other cases such as the menu) and do *not* do this in i.e. the VBlank NMI routine systematically. In particular if I do not use the input I do not poll it, however some games polls controller in the NMI routine. (There is several reason it's a bad idea, yet they still did it that way).
Care to elaborate?
Oh yeah, it's simply that in the case where the game would slow down, it's better to be safe and know the controller is read only once per logical frame (even if that frame happens to spawn across two real frames). For example when checking if, for instance, the UP button is pressed and I know the answer is no, I can assume it's not pressed on further reads of the controller variable. If the NMI updates the variable, then there's a low chance than it would update it while the program would do game logic based on it, potentially leading to crazy decision making and glitches. The chance of this happening is low, but possible.
I know Megaman 1 doesn't read the controller prior to a boss battle i.e. when the door closes, the boss appears and its life goes full. I know because during that time, I cannot make the PowerMappers menu appear. I mention this only to talk about a known case where the controller isn't polled every frame.
You could simply have a flag that says "I'm done updating for this logical frame" and only poll the controller in NMI when set, then unset the flag. In fact, you probably want to only update the graphics then anyway, so you don't end up showing a half-updated frame onscreen.
Or you could read the controller every frame in the NMI and buffer the input, and have the game engine copy that buffered state for use in the logical frame. Some frames would be skipped and never used by the engine in case of slowdown, but the controller would still be read.
tokumaru wrote:
Or you could read the controller every frame in the NMI and buffer the input, and have the game engine copy that buffered state for use in the logical frame.
This is essentially what you have to do on the Super NES if you're using controller autoreading.
Because autoreading starts at vblank and finishes a few cycles later (it's possible to use $4016/$4017 like on NES as well though), so the reading has to be done in NMI (or at least sometime after vblank).
But on NES it's easier to just save the readings for the logical frame, like Bregalad do, instead of bothering with buffers, isn't it?
I use buffers anyway, because of the way I've implemented demo playback. The playback code basically tampers with the buffered state, replacing all bits (except that of the "start" button) with recorded states. The real "start" bit is OR'd with the recorded "start" bit and the result is used to decide whether to end the demo.
Two alternative ways of solving this:
1. Don't have lag frames. Then the problem doesn't apply.
2. Don't depend on input in a way that a missed frame will matter, e.g. a continuous fire vs fire-per-tap mechanic might obviate the difference.
These are both highly dependent on your specific application, but I think they're both a valid way to sidestep the issue, for the right situation.
Wow guys. I wasn't asking for a solution to that problem - that problem is unlikely to happen anyway. I was just pointing out why it's a better idea to poll the controller before you need to take decision based on it, in the local code, rather than doing it as part of the interrupt routine. That's all. What you guys are telling me is solutions if it was REQUIRED to poll the controller in the interrupt routine, and yes indeed there is a zillion of solutions, yet it is even simpler to not poll the controller in the NMI to avoid any problems.
Am I missing context from a thread split here? I don't quite see that question in the history, bregalad... I do think it's a good question though:
There is probably a small gain in responsiveness to be had by timing an input poll as late in the frame as you can manage, but I think this is at odds with consistency. If delaying the poll introduces jitter in the actual timing, even though you might be giving the user a few more milliseconds to respond, it's probably bad if that advantage only applies sometimes.
If they have just enough time to react to something, but only on some frames and not others, that's a bad situation. They have a loss of control because they can't reliably get the result. It's hard to learn to anticipate a timing if it's not always the same.
So in general I think it is better to poll consistently than trying to poll with the least latency, at least when we're already able to poll at the display rate anyway.
I don't really get if you mean it's better to read during the NMI or the logical frame?
Also what is a "lagframe"?
My current setup is to have the NMI handler only handle graphic updates (sprites (OAM-DMA), BG, palette, PPU settings and scrolling in that order) and the sound routine, while the main program loop in the Reset handler handles reading controllers, filling the buffers for graphic updates and all logic. I put a wait for an NMI to finish at the beginning of the main loop (as I understand is the common practice to make game logic advance in a consistent frame rate). And because of that the main loop should not happen more than the NMI happens (the reverse isn't true if the main loop takes too long though). So therefore the controllers are effectivly read only ones per frame even though they are read in the main loop.
A lag frame is when the main loop takes too long and is interrupted by the NMI. The problem with reading the controllers the NMI in this case is that the part of the main loop that ran before the NMI will see one controller state, while the part that runs after the NMI will see another state, and this could cause inconsistencies in the game logic (a button might appear both pressed and not pressed in the same logical frame depending on when you check it).
Another thing to worry about in case of lag frames is the correctness of VRAM update buffers and PPU parameters such as the scroll. You must implement some means of not letting the NMI handler use partially filled buffers or new scroll values until all VRAM updates are properly carried out.
I see, that's what I thought.
The graphics updates each have their own flag (except OAM-DMA) that has to be set before they run (as suggested the article
The frame and NMIs) and the flag are only set in the main loop when there are pending updates in the corresponding buffer. But this also means an NMI is not always of the same length every frame, not sure if that is a big problem (music might get out of beat I guess).
The reason why OAM-DMA isn't conditional is because I thought earlier that it had to happen every frame. Maybe I should make that conditional too, to avoid it using a partially filled OAM buffer?
Pokun wrote:
The graphics updates each have their own flag (except OAM-DMA) that has to be set before they run (as suggested the article
The frame and NMIs) and the flag are only set in the main loop when there are pending updates in the corresponding buffer.
I don't know if individual flags for each buffer is the way to go, since the different updates might be correlated in some way that only makes sense if they're all performed at the same time. For example, in a game where the player can change characters on the fly, it makes sense to change the character's patterns, palette and OAM entries all at the same time, otherwise you may end up with miscolored or glitchy-looking sprites for a brief moment. The individual updates should not depend on each other if it there's a chance that only some of them will be carried out.
Quote:
But this also means an NMI is not always of the same length every frame, not sure if that is a big problem (music might get out of beat I guess).
I don't know as much about audio as I'd like, but I assume this distortion is way too subtle for anyone to notice. At 15720 (262 * 60) scanlines per second, a period of 20 scanlines (the length of vblank) is less than 1.3ms. I hope I did the math right.
Quote:
The reason why OAM-DMA isn't conditional is because I thought earlier that it had to happen every frame.
OAM starts decaying if the PPU is off for too long. I don't know how long is "too long", but if you aren't using forced blanking, I don't think OAM will decay from one frame to the next.
Quote:
Maybe I should make that conditional too, to avoid it using a partially filled OAM buffer?
Using a partially filled OAM buffer is pretty bad, but even if it's completely filled, if the rest of the updates aren't carried out along with the OAM DMA, the sprites might look out of sync with the rest of the scene. Objects that switch between background and sprites (such as blocks that can be broken or picked up) might look duplicated or be missing for a frame, scrolling might look jittery, and so on.
Lag frames can cause pretty bad side effects if you aren't fully prepared for them. For example, if you have a status bar along with a scrolling background, you should double buffer the scroll values (along with any other raster effects you might have) and only swap the buffers in the NMI handler. Since raster effects have to be done even during lag frames, there's no such thing as a typical "ready flag" for them, if the NMI interrupts raster effect changes, you're screwed. This is why you should double buffer them, so that there's always a set of consistent raster effects the NMI handler can use. The "ready flag" in this case means that the NMI handler can switch the sets. If you don't have raster effects, you can simply not change the scroll (which means not using $2006 either) during lag frames and the scroll from last time will be used again.
tokumaru wrote:
A lag frame is when the main loop takes too long and is interrupted by the NMI. The problem with reading the controllers the NMI in this case is that the part of the main loop that ran before the NMI will see one controller state, while the part that runs after the NMI will see another state, and this could cause inconsistencies in the game logic (a button might appear both pressed and not pressed in the same logical frame depending on when you check it).
True.
But on the other hand, if a lag frame is long enough, not polling controllers at all during lag frames might cause a press and release during a lag frame to be missed. This is the case, for example, with the Vs. coin switches.
Perhaps this is the most robust method: NMI reads the controller, accumulates presses and releases, and writes the current state to a variable. When the next frame begins, it copies the current state, presses, and releases to its own variable, and clears the NMI's copy of presses and releases.
tokumaru wrote:
For example, in a game where the player can change characters on the fly, it makes sense to change the character's patterns, palette and OAM entries all at the same time, otherwise you may end up with miscolored or glitchy-looking sprites for a brief moment.
That and if you're using CHR RAM, ensure that the "changing" cel is loaded first.
tokumaru wrote:
OAM starts decaying if the PPU is off for too long. I don't know how long is "too long", but if you aren't using forced blanking, I don't think OAM will decay from one frame to the next.
Correct: it won't decay so long as it's refreshed at least every 20-some scanlines. In particular, it won't decay between last line of one frame and the first of the next.
tepples wrote:
But on the other hand, if a lag frame is long enough, not polling controllers at all during lag frames might cause a press and release during a lag frame to be missed. This is the case, for example, with the Vs. coin switches.
Can humans press a button this fast though? If the coin switch signals are this fast, then you should probably have special code to handle that specific aspect and set a flag that the main loop can check (and clear) when it's most convenient.
Quote:
Correct: it won't decay so long as it's refreshed at least every 20-some scanlines. In particular, it won't decay between last line of one frame and the first of the next.
If I'm not mistaken, this is also the reason why OAM DMA must happen during the first 20-some scanlines of vblank in PAL consoles: OAM refresh starts after that many scanlines, even though vblank continues for another 50 scanlines or so.
Pokun wrote:
Also what is a "lagframe"?
Maybe that was the wrong term to use, but a frame that takes too long and gets displayed twice. Slowdown. 2 NMIs but only one game update.
Edit: oh, sorry. Didn't see the second page, this has already been answered.
tokumaru wrote:
tepples wrote:
if a lag frame is long enough, not polling controllers at all during lag frames might cause a press and release during a lag frame to be missed.
Can humans press a button this fast though?
I think I can do 14 presses per second without turbo controller assistance. That's about 2 frames on, 2 frames off. Mix in some Micronics and missed presses become the rule.
tokumaru wrote:
Can humans press a button this fast though? If the coin switch signals are this fast, then you should probably have special code to handle that specific aspect and set a flag that the main loop can check (and clear) when it's most convenient.
Getting off-topic, but I believe it's time to introduce tokumaru to
Takahashi Meijin (
video). (Random trivia: Hudson's Adventure Island is actually called Takahashi Meijin no Bouken Jima -- yes, Master Higgins is supposed to be Takahashi Meijin)
Whether or not a game needs to be able to handle this kind of "input rate" depends on the game. Choose poorly, however, and you may find angry retro gamers forever loathing you -- nobody likes non-responsive controls.
Oh this was all so easy before I was aware of all the possible problems. But thanks for all the tips!
OAM only decays (on NTSC PPU) when rendering is off? In other words when both BG and sprites are turned off in $2001? Then I don't see that as much of a problem as I'm mainly turning it off when changing screens and so on.
tokumaru wrote:
Pokun wrote:
The graphics updates each have their own flag (except OAM-DMA) that has to be set before they run (as suggested the article
The frame and NMIs) and the flag are only set in the main loop when there are pending updates in the corresponding buffer.
I don't know if individual flags for each buffer is the way to go, since the different updates might be correlated in some way that only makes sense if they're all performed at the same time. For example, in a game where the player can change characters on the fly, it makes sense to change the character's patterns, palette and OAM entries all at the same time, otherwise you may end up with miscolored or glitchy-looking sprites for a brief moment. The individual updates should not depend on each other if it there's a chance that only some of them will be carried out.
I see, maybe sprite and sprite palettes should share one flag and the BG buffer and the BG palettes should share another one. That way sprites and nametables will always be updated the same time as their corresponding palettes. Either that or one flag for all graphic updates so that the whole screen is updated consistently when all buffers are filled.
I haven't done any scrolling yet. My main project is a single screen game anyway, so the only scrolling I might do is for certain effects.
I might start a new thread about my particular problems to avoid derailing the thread though.
Pokun wrote:
OAM only decays (on NTSC PPU) when rendering is off? In other words when both BG and sprites are turned off in $2001? Then I don't see that as much of a problem as I'm mainly turning it off when changing screens and so on.
I believe it decays on PAL as well. It was my understanding that PAL just has a couple of forced refreshes during the extended vblank so that it doesn't end up decaying before the end of vblank. Outside of vblank it should still decay if rendering is disabled, AFAIK. (Someone with a PAL system might comment on this, though.)
i.e. the practise I understand is that after rendering is off for any length of time longer than an NTSC vblank, OAM must be fully reinitialized. OAM should only be uploaded during vblank, or on PAL specifically during the beginning part of vblank.
Oh I see, vblank time is longer than 20 scanlines on PAL so they had to refresh it after 20 scanlines, so that it doesn't decay during vblank like it does in a forced blanking.
So if you always makes sure an OAM-DMA is run before you turn on rendering, you will never have this problem.
rainwarrior wrote:
Pokun wrote:
OAM only decays (on NTSC PPU) when rendering is off? In other words when both BG and sprites are turned off in $2001? Then I don't see that as much of a problem as I'm mainly turning it off when changing screens and so on.
I believe it decays on PAL as well. It was my understanding that PAL just has a couple of forced refreshes during the extended vblank so that it doesn't end up decaying before the end of vblank. Outside of vblank it should still decay if rendering is disabled, AFAIK. (Someone with a PAL system might comment on this, though.)
OAM does actually seem to maintain its state on PAL NES even when rendering is off. (Presumably this means that if you do OAM DMA when rendering is off, you should do it within a sufficient time after NMI.) This is all hinging solely on my (possibly flawed) tests, so I really hope somebody else with PAL NES eventually tries to duplicate these results.
Reference:
viewtopic.php?f=9&t=11041&p=127180
Pokun wrote:
So if you always makes sure an OAM-DMA is run before you turn on rendering, you will never have this problem.
You'd think that a fresh OAM DMA would solve all issues, but there's one problem that not even this can fix: if you disable rendering while sprites are being evaluated, the PPU goes batshit crazy when rendering is enabled again and corrupts a few OAM bytes. For this reason, avoid turning rendering off mid-screen, but if you really need to, avoid doing it in scanlines with many sprites, and do it as close to the end of the scanline as possible.
OK so OAM decay on PAL is still unclear.
Normally I turn off rendering using a subroutine like this:
Code:
ppu_off:
lda #$00
sta shadow_2001 ;turn off rendering in buffer
lda #$01
sta ppu_flag ;indicate that there are PPU setting updates
jsr nmi_wait ;wait for an NMI to update from buffer
rts
Then the NMI handler copies the buffer to the real $2001.
Buffering PPU setting updates to $2000 and $2001 is also as suggested from "The frame and NMI". This should make sure rendering is always turned off in vblank if I'm not mistaken.
Pokun wrote:
This should make sure rendering is always turned off in vblank if I'm not mistaken.
Yes, but does this have anything to do with OAM decay?
Not OAM decay but you just said the PPU goes batshit and corrupts parts of OAM if rendering is turned off while sprites are being evaluated. I assumed sprite evaluation isn't being done during vblank. In that case turning off rendering in vblank is the safe way to turn off rendering I thought.
"The frames and NMI" also suggest doing this, although it doesn't explain exactly why (it says something about that the screen jumps if rendering is turned on outside of vblank).
Pokun wrote:
you just said the PPU goes batshit and corrupts parts of OAM if rendering is turned off while sprites are being evaluated.
Ah, OK. This is a much bigger problem if rendering is being consistently turned off at a bad moment every frame, but one frame after transitions and such would hardly be noticeable. But you are right, delaying $2000/$2001 writes until vblank is the best practice. Not only you avoid any sprite corruption, but you also avoid displaying partial frames that may make the screen appear to "jump".