Page 1 of 4

How to hide vertical scrolling updates with no status bar?

Posted: Wed Feb 20, 2013 5:47 pm
by GradualGames
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

Posted: Wed Feb 20, 2013 6:03 pm
by Kasumi
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

Posted: Wed Feb 20, 2013 6:05 pm
by 3gengames
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

Posted: Wed Feb 20, 2013 6:11 pm
by tokumaru
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.
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).
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.
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

Posted: Wed Feb 20, 2013 6:16 pm
by tokumaru
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

Posted: Wed Feb 20, 2013 6:58 pm
by GradualGames
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

Posted: Wed Feb 20, 2013 7:22 pm
by tokumaru
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

Posted: Wed Feb 20, 2013 7:27 pm
by infiniteneslives
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

Posted: Wed Feb 20, 2013 7:51 pm
by GradualGames
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

Posted: Wed Feb 20, 2013 8:12 pm
by 3gengames
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

Posted: Wed Feb 20, 2013 8:47 pm
by GradualGames
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

Posted: Wed Feb 20, 2013 8:53 pm
by tokumaru
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).
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.
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

Posted: Wed Feb 20, 2013 8:58 pm
by GradualGames
tokumaru wrote:
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

Posted: Wed Feb 20, 2013 9:45 pm
by tokumaru
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:
clean-scroll-1.png
clean-scroll-1.png (4.87 KiB) Viewed 2414 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).
clean-scroll-2.png
clean-scroll-2.png (3.78 KiB) Viewed 2414 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

Posted: Wed Feb 20, 2013 9:48 pm
by tokumaru
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.