Thanks both of you for your tips.
BG updates and palette updates could be run by one system. You may not want to update the entire palette each time, but only 1 or 3 bytes. Which makes hardcoding $3f00 in not great.
Anyway, something like...(fill buffer with)
# of bytes
# of bytes
Etc, until # of bytes is zero, exit
And, I moved my frame counter outside the NMI, because I was timing enemy movements through it, but when I hit "pause" it would continue to tick upward, causing odd enemy movements if pause was repeatedly hit.
My BG buffer works kind of like that. I made the palette buffer simple since there are only 32 palette entries, but if vblank time becomes scarce I'll definitely design a more flexible palette update routine.
I only use the frame counter for displaying the number of frames at the moment so I thought it would be best if it was running at 60 Hz. I guess you could have a separate counter that counts logical frames in your game state handler.
The draw flag prevents OAM and VRAM updates to happen during lag frames when the OAM and VRAM buffers aren't completly filled yet
But you're setting the flag at the beginning of the frame, when no processing has been done yet? I don't get it.
What's the difference between setting it at the end an infinite loop or at the beginning of it? I actually initially had it at the end, but then moved it up so that it's a bit closer to the NMI wait, and It works as expected. The only potential problem I see is that no logic has processed the very first loop after reset, so that frame could have incorrect data written to the PPU. But I initialize all buffers in my init code so that's not a problem either.
2- Don't bit $2002 unconditionally in the NMI, because it might be interrupting the $2006 writes of a background update
Ok I moved that instruction within the draw and render flag conditions so it's not executed during lag frames or when rendering is off.
3- Writing $00 to $2006 twice at the end of the NMI will force the use of NT 0, overriding the NT chosen through $2000
This is new to me. Currently I have no scrolling at all so I'm always using nametable 0. But I learned somewher that writing 0 to $2006 twice is necessary before setting the scroll coordinates or else previous PPU writes will affect scroll. The wiki mentions something about it producing "interesting raster effects" if writing to this during screen refresh
, is this what you are refering to?
4- If you have raster effects, double buffer the scroll, if you don't, don't update the scroll during lag frames;
5- Updating $2000 and $2001 during lag frames could use inconsistent values if you don't double buffer them;
OK since I have no raster effects I made both of these conditional based on the render flag (makes them not update when rendering is off) and the draw flag (makes them not update during lag frames). Both render_flag and draw_flag now jumps to graphic_end instead of draw_end to achieve this. But I still have the problem with the render flag breaking my screen transition drawing routines:
Also in another thread it was recommended to have a render flag that prevents graphic updates when rendering is off. If I understand it correctly it should skip all graphic updates including PPU settings and scroll updates. I tried doing that (by using a render_flag that if set jumps to the "graphic_end" label), but that ended up breaking my between screens drawing routines that draws the entire screen between screen transisions.
Now that's weird, because the purpose of leaving the PPU alone when rendering is off is precisely to not interfere with the transition code that's drawing stuff to the PPU. Maybe you were delaying the $2001 write that was supposed to disable rendering but because of the flag the write ended up never happening, meaning the transition happened with the screen still on? In my own engine, the only register I update regardless of whether rendering is on or off is $2001, so that the PPU can be turned on and off according to the "rendering" flag. AFAIK, $2001 writes don't have any side effects that could interfere with VRAM updates.
I turn on and off using two subroutines that should make sure that it's done correctly:
;Turns on rendering.
sta render_flag ;set rendering flag
sta shadow_2001 ;turn on rendering in buffer
jsr nmi_wait ;wait for an NMI to enable rendering
;Turns off rendering.
sta shadow_2001 ;turn off rendering in buffer
jsr nmi_wait ;wait for an NMI to disable rendering
sta render_flag ;clear rendering flag
Yet it doesn't work as expected. The screen is drawn only partly during transitions...