My sprites are flickering on real NES, not in any of 4 emus.
Moderator: Moderators
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
My sprites are flickering on real NES, not in any of 4 emus.
I had a nasty surprise this evening when I tested some of my experiments on a real NES. I thought I had tested this particular experiment on a real NES before, but apparently not. I'm getting nasty sprite flicker. It sucks cause this doesn't happen on any of the 4 emulators I've been testing with.
The only thing I can think is maybe I've written some highly inefficient, cycle-heavy code and it is going past the length of one vblank (but shouldn't an accurate emulator catch this?). In fact, I did add one (harmless) instruction in my code and the flicker got worse...that would lend credence to that possibility would it not?
The only thing I can think is maybe I've written some highly inefficient, cycle-heavy code and it is going past the length of one vblank (but shouldn't an accurate emulator catch this?). In fact, I did add one (harmless) instruction in my code and the flicker got worse...that would lend credence to that possibility would it not?
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
I first disable graphics, then wait two vblanks, then clear ram in pages $000-$700.
My program is an experiment with displaying meta-sprites. In my current test program, I am displaying two meta sprites. If each meta sprite is composed of 8 sprites (4 wide x2 high), there is no flicker. If each meta sprite is composed of more than this, the sprites begin to flicker. The max size I've tried is two meta sprites which are 4x4 sprites. From what I understood from documentation, this would bring the max sprites per scanline to 8 (if the two meta sprites are positioned next to each other), which is the max allowed for the NES. I assumed when I read that that there would be no flicker...is that incorrect?
*edit* Upon modifying my test programs, when I displayed two 4x4 meta sprites, the flicker did begin to show up in both Nestopia and Nintendulator. There seems to be a small discrepancy between these emulators and the real hardware for when flicker begins occurring (based on no. of sprites)
*edit* I found tepples' post
http://www.nesdev.com/bbs/viewtopic.php ... d1ee7456b4
I am not yet certain if I'm seeing the same problem, though.
My program is an experiment with displaying meta-sprites. In my current test program, I am displaying two meta sprites. If each meta sprite is composed of 8 sprites (4 wide x2 high), there is no flicker. If each meta sprite is composed of more than this, the sprites begin to flicker. The max size I've tried is two meta sprites which are 4x4 sprites. From what I understood from documentation, this would bring the max sprites per scanline to 8 (if the two meta sprites are positioned next to each other), which is the max allowed for the NES. I assumed when I read that that there would be no flicker...is that incorrect?
*edit* Upon modifying my test programs, when I displayed two 4x4 meta sprites, the flicker did begin to show up in both Nestopia and Nintendulator. There seems to be a small discrepancy between these emulators and the real hardware for when flicker begins occurring (based on no. of sprites)
*edit* I found tepples' post
http://www.nesdev.com/bbs/viewtopic.php ... d1ee7456b4
I am not yet certain if I'm seeing the same problem, though.
I don't think any NES emulator accurately emulates what can happen when writing to the PPU in an active scanline. An easy 'fix' for your program is: vblank NMI -> disable PPU -> upload data to PPU -> enable PPU.
Also, be sure to do a sprite DMA every vblank, as sprite attribute RAM contents may deteriorate if untouched for a while (not sure of this myself). This effect is also not emulated.
Also, be sure to do a sprite DMA every vblank, as sprite attribute RAM contents may deteriorate if untouched for a while (not sure of this myself). This effect is also not emulated.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
I noticed if I draw a large enough meta sprite (with 28 sprites in nintendulator), my background starts to flicker and scroll vertically (with your suggestion of turning off rendering-> upload to PPU -> turning on rendering). This looks like my rendering is taking longer than vblank. Maybe I should test in PAL mode to confirm this. *edit* sure enough, no problems in pal mode in nintendulator.
-
Celius
- Posts: 2159
- Joined: Sun Jun 05, 2005 2:04 pm
- Location: Minneapolis, Minnesota, United States
- Contact:
If you haven't implemented a "flicker" routine and all sprites hold the same places in the OAM page every frame, the sprites should not flicker at all. Have you ever played SMB1 and watched one of those pulley-platforms disappear when on the same scanline as another? That's what it should look like. One and only one should completely disappear.
My guess is it's something kind of unnatural, like a PPU glitch. Always be very aware of how long your Vblank code takes. You should count the cycles. If it works in PAL mode like you said, it's very possible this is what's happening.
My guess is it's something kind of unnatural, like a PPU glitch. Always be very aware of how long your Vblank code takes. You should count the cycles. If it works in PAL mode like you said, it's very possible this is what's happening.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
I've read on this forum that vblank is over 2000 CPU cycles in length, yet from testing my own programs in nintendulator, I seem to get flicker with the following code: (I have already loaded a background, and in vblank all I do is disable rendering and re-enable it)
I don't know how long it takes to enable/disable rendering, but I put some loops in there which, if I've done my arithmetic right, take 1402 cycles. Where are the remaining 600+ cycles going?
Code: Select all
vblank:
pha ;1
txa ;1
pha ;1
tya ;1
pha ;1
php ;1
ldx #0
stx $2001 ; disable rendering
ldx #$ff ;2
- dex ;1
bne - ;2
ldx #$d3 ;2
;ldx #$d4 ;2 ;uncomment this line, you will get flicker
- dex ;1
bne - ;2
lda #%00011110
sta $2001
plp ;1
pla ;1
tay ;1
pla ;1
tax ;1
pla ;1
irq:
rti
And all instructions take at least two cycles. Looks like you're totaling the number of BYTES each instruction is encoded in, rather than the amount of work it's doing. Here's a more realistic cycle timing:
I calculate 2293 cycles from NMI to the final STA $2001. Uncommenting that line adds 7 cycles.
Code: Select all
vblank:
; 14 for previous instruction + vectoring
pha ; 3
txa ; 2
pha ; 3
tya ; 2
pha ; 3
php ; 3
ldx #0 ; 2
stx $2001 ; 4 disable rendering
ldx #$ff ; 2
- dex ; 2
bne - ; 3
; -1
ldx #$d3 ; 2
;ldx #$d4 ; 2 uncomment this line, you will get flicker
- dex ; 2
bne - ; 3
; -1
lda #%00011110; 2
sta $2001 ; 4
plp ; 4
pla ; 4
tay ; 2
pla ; 4
tax ; 2
pla ; 4
rti ; 6- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Thanks to you guys, I've had a leap of understanding about programming for the NES this evening. So, vblank is only around 2000 cycles long, that must mean there's quite a lot more cycles available while the PPU is rendering. Thus, I would imagine game engines are (often, I realize there is more than one way to do this) set up roughly as follows:
Code: Select all
loop:
;wait for frame to begin (perhaps wait for our vblank to end with a simple flag)
;none of this code will update graphics or sound, just make various game related calculations (which may be quite CPU intensive, thus this is the most appropriate place for them)
jsr updateAllGameObjectsAndAI
jmp loop
vblank:
;all of these update graphics and sound as calculated by the game engine during the previous frame
jsr updateSprites ;sprite DMA
jsr updateBackground ;scrolling, nametable updates
jsr updateSound ;sound and music engine
;set a flag so the game engine knows it can do whatever it wants til the next vblank is called
rti-
Celius
- Posts: 2159
- Joined: Sun Jun 05, 2005 2:04 pm
- Location: Minneapolis, Minnesota, United States
- Contact:
I have never seen anyone poll for $2002 that way before! To me, that's not even a newbie way of doing it; it's more complex than the standard way to do it:ZomCoder wrote:Code: Select all
- lda $2002 clc rol a bcs -
Code: Select all
-
lda $2002
bmi -
I'm pretty sure you're right though about the game loop thing, just it's executed differently (probably with no polling). You never want the game loop to run at more than 60/50 Hz (either NTSC or PAL), and you never want the NMI to update data when its not ready. So that basically means you should have flags and stuff that indicate whether or not the data is ready. Though whether or not this approach is worth the complexity is debatable.