Rogue pixels

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Rogue pixels
by on (#215547)
Hi all :)

I've been banging my head against this problem for a few days with no luck, so I'm hoping one of you guys could help me out. I'm a newbie NES programmer and I'm using ASM6 and 6502 assembly.

So far, I've done the Nerdy Nights tutorials and am trying my hand at my own game. I've got everything pretty much working and I even managed to integrate the GGSound engine without too much trouble. I added the examples from the https://wiki.nesdev.com/w/index.php/The_frame_and_NMIs page but now I have rogue pixels at the top left of my screen and I can't figure out where they're coming from.

I've moved the scroll values around and tried turning off the background, palette, sprites, etc. Turning off the palette blanks the screen so it's hard to tell if it's still there.

Attachment:
File comment: screenshot
rogue-41.png
rogue-41.png [ 3.25 KiB | Viewed 2515 times ]


You can see it as red, white, and grey pixels at the top left.

Here's the basics of my code. Let me know if you need to see more. It's really just a framework with some custom and placeholder sprites.
Re: Rogue pixels
by on (#215549)
Does it still happen when you render the background, but not sprites? My first guess is "sprites.spr" is not long enough, or has errors.

My second guess is something similar with rogue.nam.

The longshot:

Behold, the way to draw all the colors on the screen at once: https://wiki.nesdev.com/w/index.php/Full_palette_demo
Quote:
Normally, the PPU displays the palette byte from $3F00 as the background color. When rendering is disabled and the PPU address is in the $3F00-$3FFF range, the PPU displays the palette byte at that address.

But the only way I can see that happening in the code you posted is if the sound engine wasn't set up to use unique RAM.

Another potential issue is a negative scroll value for Y, but similarly I can't see anything that would cause that except RAM collisions here.
Re: Rogue pixels
by on (#215550)
If you would post an NES ROM as well, it would be very easy to tell what is causing any visual element that appears with a good debugging emulator (Mesen, FCEUX, Nintendulator, etc.)

The assembly files are helpful as well for diagnosing a problem, but it's much easier to just check what the ROM is actually doing than either try to reason about what a bunch of code does.
Re: Rogue pixels
by on (#215551)
Top left is usually sprites that haven't been properly pushed off the screen (by setting a y value >= $f0).

If a sprite entry is left as 0,0,0,0 it will draw the #0 tile at position 0,0 (top left) using palette #0.

I'm guessing you have video settings at the default with top and bottom 8 pixels hidden.

Sprites show up 1 pixel lower on the screen, which is why you would see the bottom 8x1 slice of the sprite only. (top 8 pixels hidden, sprites shifted down 1 = 7 hidden and 1 visible).
Re: Rogue pixels
by on (#215552)
Also, as a developer, it's a good idea to configure your emulators to display all 240 scanlines (some emulators hide the top and bottom 8 scanlines by default, because some games have glitches in those areas and real TVs tend to hide some of those scanlines too), so you can see the whole picture your code is producing and detect problems that maybe you wouldn't notice otherwise.
Re: Rogue pixels
by on (#215555)
dougeff wrote:
Top left is usually sprites that haven't been properly pushed off the screen (by setting a y value >= $f0).

If a sprite entry is left as 0,0,0,0 it will draw the #0 tile at position 0,0 (top left) using palette #0.


There's almost a 100% chance this is it. There is actually not a lot of newbie-friendly documentation out there about how to "disable" sprites, even though it should be obvious once you think about it. The NES hardware always renders 64 sprites, wether you want it or not. You can use invisible tiles, etc. for sprites you don't want the player to see, but by far the best and easiest solution is to simply push every unused sprite out of the visible area by setting the Y coordinate to something higher than 240 pixels (where you don't have to worry about the 8 sprites on a scanline limit either).

I'm assuming you're copying a full object table from a "sprite buffer" every NMI, so a good cause of this issue could be that you simply have a bunch of zeroes in your unused part of the RAM buffer, which places sprites in the top left corner like dougeff describes. A lazy way to initialize your sprite buffer if just to write $ff to every byte, but you also want to clear out unused sprites every single frame, so you don't leave old garbage ones hanging around.
Re: Rogue pixels
by on (#215556)
Sumez wrote:
by far the best and easiest solution is to simply push every unused sprite out of the visible area by setting the Y coordinate to something higher than 240 pixels (where you don't have to worry about the 8 sprites on a scanline limit either).

Actually using 239 ($ef) or 240 ($f0) works too. (239 works because sprites are one pixel lower than the coordinate which is used in OAM).
Re: Rogue pixels
by on (#215576)
You guys were totally right. You guys are awesome. Cheers! :beer:

I had originally zero filled my sprite table thinking that was the way to go. I went back and replaced everything but the onscreen sprites with $EF and that fixed it. And now I realize why just turning off my sprite drawing routine was also causing the error since the PPU memory would still be zero when I turned sprites on.

I've included the fixed rom file and source if anyone wants to check it out. :) Deconstructing source and rom has really helped me fill in the gaps between the tutorials and actually making a game so I'm hoping someone finds it useful.

You've also cleared up why setting my initial yscroll value to #$08 was the only way to get the screen to show properly.

I've been using FCEUX as an emulator. Is there any way to see the PPU memory values?

Next up is actually figuring out how to store, unpack, and display levels. :|
Re: Rogue pixels
by on (#215578)
FCEUX has an OAM (sprite memory) page in the hex editor, but it's not in the last release version (have to use a development build).

You can also use LUA scripts to help visualize where the sprites are (see included "sprites.lua", though tokumaru also wrote a really nice one).

However, Mesen and Nintendulator have dedicated OAM viewer tools which do a much better job of this, with good visual display of information.


FWIW, a lot of commercial era NES games put a value of "-8" into the Y scroll for more convenient alignment with the commonly visible picture. You could do this either with 232 (240-8) or 248 (256-8), though the latter causes garbage to appear in the extra row. You can see this in TMNT, for example, if you tell your emulator to show you the whole picture instead of cropping lines from the top and bottom.
Re: Rogue pixels
by on (#215579)
rainwarrior wrote:
FCEUX has an OAM (sprite memory) page in the hex editor, but it's not in the last release version (have to use a development build).

You can also use LUA scripts to help visualize where the sprites are (see included "sprites.lua", though tokumaru also wrote a really nice one).

However, Mesen and Nintendulator have dedicated OAM viewer tools which do a much better job of this, with good visual display of information.


Great suggestions. I've downloaded both of them and the tools work great. One question though: the palette colors look way different from FCEUX. I know simulating CRT rendering isn't exact, but are there different approaches to approximating it?


rainwarrior wrote:
FWIW, a lot of commercial era NES games put a value of "-8" into the Y scroll for more convenient alignment with the commonly visible picture. You could do this either with 232 (240-8) or 248 (256-8), though the latter causes garbage to appear in the extra row. You can see this in TMNT, for example, if you tell your emulator to show you the whole picture instead of cropping lines from the top and bottom.


I'm still trying to wrap my head around this. Do you mean treating y-scroll value as a signed int? Or wrapping around?


BTW: I loved Lizard :)
Re: Rogue pixels
by on (#215580)
sailense wrote:
I'm still trying to wrap my head around this. Do you mean treating y-scroll value as a signed int? Or wrapping around?

Sort of both. Yes, wrapping around, but in two's complement representation, a signed byte -8 is the same as an unsigned byte 256-8 (248).

The NES picture also wraps to the next screen at Y=240, though, so it has two wrapping points, which is weird. (It's supposed to skip over 240-255, where the attribute data is stored, but if you start inside that range it will render a few lines of garbage data from it.)
Re: Rogue pixels
by on (#215586)
Yeah, a Y scroll of 248 or 232 will result in the same picture from scanline 8 onwards, but scanlines 0-7 will be different: 248 will show garbage (attribute table data interpreted as name table data), 232 will show the bottom row of the name table.
Re: Rogue pixels
by on (#215588)
I think I get :) This thread helped alot too viewtopic.php?f=10&t=17014

Right now I'm resetting scoll values in all my subroutines where I write to $2006. Is that the best way to go? And when is the best time to read from controller? Every NMI or during the main loop?
Re: Rogue pixels
by on (#215589)
sailense wrote:
Right now I'm resetting scoll values in all my subroutines where I write to $2006. Is that the best way to go? And when is the best time to read from controller? Every NMI or during the main loop?

I can think of theoretical situations where someone might want to read and use input in the NMI, but in general there's no reason to read the controller more often than you do something with those read values, so probably I'd suggest main loop.
Re: Rogue pixels
by on (#215590)
rainwarrior wrote:
sailense wrote:
Right now I'm resetting scoll values in all my subroutines where I write to $2006. Is that the best way to go? And when is the best time to read from controller? Every NMI or during the main loop?

I can think of theoretical situations where someone might want to read and use input in the NMI, but in general there's no reason to read the controller more often than you do something with those read values, so probably I'd suggest main loop.


Perfect. Thanks so much. :)
Re: Rogue pixels
by on (#215598)
sailense wrote:
Right now I'm resetting scoll values in all my subroutines where I write to $2006. Is that the best way to go?

If you're not doing any raster effects, you only need to reset the scroll once per frame, before rendering starts. Normally that'd be at the end of your NMI handler, after all PPU operations have already been done.

Quote:
And when is the best time to read from controller? Every NMI or during the main loop?

Doing it in the NMI can actually cause bugs during lag frames, because the same logic frame may end up using 2 different states of the same button if an NMI happens between two checks. Better do it in the main loop, once for each logic frame.
Re: Rogue pixels
by on (#215604)
tokumaru wrote:
[Reading the controller] in the NMI can actually cause bugs during lag frames, because the same logic frame may end up using 2 different states of the same button if an NMI happens between two checks. Better do it in the main loop, once for each logic frame.

That's a good idea in many cases. The other way to handle it, especially if you're playing DPCM samples, is to have the main loop request that the NMI handler perform the reread immediately after uploading a display list to OAM, as Rahsennor discovered.
Re: Rogue pixels
by on (#215605)
Oh yeah, I forgot about that. Yes, if you read the controllers in the NMI only when a logic frame isn't interrupted, you can avoid that button inconsistency issue I mentioned before and still make use of this technique to avoid DPCM input glitches.
Re: Rogue pixels
by on (#215635)
tepples wrote:
tokumaru wrote:
[Reading the controller] in the NMI can actually cause bugs during lag frames, because the same logic frame may end up using 2 different states of the same button if an NMI happens between two checks. Better do it in the main loop, once for each logic frame.

That's a good idea in many cases. The other way to handle it, especially if you're playing DPCM samples, is to have the main loop request that the NMI handler perform the reread immediately after uploading a display list to OAM, as Rahsennor discovered.


That's a great link. The ring counter technique is awesome.

I'm purposely avoiding DPCM samples in the music specifically so I don't have to worry about it.