This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

How to hide vertical scrolling updates with no status bar?

How to hide vertical scrolling updates with no status bar?
by on (#107964)
I've (had) an 8 way scroller for my new game, which currently takes advantage of NTSC overscan, like Super Bat Puncher, to hide scrolling glitches. As you know though it is not perfect, some TVs still show a tiny bit of the nametable updates with this approach. Personally, I will be happy with this approach if I can't find something better, but I am going to investigate some possibilities.

One possibility I was thinking of was Sprite 0 hit, and turning graphics on and off---however I don't think this is even possible. Graphics must be on for Sprite 0 hit to work at all.

Another possibility is to ensure that my vblank code always does the exact same amount of work and do cycle counting to hide graphics at the top, and then use sprite 0 hit at the bottom and turn off graphics once detected.

And finally, the last possibility I can think of is to have bankswitchable CHR, and have one bank loaded with nothing but blank tiles, and use sprite 0 hit and bankswitch to the "blank graphics" chr bank for the scanlines at the top and bottom that I want to hide.

I was just curious what your thoughts were on these possibilities. The first one I'm probably going to try is the cycle counting and Sprite 0 hit hybrid.

Note I am not interested in using a status bar, only hiding scrolling glitches. *edit* Note also, I do not plan on using a scanline counter, this would be prohibitively expensive for building homebrew cartridges with new parts.

*edit* Here's a video of what I ended up implementing:
Cycle-timed scroll update hiding
Re: How to hide vertical scrolling updates with no status ba
by on (#107966)
Use Horizontal mirroring. Then, hide sprites/tiles in the left 8 pixels. You'll still get some attribute glitches, but that's not too bad.
Re: How to hide vertical scrolling updates with no status ba
by on (#107967)
An extra 2KB of RAM is cheap to add to the PCB. Personally, I would add the extra RAM if this was one of my projects.
Re: How to hide vertical scrolling updates with no status ba
by on (#107968)
GradualGames wrote:
One possibility I was thinking of was Sprite 0 hit, and turning graphics on and off---however I don't think this is even possible. Graphics must be on for Sprite 0 hit to work at all.

Yeah, no rendering = no sprite hit. Also, if you have rendering disabled at the start of the frame you get the alternate dot crawl pattern, which can make scrolling look weird IMO.

Quote:
Another possibility is to ensure that my vblank code always does the exact same amount of work and do cycle counting to hide graphics at the top, and then use sprite 0 hit at the bottom and turn off graphics once detected.

Constant timed VBlank code is very tedious to program. I've done it before, but I really don't recommend it. Sprite 0 hits can be tough to pull off properly when you scroll vertically as well as horizontally, because it gets harder to guarantee the presence of solid background pixels (unless you update the position of a constant solid tile under the sprite, like in Big Nose Freaks Out).

Quote:
And finally, the last possibility I can think of is to have bankswitchable CHR, and have one bank loaded with nothing but blank tiles, and use sprite 0 hit and bankswitch to the "blank graphics" chr bank for the scanlines at the top and bottom that I want to hide.

This is very clean, because it doesn't mess with the normal operation of the PPU. The CHR can't be totally blank though, because sprite 0 would have nothing to collide with, so you'd probably need that "constant solid tile" thing I mentioned before.

Quote:
I was just curious what your thoughts were on these possibilities. The first one I'm probably going to try is the cycle counting and Sprite 0 hit hybrid.

Good luck with the cycle counting, I'm sure you'll regret that choice! =)

I found a different solution: to completely hide scrolling glitches, I needed to blank 16 scanlines. Due to the difficulty of dividing that amount between the top and the bottom of the screen, I decided to hide them all at the top (looks pretty good on my TV, at least). I put 9 blank high priority 8x16 sprites at the very top of the screen to hide all other sprites that might go up there. As a bonus, those 9 sprites will trigger the sprite overflow flag as soon as rendering starts, which I use to detect the start of the frame (meaning my VBlank handler doesn't need to be constant-timed). Then I wait a fixed amount of time (16 scanlines - during this time you can even do some constant-timed tasks, like reading the controllers, initializing buffers and such) before enabling background rendering (which I disabled during VBlank).

This method has that advantage of not messing with the normal PPU operation. Since sprites are enabled, the PPU works normally. If you are not using 8x16 sprites and you really want to mask 8 scanlines at the top and 8 at the bottom, you can still use my trick at the top and a sprite 0 (with a constant solid background tile) at the bottom.

You might think that 9 sprites is a big waste, but it's still considerably less than what Alfred Chicken and Felix the Cat use to hide their scrolling glitches: The use horizontal mirroring, so that the glitches are at the sides of the screen, and then they set the PPU to mask off the left side and use a big column of sprites to hide the right side. This not only wastes more sprites but also effectively reduces the sprites-per-scanline count to 7!
Re: How to hide vertical scrolling updates with no status ba
by on (#107969)
Kasumi wrote:
Use Horizontal mirroring. Then, hide sprites/tiles in the left 8 pixels. You'll still get some attribute glitches, but that's not too bad.

I find those attribute glitches so annoying, I could never have something like that in my games!

3gengames wrote:
An extra 2KB of RAM is cheap to add to the PCB. Personally, I would add the extra RAM if this was one of my projects.

If GradualGames is anything like me, he wants to keep the hardware as simple/cheap as possible. There are ways to completely hide the glitches purely with software, you just have to make some minor sacrifices.
Re: How to hide vertical scrolling updates with no status ba
by on (#107973)
tokumaru wrote:
Good luck with the cycle counting, I'm sure you'll regret that choice! =)


I just got done trying it actually. I duplicated all my vblank routines, and made versions of them called whatever_nop. Then I found all sta's and wrote to a location in ram or zp that is not used. Then, whenever I'm not uploading a column or row, I call the "nop" version. I think I still have it off by a few cycles, but I've got a fairly stable 16 pixel wide blackout at the top of the screen going. Not sure if I'll stick with this approach, the trick you mention below sounds quite attractive.

tokumaru wrote:
I found a different solution: to completely hide scrolling glitches, I needed to blank 16 scanlines. Due to the difficulty of dividing that amount between the top and the bottom of the screen, I decided to hide them all at the top (looks pretty good on my TV, at least). I put 9 blank high priority 8x16 sprites at the very top of the screen to hide all other sprites that might go up there. As a bonus, those 9 sprites will trigger the sprite overflow flag as soon as rendering starts, which I use to detect the start of the frame (meaning my VBlank handler doesn't need to be constant-timed). Then I wait a fixed amount of time (16 scanlines - during this time you can even do some constant-timed tasks, like reading the controllers, initializing buffers and such) before enabling background rendering (which I disabled during VBlank).

This method has that advantage of not messing with the normal PPU operation. Since sprites are enabled, the PPU works normally. If you are not using 8x16 sprites and you really want to mask 8 scanlines at the top and 8 at the bottom, you can still use my trick at the top and a sprite 0 (with a constant solid background tile) at the bottom.

You might think that 9 sprites is a big waste, but it's still considerably less than what Alfred Chicken and Felix the Cat use to hide their scrolling glitches: The use horizontal mirroring, so that the glitches are at the sides of the screen, and then they set the PPU to mask off the left side and use a big column of sprites to hide the right side. This not only wastes more sprites but also effectively reduces the sprites-per-scanline count to 7!


This sounds really neat, I like that it allows the vblank routine to not be an ugly mess! :) I'm not sure I do like losing 9 sprites to it, though. This is an interesting trade-off.

OK---so one really weird thing that came up while experimenting with cycle counting this evening---my code does not appear to work at all in PAL. Maybe I just need to count way more cycles or something? I'm not getting the nice black bar that I do in NTSC mode. Part of what motivated me to do this to begin with was possibly creating two variants of the new game one for NTSC and one for PAL. *edit* yup, that was it, just wasn't counting enough cycles for PAL.
Re: How to hide vertical scrolling updates with no status ba
by on (#107974)
GradualGames wrote:
my code does not appear to work at all in PAL. Maybe I just need to count way more cycles or something?

Yeah, VBlank is way longer in PAL consoles (around 70 scanlines, against 20 on NTSC), so everything you're doing is probably finishing before the frame even starts rendering.

If you're planning on making a single ROM compatible with NTSC and PAL you'll need to detect the type of the console at the beginning of the program. But if you plan on making 2 different ROMs you can just hardcode the timed loops accordingly.

About the constant timed VBlank code, I guess it's a nice exercise, but to me it got exhausting when I had to make modifications to the code, because I had to recalculate everything. I did try to make the basic structure first (with things that always happen, like sprite DMA, scroll reset, etc.), and then divided the remaining time into 2 (at one point, 3) equal-sized chunks, which I used for actual VRAM updates. This meant that each type of update routine (name table, palettes, patterns, etc.) had to fit into a fixed amount of cycles (and be padded to that amount if they used less), and they were allocated as necessary. Even by defining a number of cycles for each type of VRAM update I found myself constantly needing to adjust the timings, so I eventually got tired of that.

Now I use basically the same scheme, only I don't have to worry about using the same amount of cycles every time. The different VRAM updates have a maximum number of cycles they can use, but there's absolutely no problem in using less than that.
Re: How to hide vertical scrolling updates with no status ba
by on (#107975)
GradualGames wrote:
*edit* Note also, I do not plan on using a scanline counter, this would be prohibitively expensive for building homebrew cartridges with new parts.


Not that I don't agree with the philosophy that you're better to solve it with software with minor sacrifices. But the hardware cost difference between a discrete mapper and a non-standard scanline counter and/or cpu cycle counter can be as low as ~$1. Not worth the cost or hassle in a case like this, but it opens the doors for more features if the investment was made which wouldn't seem prohibitively expensive to me at least.
Re: How to hide vertical scrolling updates with no status ba
by on (#107978)
tokumaru wrote:
you can still use my trick at the top and a sprite 0 (with a constant solid background tile) at the bottom.


By constant solid background tile you mean a tile that never uses the background color? That may be tricky. I definitely want to maximize flexibility with background graphics. *edit* for example, most of our graphics uses black as the shared (background) color. These will scroll in and out of position where I may want sprite 0 hit to intersect with the background...which will probably break that approach.

I'm using 8x8 sprites, too, so that might cut out the possibility of using your approach (unless I want to start from scratch, and that isn't an option!)

If you do mean "tile that never uses the background color," it sounds like I can't even use the bankswitchable CHR-RAM idea with sprite 0 hit, except at the top, where I can guarantee using that "all solid" set of chr data that I can use sprite 0 hit. So it looks like if I really want to hide scrolling glitches with my desired setup, that or cycle counting are probably my only options at this point, with all nametable updates done in a 16 pixel wide bar at the top. Cycle counting may not be bad, for me, I tend not to re-write code til I begin working on a new project!

I was even thinking, if I make that bar a little wider I might even be able to fit worst-case sound updates in that bar.
Re: How to hide vertical scrolling updates with no status ba
by on (#107982)
Just checked, SRAM 2048x8 is pretty much $1. That's a small profit sacrifice/price to pass on to the consumer to eliminate a LOT of visual glitches. But still, if you want to post pictures of any ideas you implement, that's be nice to see.
Re: How to hide vertical scrolling updates with no status ba
by on (#107984)
3gengames wrote:
Just checked, SRAM 2048x8 is pretty much $1. That's a small profit sacrifice/price to pass on to the consumer to eliminate a LOT of visual glitches. But still, if you want to post pictures of any ideas you implement, that's be nice to see.

I'm looking for best practices I can do all in software. I'm trying to use the simplest and most readily available boards/mappers. On Nomolos this was UnROM, for the new game, it will either be UnROM or Bunnyboy's new UnROM like board that has bankswitchable CHR-RAM. I'll probably use the new board, so I can take advantage of one of the cleaner approaches for hiding glitches, not to mention that it might allow me to do sound updates during the time I'm waiting for Sprite 0 hit.
When I have something I'm happy with, I'll put up some unlisted youtube videos or something. It'll be a few months til I have something "nice" I want to show to the general retro gaming public though (i.e. graphics and core gameplay that is more interesting to gamers than a technical programming trick)
Re: How to hide vertical scrolling updates with no status ba
by on (#107985)
GradualGames wrote:
By constant solid background tile you mean a tile that never uses the background color? That may be tricky. I definitely want to maximize flexibility with background graphics. *edit* for example, most of our graphics uses black as the shared (background) color. These will scroll in and out of position where I may want sprite 0 hit to intersect with the background...which will probably break that approach.

Yeah, that's the problem. Have you ever played Big Nose Freaks Out? Watch the video and you'll see it keeps a solid tile at the bottom right corner at all times. The problem with this approach is that the tile itself ends up looking like a glitch, which doesn't make much sense considering that our purpose is to -hide- glitches (Big Nose probably does it for the extra VBlank time though).

Quote:
I'm using 8x8 sprites, too, so that might cut out the possibility of using your approach (unless I want to start from scratch, and that isn't an option!)

Like I said, you can still use this trick to hide 8 scanline at the top, and use a sprite hit to disable rendering at the bottom 8 scanlines early (although that needs the undesirable solid tile).

You can even blank all 16 background scanlines at the top, but sprites will only be masked for 8 of them. Make those the last 8 (so sprites can smoothly scroll from the top of the screen) and add some extra logic to your metasprite code to not output sprites with Y < 8. You really don't need 8x16 sprites for that trick.

Quote:
I was even thinking, if I make that bar a little wider I might even be able to fit worst-case sound updates in that bar.

But then you'll have to make your sound engine constant-timed too, and that sounds like a pain!
Re: How to hide vertical scrolling updates with no status ba
by on (#107986)
tokumaru wrote:
Quote:
I was even thinking, if I make that bar a little wider I might even be able to fit worst-case sound updates in that bar.

But then you'll have to make your sound engine constant-timed too, and that sounds like a pain!


I think when I wrote that last sentence, I was thinking of the following approach:

-Use bankswitchable CHR-RAM
-Upload all solid tiles in one of those banks
-Be switched to the all solid bank at end of vblank
-Run sound engine code (but be sure that worst case, all music and effects won't take a very long time)
-Wait for sprite 0 hit at 16th scanline (or maybe later, to account for worst case sound engine updates)
-Switch to whatever should be the active CHR-RAM bank for normal graphics (still lets me use 3 frames of animation for background, should be fine)

I feel like this might be better than waiting all 16 scanlines for sprite 0 hit, and then doing sound, and then all frame logic. I'm going to try this next...I suspect it will end up working a lot better for the setup I've chosen. Though, I can do this cycle counting thing as a fallback...I don't like the ugliness of it and the maintainability issues you already pointed out.
Re: How to hide vertical scrolling updates with no status ba
by on (#107989)
I just remembered another method that could work:

With vertical mirroring, we have a 512-pixel wide area for backgrounds, but only 256 are visible. Considering that metatiles are usually 16x16 pixels and that the scroll most of the time isn't aligned with them, we need a valid picture that's 17 metatiles wide (272 pixels), which leaves us with 240 pixels to play with, just 16 pixels short of a complete screen.

If you take the little extra time needed to maintain a blank 240x16-pixel area (blank except for a solid tile you'll use for the sprite hit) in the unused part of the name tables, you can use that for the top of the screen. Use the PPU feature that blanks the left edge of the screen and now you only need 2 8x8 sprites on top of each other to hide the remaining glitches. You'll obviously gonna need sprite 0 to, so that's a total of 3 sprites, much better than 9. At the end of the 16th scanline, you can reset the scroll (with full $2005/6 trickery) to the actual scroll location.

Here are some pictures to illustrate the idea:

Attachment:
clean-scroll-1.png
clean-scroll-1.png [ 4.87 KiB | Viewed 1756 times ]

This is the name table layout. Every time you need to move the visible area sideways you must also update the blank bar and the solid tile, so that it maintains its layout (30x2 blank tiles, solid tile at bottom right corner).

Attachment:
clean-scroll-2.png
clean-scroll-2.png [ 3.78 KiB | Viewed 1756 times ]

This is how the rendered image will look. Sprites and background are enabled from the start, but once the sprite hit happens you can turn sprite rendering off for the remaining scanlines of the border, so sprites can smoothly scroll from the top. Once the border ends, you can set the scroll to the gameplay area and enable sprites again.

That's a clean split, with minimal sprite sacrifice. The only downside is that you need to update some extra tiles during VBlank (something between 3 and 5 tiles I guess) to keep the blank border consistent.
Re: How to hide vertical scrolling updates with no status ba
by on (#107990)
GradualGames wrote:
-Upload all solid tiles in one of those banks

A pattern table filled with solid tiles will result in attribute glitches, because each palette uses different solid colors. Unless you decide to make one of the colors always the same, which is a huge waste IMO, since they all share color 0 already. Two unique colors per palette is a pretty serious restriction if you ask me.
Re: How to hide vertical scrolling updates with no status ba
by on (#107992)
Quote:
I found a different solution: to completely hide scrolling glitches, I needed to blank 16 scanlines. Due to the difficulty of dividing that amount between the top and the bottom of the screen, I decided to hide them all at the top (looks pretty good on my TV, at least).

I'd just add this is the only way to have 8x16 sprites cleanly getting in and off the screen on the top border. Since sprite's coordinate can't be signed (anything from $f0 to $ff is considered a disabled sprite), it is impossible to have a sprite partially in the screen, and having the sprites "pop-up" can be noticeable, especially with 8x16 sprites. This can be even more annoying than attribute clashes.

So in order to have 100% clean scrolling for both BG and sprites it is required to :
- Enable the left border clipping
- Find some way to disable graphics on the top 16 pixels by one of the ways mentioned in this thread (or top 8 if 8x8 sprites are used)

And this no matter what mirroring is used.
Re: How to hide vertical scrolling updates with no status ba
by on (#107994)
You could actually have a memory mapper high the top and bottom lines for you automatically by having it pay attention to the PPU bus like the MMC5 does. That would be kind of cool. Though I think an IRQ is the best way to go, combined with setting the graphics banks to all blank tiles. But if you can make it work with less, go for it as long as it works well. It's amazing what RARE did with discrete mappers and CHR-RAM.
Re: How to hide vertical scrolling updates with no status ba
by on (#108000)
MottZilla wrote:
Though I think an IRQ is the best way to go, combined with setting the graphics banks to all blank tiles.

Jurassic Park does this. It's a very clean solution if you have a scanline/cycle counter available. You can still use this easily at the top of the screen without an scanline counter if you have a way to count cycles from the top of the screen (VBlank is constant timed or you detect the start of the frame waiting for the overflow or sprite 0 hit flags to clear).

Quote:
It's amazing what RARE did with discrete mappers and CHR-RAM.

They didn't care about the alternate dot crawl pattern, though. I think it looks OK for static images, but scrolling left and right produce different effects that bother me a bit.
Re: How to hide vertical scrolling updates with no status ba
by on (#108002)
What do you need the blank tiles for, when you can simply disable rendering backgrounds, but keep rendering sprites?

Anyway, the king of status bars on discrete hardware is Fire Hawk, which is driven entirely by DMC IRQs once it uses sprite 0 to synchonize them properly. But honorable mention also goes to Time Lord and Wizards and Warriors III. Wizards and Warriors III makes a copy of one of the tiles to add a dot to that tile, then makes sprite 0 (another dot) hit that tile. Time Lord does that, and also uses DMC IRQs to ensure that the code to wait for the sprite 0 hit is called.
Re: How to hide vertical scrolling updates with no status ba
by on (#108003)
Dwedit wrote:
What do you need the blank tiles for, when you can simply disable rendering backgrounds, but keep rendering sprites?

This. Since sprites can be hidden with 8 high priority sprites, it's perfectly possible to hide both BG and sprites without disabling graphics and without wasting a CHR-ROM page with blank patterns.
Re: How to hide vertical scrolling updates with no status ba
by on (#108004)
tokumaru wrote:
GradualGames wrote:
-Upload all solid tiles in one of those banks

A pattern table filled with solid tiles will result in attribute glitches, because each palette uses different solid colors. Unless you decide to make one of the colors always the same, which is a huge waste IMO, since they all share color 0 already. Two unique colors per palette is a pretty serious restriction if you ask me.


Dangit, I didn't think of this. It's starting to look like my only option given my setup may be cycle timed code. Which, I don't think will be that bad. And, I thought more on it and I think as you may have already pointed out, the 9 sprite trick may be useful for graceful sprite clipping, too (in other words, if I'm not using it for sprite 0 hit, I can still use it just for sprite clipping and nothing else). Thanks.

*edit* At one point, I was feeling hopeful that the palette itself could be bankswitched out using bankswitchable CHR-RAM. But, I believe the palette maps to registers in the ppu itself, you can't have a CHR-ROM palette for example?

And, part of me is tempted to just simply never bother and rely on NTSC overscan. Problem is, I've already seen this not work as well as one might like on some TVs.
Re: How to hide vertical scrolling updates with no status ba
by on (#108008)
HDTVs hide the top 8 and bottom 8 lines; SDTVs tend to hide about the top 12 and bottom 4.

But there's one way to stop attribute glitches cold: a row of blank tiles at the scroll seam. This row can sit well within the NTSC overscan.
Re: How to hide vertical scrolling updates with no status ba
by on (#108012)
tokumaru wrote:
They didn't care about the alternate dot crawl pattern, though. I think it looks OK for static images, but scrolling left and right produce different effects that bother me a bit.


Is this only noticeable on an actual TV? I hadn't noticed anything odd using cycle timed code to black out graphics for the top 16 or so scanlines within an emulator. I must have something else wrong though because on FCEUX, some actual previously uploaded CHR data seemed to get corrupted---but it was fine on Nestopia and Nintendulator (granted, my very quick try has not been smoothed out yet.)

Is dot crawl a fairly subtle effect? From a little bit of reading, it sounds like that subtle jagged edge effect one can see in a composite signal. If it just juggles that pattern a bit, I can't imagine finding this too bothersome.

*edit* also, how bad would it look to actually upload a black palette before end of vblank, and then upload the correct palette (after waiting with cycle timed code)? If it just produces a one pixel wide glitchy looking line, I might actually be ok with this. Or is there another gotcha there? Hmm, if that can work, maybe hide the glitchy line with 9 sprites? (assuming the glitchy part of the line is short enough to be covered by all of these) This could eliminate dot-crawl problem by leaving graphics on but also help with sprite clipping at same time perhaps?
Re: How to hide vertical scrolling updates with no status ba
by on (#108014)
Quote:
Is this only noticeable on an actual TV?

Yes, if at the end of the VBlank the graphics are disabled the dot who is skipped every other frame is never skipped. Then it makes the image looks as crappy as Sega consoles :)
Re: How to hide vertical scrolling updates with no status ba
by on (#108015)
Bregalad wrote:
Quote:
Is this only noticeable on an actual TV?

Yes, if at the end of the VBlank the graphics are disabled the dot who is skipped every other frame is never skipped. Then it makes the image looks as crappy as Sega consoles :)


I wonder if I could use the 9 sprite trick tokumaru mentioned to detect the beginning of a frame, and THEN turn off graphics, then wait with cycle timed code, then turn them back on. Is that another possible way to eliminate dot crawl as well? Or is that exactly the trick tokumaru mentioned and I'm now understanding all of the edge cases it addresses? :)
Re: How to hide vertical scrolling updates with no status ba
by on (#108018)
Quote:
I wonder if I could use the 9 sprite trick tokumaru mentioned to detect the beginning of a frame, and THEN turn off graphics, then wait with cycle timed code, then turn them back on. Is that another possible way to eliminate dot crawl as well? Or is that exactly the trick tokumaru mentioned and I'm now understanding all of the edge cases it addresses?


That's pretty much what I've done for my own game recently - you can find some interesting points about how I solved it at the end of this thread.

As the topic suggests, disabling rendering triggers a nasty bug on NTSC NESes which causes corruption of sprites the next time you enable it. But if you turn off rendering around dot 330 then AFAICT this will always affect sprites 2 and 3 only, so you can avoid the sprite corruption by just starting your sprite page write pointer at a higher offset. But I cannot stress enough that if you write code where timing is this important to avoid a hardware quirk you should in no way rely on emulators for testing its correctness.

Also, if you have a sprite#0 hit that gets triggered in every frame then you don't need those 9 blank sprites you mentioned since you can wait for the start of vblank just by waiting for this flag to get cleared again. :)
Re: How to hide vertical scrolling updates with no status ba
by on (#108020)
Bananmos wrote:
Quote:
I wonder if I could use the 9 sprite trick tokumaru mentioned to detect the beginning of a frame, and THEN turn off graphics, then wait with cycle timed code, then turn them back on. Is that another possible way to eliminate dot crawl as well? Or is that exactly the trick tokumaru mentioned and I'm now understanding all of the edge cases it addresses?


That's pretty much what I've done for my own game recently - you can find some interesting points about how I solved it at the end of this thread.

As the topic suggests, disabling rendering triggers a nasty bug on NTSC NESes which causes corruption of sprites the next time you enable it. But if you turn off rendering around dot 330 then AFAICT this will always affect sprites 2 and 3 only, so you can avoid the sprite corruption by just starting your sprite page write pointer at a higher offset. But I cannot stress enough that if you write code where timing is this important to avoid a hardware quirk you should in no way rely on emulators for testing its correctness.

Also, if you have a sprite#0 hit that gets triggered in every frame then you don't need those 9 blank sprites you mentioned since you can wait for the start of vblank just by waiting for this flag to get cleared again. :)


What if we never disable rendering, upload a black palette by the end of vblank, then wait for enough cycles to black out the top 16 scanlines, and then upload the correct palette? I would expect some part of a scanline at the bottom of the blacked out 16 pixel wide bar to show the palette gradually come in and this line might look odd. But, I was thinking, maybe sprites could be used to hide this. I wonder how well this would work? Has anyone tried this?
Re: How to hide vertical scrolling updates with no status ba
by on (#108021)
Quote:
What if we never disable rendering, upload a black palette by the end of vblank, then wait for enough cycles to black out the top 16 scanlines, and then upload the correct palette?


Yeah, I guess that would work. Though you would miss the opportunity to use the black area for PPU updates. And you'd still need to disable rendering when uploading the "real" palette, so the hardware quirk would still have to be handled.

Quote:
I would expect some part of a scanline at the bottom of the blacked out 16 pixel wide bar to show the palette gradually come in and this line might look odd. But, I was thinking, maybe sprites could be used to hide this. I wonder how well this would work? Has anyone tried this?


Not doable, simply because updating the palette requires you to turn off rendering in the first place. ;)
(in addition, turning rendering off will make sprites invalid for the next scanline)
Re: How to hide vertical scrolling updates with no status ba
by on (#108023)
Bananmos wrote:
Quote:
What if we never disable rendering, upload a black palette by the end of vblank, then wait for enough cycles to black out the top 16 scanlines, and then upload the correct palette?


Yeah, I guess that would work. Though you would miss the opportunity to use the black area for PPU updates. And you'd still need to disable rendering when uploading the "real" palette, so the hardware quirk would still have to be handled.

Quote:
I would expect some part of a scanline at the bottom of the blacked out 16 pixel wide bar to show the palette gradually come in and this line might look odd. But, I was thinking, maybe sprites could be used to hide this. I wonder how well this would work? Has anyone tried this?


Not doable, simply because updating the palette requires you to turn off rendering in the first place. ;)
(in addition, turning rendering off will make sprites invalid for the next scanline)


I can't believe how deep the rabbit hole goes with this stuff, it is pretty staggering. Maybe I should just throw in the towel and make my game single-screen only, LOL. I'm tempted to just leave it as using NTSC overscan straddling the row update between the top and bottom 8 pixels. It'll look 99% ok on most TV's. I'm pretty sure Mega Man 1 uses the straddle technique when scrolling vertically. And I know Super Bat Puncher does, and it looks great.

I forget why you must have rendering off to upload the palette. I know I ran into this before and found I must always upload the palette either inside vblank or with rendering off, does it cause tearing in places other than the scanline currently being rendered? I can't remember.
Re: How to hide vertical scrolling updates with no status ba
by on (#108024)
tokumaru wrote:
Yeah, that's the problem. Have you ever played Big Nose Freaks Out? Watch the video and you'll see it keeps a solid tile at the bottom right corner at all times. The problem with this approach is that the tile itself ends up looking like a glitch, which doesn't make much sense considering that our purpose is to -hide- glitches (Big Nose probably does it for the extra VBlank time though).

What is the logic behind that tile? It seems to constantly move around o_O;

tokumaru wrote:
Jurassic Park does this.

Except it uses all-black tiles instead of blank tiles, which are very noticeable because they don't match the background color (which is used for the border!).

Bregalad wrote:
Since sprites can be hidden with 8 high priority sprites, it's perfectly possible to hide both BG and sprites without disabling graphics and without wasting a CHR-ROM page with blank patterns.

If you have the mapper do the hiding for you then you don't even need dedicated CHR-ROM tiles for that, just make the mapper return all zeroes... (of course this is starts making the circuit a bit more complex than what is already being discussed)
Re: How to hide vertical scrolling updates with no status ba
by on (#108025)
I just got another idea, what do you guys think of this:

-Use bankswitchable CHR-RAM
-Upload all solid tiles in one of those banks, which select colors with matching luminosity in all four, four color palettes
-Be switched to the all solid bank at end of vblank, and set the monochrome bit
-Run sound engine code (but be sure that worst case, all music and effects won't take a very long time)
-Wait for sprite 0 hit at 16th scanline (or maybe later, to account for worst case sound engine updates)
-Switch to whatever should be the active CHR-RAM bank for normal graphics (still lets me use 3 frames of animation for background, should be fine)
-Clear the monochrome bit.

If one could somehow guarantee that the luminosity is the same for say the third color of every four color sub palette, it seems like using the monochrome bit would get rid of the attribute glitches tokumaru mentioned. I certainly don't care what the color of the "hiding bar" is, just that it works and looks stable! *edit* The primary disadvantage of course would be having to make sure your palettes always work with this scheme. It might not be as bad as ensuring that one color of every four color sub-palette would have to match luminosity, because I think setting the monochrome bit does not get you 4 luminosities of gray, I recall at least two of them always collapsing together and showing the same gray.
Re: How to hide vertical scrolling updates with no status ba
by on (#108026)
Dwedit wrote:
What do you need the blank tiles for, when you can simply disable rendering backgrounds, but keep rendering sprites?

Two reasons:
1 - keeping the background enabled will allow you to use a sprite 0 hit to sync with the PPU (i.e. no constant-timed VBlank);
2 - after the sprite hit, sprites can be masked without fully disabling rendering or needing dummy high priority sprites;

Quote:
Wizards and Warriors III makes a copy of one of the tiles to add a dot to that tile, then makes sprite 0 (another dot) hit that tile.

That's pretty extreme, but much better looking than the solid tile in Big Nose Freaks Out.
Re: How to hide vertical scrolling updates with no status ba
by on (#108031)
tepples wrote:
SDTVs tend to hide about the top 12 and bottom 4.

I observed something like this in My TVs as well, which is why it doesn't bother me to hide a significant amount of scanlines at the top only, instead of hiding scanlines at the bottom too.

GradualGames wrote:
Is this only noticeable on an actual TV?

On actual TVs or emulators that use blargg's NTSC filter.

GradualGames wrote:
I wonder if I could use the 9 sprite trick tokumaru mentioned to detect the beginning of a frame, and THEN turn off graphics, then wait with cycle timed code, then turn them back on. Is that another possible way to eliminate dot crawl as well?

The alternate dot crawl will only happen if both background and sprites are disabled (the PPU only "shuts down" if both are disabled, otherwise it functions as normal and just doesn't display the layer that's turned off). If you're keeping sprites enabled you don't have to worry about it. Disabling the PPU for good (both sprites and BG) has the annoying side effect of corrupting OAM (this was discovered by tepples a while ago) unless you obey some mystical conditions (like the exact point in the scanline where you do it or which sprites are visible in that scanline).

Quote:
What if we never disable rendering, upload a black palette by the end of vblank, then wait for enough cycles to black out the top 16 scanlines, and then upload the correct palette?

To update the palette you have to fully disable rendering, so you run into that OAM corruption issue again. Also, you'll have to reset the scroll with $2005/6 magic after changing the palette.

Sik wrote:
What is the logic behind that tile? It seems to constantly move around o_O;

Without an scanline counter, the most common way to sync with the PPU is with sprite 0 hits: the PPU sets a bit when a solid pixel in sprite 0 overlaps a solid pixel in the background. If the game scroll horizontally and vertically, it gets hard to guarantee that there will be a solid background pixel where the sprite is unless you intentionally put a solid tile there. This is what this game does, and it ends up looking like an annoying glitch.

GradualGames wrote:
and set the monochrome bit

Now there's a good idea! Having to use a constant luminosity at a certain palette slot is not such a bad limitation. Sounds to me like a great solution.
Re: How to hide vertical scrolling updates with no status ba
by on (#108036)
tokumaru wrote:
Disabling the PPU for good (both sprites and BG) has the annoying side effect of corrupting OAM (this was discovered by tepples a while ago) unless you obey some mystical conditions (like the exact point in the scanline where you do it or which sprites are visible in that scanline).

Mystical nothing. It takes 64 dots to start the sprite evaluator each line, 128 to check whether all are in range, and 6 more for each that is in range. If all 8 are in range, that's 240 dots, so if you can turn it off between 240 and 255 you're golden.
Re: How to hide vertical scrolling updates with no status ba
by on (#108038)
Quote:
Mystical nothing. It takes 64 dots to start the sprite evaluator each line, 128 to check whether all are in range, and 6 more for each that is in range. If all 8 are in range, that's 240 dots, so if you can turn it off between 240 and 255 you're golden.


Have you confirmed that turning it off between dot 240-255 actually prevents all glitches? That range does seem a lot more forgiving to time to than the current dot 330 I've been using... :)
Re: How to hide vertical scrolling updates with no status ba
by on (#108048)
I think you should just leave the "glitches" because commercial games have them but generally they are so on the edge you don't see them plus if the screen is moving it distracts the players from the glitches if they are appearing on the opposite side of travel, so if you are going up the glitches should show on the bottom and vice versa.

I don't think it is worth an overly complex solution to hide minor graphics glitches.

Also wouldn't just wiring up a SRAM for 4 screen mirroring solve the issue too? Seems that either of those are preferable to trying to rig up a complex routine to hide it.
Re: How to hide vertical scrolling updates with no status ba
by on (#108052)
The first page, they said $1 was not worth fixing it. Heh. But yeah, SMB3 has huge scrolling glitches on the side, I always noticed....boo.
Re: How to hide vertical scrolling updates with no status ba
by on (#108056)
SMB3 doesn't seem to put any serious effort on hiding those glitches though, if at all. It just waits for the 16 pixel column to be fully visible and then sets the palette - blatantly noticeable. At least it disables the leftmost 8 pixels column so the glitches are only in the palette and not in the tiles (also it's doing horizontal mirroring, here we're looking for vertical mirroring).
Re: How to hide vertical scrolling updates with no status ba
by on (#108074)
MottZilla wrote:
I think you should just leave the "glitches" because commercial games have them but generally they are so on the edge you don't see them

I ALWAYS see them, it's like they're screaming at me.

Quote:
plus if the screen is moving it distracts the players from the glitches if they are appearing on the opposite side of travel

To me it's the exact opposite, the glitches distract me from the game action. Humans can only focus on small spots, and we use our blurry peripheral vision to detect movement, and when that happens we move our eyes to focus on the area where the movement occurred. When I'm playing and some blocks suddenly change color at the edge of the screen, my brain thinks something is happening over there, so I look at the glitches. My peripheral vision keeps noticing them, and they keep distracting me... I actually have to force myself to ignore the popping colors in order to play games like SMB3 and Kirby's Adventure (which I love, despite this problem). I don't know if this is just me, but it's enough for me to not want this in my own games.

Quote:
I don't think it is worth an overly complex solution to hide minor graphics glitches.

Vertical glitches are minor only in NTSC I think, I remember people saying that they are very noticeable on PAL.

Quote:
Also wouldn't just wiring up a SRAM for 4 screen mirroring solve the issue too? Seems that either of those are preferable to trying to rig up a complex routine to hide it.

If you're using CHR-RAM and can use the same chip for name tables then I agree. But if you use CHR-ROM and need to hack another chip in, a software solution would be better.

Sik wrote:
SMB3 doesn't seem to put any serious effort on hiding those glitches though, if at all. It just waits for the 16 pixel column to be fully visible and then sets the palette - blatantly noticeable.

It really bothers a lot that some high profile games such as SMB3 (widely considered the best NES game ever) and Kirby's Adventure settled for this.
Re: How to hide vertical scrolling updates with no status ba
by on (#108076)
4-screen mirroring would definitely be ideal. So far, I have relied on retrousb for production of cartridges and will probably continue to. If it is as cheap as you guys have mentioned here in this thread, I'll proably go that route. I have a vague memory though of being told that could be more expensive than 1$, but I'll have to look into it again.

If that doesn't work though, yes, I am tempted to just leave it as-is and rely on NTSC overscan. I have one crt tv which just barely shows the top of the updated row at the bottom of the screen. It's not even as bad as SMB3 or Kirby, so I'll probably be happy with this if none of these other solutions pan out. I definitely am enjoying learning how to make this work should I choose to stick with it, though.

Tokumaru, why are you not happy with NTSC overscan the way Super Bat Puncher does? Just that some tvs might show a little of the updates?
Re: How to hide vertical scrolling updates with no status ba
by on (#108083)
4-screen mirroring can't hide the sprites-pop up glitches at the left nor at the top of the screen.

As I said the only way to get 100% clean scrolling is to hide the leftmost and top most 8 pixels. Then, if vertical mirroring or 8x16 sprites are used (or both), the top 16 pixels should be hidden, otherwise, if horizontal mirroring is used there should instead hide the right most 8 pixels too with sprites.

Therefore, the only purpose of 4-screen mirroring is that you could hide only the left 8 and top 8 pixels if you use 8x8 sprites, and if you use 8x16, there is no difference whenever you use 4-screen or vertical mirroring (since you should hide the top 16 scanlines anyways).

Now whenever you actually want 100% clean scrolling is another story.
Re: How to hide vertical scrolling updates with no status ba
by on (#108086)
For the sake of simplicity, I had meant to constrain this thread to just background scrolling. I don't care as much about sprite popping because that's so brief and near the edge of the screen. But if the whole updated row of a nametable is visible you have a veritable light show on your hands. So, if I end up perfecting any of those issues, it will be scrolling.
Re: How to hide vertical scrolling updates with no status ba
by on (#108088)
I don't understand why people would be bothered by glitches on the background, but not on the sprites.

Attributes clashes on a scrolling BG are also "so brief" and "near the edge of the screen", yet people seems to find them unacceptable.

That being said I perfectly respect that you'd make such a choice, I was just pointing out that if you aim for perfect scrolling, sprites should be taken into consideration, too, because yes, this is noticeable, and probably moreso than 3 pixel attributes clashes on a horizontal scrolling BG using horizontal mirroring such as in my demo.
Re: How to hide vertical scrolling updates with no status ba
by on (#108090)
GradualGames wrote:
4-screen mirroring would definitely be ideal. So far, I have relied on retrousb for production of cartridges and will probably continue to. If it is as cheap as you guys have mentioned here in this thread, I'll proably go that route.

I believe that if you use CHR-RAM (and the CHR-RAM chip is at least 16KB - most are I think, 8KB RAMs are pretty rare nowadays), it's just a matter of keeping the CHR chip always enabled and the internal CIRAM always disabled, you just need to change 1 or 2 connections, so AFAIK the cost is $0. CHR-ROM makes things more complicated, because you have to add an extra chip and select between it and the CHR-ROM.

Quote:
Tokumaru, why are you not happy with NTSC overscan the way Super Bat Puncher does? Just that some tvs might show a little of the updates?

Things don't look so bad in Super Bat Puncher, because it has very dark backgrounds. Most of my projects have pretty sunny levels, which makes the glitches more noticeable. Also, from what I've heard, PAL consoles/TVs don't crop any of the picture at the top and bottom, so all glitches are fully visible.
Re: How to hide vertical scrolling updates with no status ba
by on (#108091)
[Off topic post.] Sprites 1. Show up 100% and correctly. 2. Aren't clearly visible for lots of frames. 3. Can be eliminated by game design ad not having enemies come from the top?

But still, if you use CHR-RAM for the 4 screen, you'll be giving up lots of space in the RAM. But it's not too bad. Stick a 16KB RAM on there and have at it, I guess?

But still, IMO, software patching and making the screen off-center just to fix it are worse design choices than giving up a tiny bit of your profit. If you're not using custom boards, then software is the best way. But if you can develop a PCB, then just stick a 4KB RAM in a devtendo and start going at it. :)
Re: How to hide vertical scrolling updates with no status ba
by on (#108092)
Bregalad wrote:
I don't understand why people would be bothered by glitches on the background, but not on the sprites.

Most homebrewers use 8x8 sprites, so the problem isn't so severe at the top of the screen, and the left side can just be hidden by the PPU.

Quote:
Attributes clashes on a scrolling BG are also "so brief" and "near the edge of the screen", yet people seems to find them unacceptable.

With the background the artifacts span an entire side of the screen (much larger), they are periodic (like a blinking light, draws more attention), and they happen on static objects. A sprite is most likely going to be a moving object, so when it "pops" and your peripheral vision draws your attention to it, it does indeed find a moving object that needs your attention (like an enemy). When colors "pop" on the background you are deceived, there's nothing there that needs your attention.

I try to make scrolling cleaner on sprites as well, but that's not a priority for me.

Quote:
this is noticeable, and probably moreso than 3 pixel attributes clashes on a horizontal scrolling BG using horizontal mirroring such as in my demo.

I completely disagree, for the reasons I listed above.
Re: How to hide vertical scrolling updates with no status ba
by on (#108095)
Tokumaru, have you tried the DMC IRQ technique mentioned a couple of times in this thread? To me, this sounds almost ideal. With an IRQ, I can avoid doing any waiting for a bit transition and let my sound engine run (I mention this because I update all sound at end of vblank in the new engine). I was also thinking, I wonder if it is possible to set up DMC IRQ for raster effects like this:

-set it up at start of vblank, but tweak the timing to fire an IRQ AFTER vblank is done and a frame has begun rendering, preferably far enough down to hide updates at top

-once the first irq fires, set it up immediately to fire again near the bottom of the screen.

If this is possible, this seems absolutely ideal for my present setup because it would require no new hardware, would not eat up very much cpu time (waiting for anything), and would hide updates very gracefully. I guess I'd have to tweak the timing for NTSC and PAL builds, though, but it doesn't sound so bad.

I guess the primary disadvantage is you can't use DMC for sound. I made the decision early on in this project to not use DMC for sound. Hmm, if I use DMC at all though, will that introduce the controller read bug?
Re: How to hide vertical scrolling updates with no status ba
by on (#108109)
GradualGames wrote:
Tokumaru, have you tried the DMC IRQ technique mentioned a couple of times in this thread?

The DMC IRQ isn't as useful as you'd like. The precision is far from ideal and the APU works at a pace you cannot mess with. This means that even you start playing a (silent) sample at the same time every frame, the IRQ will fire at different times, with errors of several scanlines. What was suggested in this thread (IIRC) was to have the IRQ fire a little before the position of sprite 0, so you wouldn't miss the hit.

A while ago tepples had an idea to make DMC IRQs more useful, which involved counting how long it takes for one IRQ to fire and use that time to compensate for the error in subsequent IRQs. I experimented with this a bit too, but never got something as stable as I wanted. Tepples released some demos using this technique... try searching for them.

Quote:
Hmm, if I use DMC at all though, will that introduce the controller read bug?

If you read the controller between the time you start playing the sample and when the IRQ fires, yes.
Re: How to hide vertical scrolling updates with no status ba
by on (#108119)
tokumaru wrote:
A while ago tepples had an idea to make DMC IRQs more useful, which involved counting how long it takes for one IRQ to fire and use that time to compensate for the error in subsequent IRQs. I experimented with this a bit too, but never got something as stable as I wanted. Tepples released some demos using this technique... try searching for them.

The demo was DPCM Letterbox, and the topic was this one. the demo is for NTSC and shows a scrolling window about 160 lines tall. One advantage of blanking so much is that in the era of widescreen TVs, zooming in won't cover anything important.

tokumaru wrote:
GradualGames wrote:
Hmm, if I use DMC at all though, will that introduce the controller read bug?

If you read the controller between the time you start playing the sample and when the IRQ fires, yes.

If you read the controller immediately after getting an IRQ, you shouldn't get the bug.
Re: How to hide vertical scrolling updates with no status ba
by on (#108122)
Bregalad wrote:
I don't understand why people would be bothered by glitches on the background, but not on the sprites.

Sprites vanishing like that horizontally can be hidden with the left column blanking, and in most games sprites vanishing vertically are sprites that are moving in that direction anyway so you probably want to pay attention to them.
Re: How to hide vertical scrolling updates with no status ba
by on (#108151)
Here's a "before and after" video of my first attempt at hiding scrolling glitches.

Cycle timed scrolling glitch hiding

Advantages:
-Was pretty easy to implement, mainly because my vblank routines are pretty linear and easy to cycle-pad (just blasting buffers to ppu, very few branches)
-Does not use up any sprites
-No extra hardware required
-May encourage me to try to optimize other parts of my engine because of the wasted cpu time

Disadvantages:
-Uses up a lot of cpu cycles just to hide graphical glitches. I may try putting some stable portions of sound update and controller reading (as suggested here in this thread!) in the padded part.
-Need to tweak timing for PAL separately from NTSC if I choose to support PAL systems.
-Hard to get absolutely right. You can see a few bouncy pixels on the bottom scanline of the artificial hidden area. Probably due to taken or untaken branches not accounted for in the padding.

I'm pretty happy with this, for now. My new game is a hybrid between full scrolling "overworld" areas and single-screen dungeon type of areas---it is possible I may not need to find a better approach that doesn't eat up CPU cycles. But I really like getting the clean scrolling out of this.

*edit* oops, I just saw a bug in that video. Can you spot it? Have to fix that...
Re: How to hide vertical scrolling updates with no status ba
by on (#108152)
So you're keeping sprites enabled to avoid the different dot crawl and using timed code to enable background rendering? Sounds like a good compromise to me, sprite popping doesn't bother me nearly as much as background glitches.

GradualGames wrote:
-Uses up a lot of cpu cycles just to hide graphical glitches. I may try putting some stable portions of sound update and controller reading (as suggested here in this thread!) in the padded part.

Yeah, put as much constant-timed code as you can in there.

Quote:
-Need to tweak timing for PAL separately from NTSC if I choose to support PAL systems.

That's pretty easy though. There are several ways to detect whether the system is NTSC, PAL or DENDY on start up, and then you can time the wait based on that detection. You can just wait the amount of time necessary to make the trick work in NTSC/DENDY and then check whether you need to wait any longer for PAL.
Re: How to hide vertical scrolling updates with no status ba
by on (#108157)
Looks like you solved it well. Just hope you really don't need that extra CPU time. Though you can put some of it to use you'll probably not be able to utilize all of it.
Re: How to hide vertical scrolling updates with no status ba
by on (#108256)
tokumaru wrote:
Good luck with the cycle counting, I'm sure you'll regret that choice! =)


You weren't kidding! I spent the whole weekend on this thing and I think I've finally got it tweaked right. My first attempt, shown in the video, wasn't quite correct because the padding was a bit rough and sometimes the graphic hiding logic (turn bg off...wait....turn on) would start near the end of vblank rather than at the start of a new frame. I got some weird scrolling glitches as a result (only on real hardware...!). So, I had to come up with a better way to cycle-pad my column and row vblank routine. I came up with this:

Code:
  ;cycle pad this ppu upload routine for the artificial scroll
  ;update hiding bar (see the main module)
  lda #0
  sta cycle_pad_lut_index
  lda column_ready
  ror
  rol cycle_pad_lut_index
  lda #0
  sta column_ready

  lda row_ready
  ror
  rol cycle_pad_lut_index
  lda #0
  sta row_ready

  ldx cycle_pad_lut_index
  lda cycle_pad_lut1,x
  tax
: dex
  bne :-
  ldx cycle_pad_lut_index
  lda cycle_pad_lut2,x
  tax
: dex
  bne :-


It accounts for all four combinations of "please upload a row," "please upload a column," that can be passed into this routine. The luts have values that I just played with until I could see the graphics hiding bar start just a few pixels from the top left part of the screen (for all directions, up/down, left/right, and diagonals). So, I basically moved the "bouncy pixels" artifact to the top left, which is great for NTSC. As an unexpected and cool side effect, the bottom right of the graphics hiding bar is no longer bouncy. I wonder if it is disappearing into hblank at that point?
Re: How to hide vertical scrolling updates with no status ba
by on (#108262)
GradualGames wrote:
I wonder if it is disappearing into hblank at that point?

HBlank is 28.33 cycles on NTSC and 26.5625 cycles on PAL, so you have a little room to accommodate small timing variations.
Re: How to hide vertical scrolling updates with no status ba
by on (#108273)
If you use sprite-0-hits, you can use the clearing of the sprite-0-hit flag to figure out the beginning of rendering (top of screen). This takes out the PAL/NTSC difference from the equation.

To force that sprite-0-hit flag is triggered at the bottom of the screen with minimal impact, you can duplicate the trick that Solar Jetman uses. Solar Jetman does some serious magic to ensure that there is _always_ a visible tile in the bottom left corner of the play area, and that when there is not supposed to be one, there still is one and it looks like just one pixel. It helps getting away with it, that the background has stars, which also look like singular pixels. This minimal-impact method is doable only on VRAM.

Personally, I would say run with it. Simon's Quest does 4-way scrolling with vertical mirroring. It updates 8-pixel tall/wide columns/rows at once on the edges of the screen, and it updates attribute tables at 16-pixel intervals. (I.e. finest grained possible in each direction.) Obviously this means that there can be 0-7 pixels of garbage tiles on the top of the screen, and 0-15 pixels of wrong colors at the top of the screen, if the television displays the full 240 scanlines. Not too bothersome. Way less bothersome, in my opinion, than what SMB3 has going on in the right edge of the screen.