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

[Solved] Forced VBlank at Line 216

[Solved] Forced VBlank at Line 216
by on (#101276)
Heyas! Long time no 8-bit :P

I'm working on a design that requires a lot of PPU bandwidth but not a lot of screen space. What I'd like to do is to use a sprite 0 hit to disable the PPU after line 216, then start the PPU writes. I'd then re-enable rendering when I'm done, sometime before line 24.

I remember there was a lot of discussion some time back about disabling sprite rendering at the wrong time on a scan line, but I can't find the thread. Also I have read that the Sprite 0 hit flag is cleared during the pre-render scan line and I am unsure if this will still happen if PPU rendering is disabled during that scan line.

Can anyone point out the caveats to this method? Example code?

Thanks,
QBRADQ
Re: Forced VBlank at Line 216
by on (#101278)
The sprite 0 hit and nine sprites bits are cleared on line -1 even if rendering is disabled. The only things skipped are resetting the VRAM address (loopy_v = loopy_t) and the dropped dot used for dot crawl realignment.

Does this project scroll in four directions? If so, you'll need to think of a clever way to keep sprite 0 overlapping something opaque.
Re: Forced VBlank at Line 216
by on (#101280)
qbradq wrote:
I remember there was a lot of discussion some time back about disabling sprite rendering at the wrong time on a scan line, but I can't find the thread.

Finding the thread is easy, the hard part is figuring out the safe moment to turn rendering off. It seems that this is only safe when there are no sprites in the scanline.
Re: Forced VBlank at Line 216
by on (#101297)
tepples wrote:
The sprite 0 hit and nine sprites bits are cleared on line -1 even if rendering is disabled. The only things skipped are resetting the VRAM address (loopy_v = loopy_t) and the dropped dot used for dot crawl realignment.


It's good to chat with you again Tepples! I remember dealing with the loopy_v and loopy_t issue when I made my first scrolling space shooter demo. Had to reset the scroll registers every frame. How do I fix the dot crawl realignment issue though? Doesn't that make the screen look all funky?

tepples wrote:
Does this project scroll in four directions? If so, you'll need to think of a clever way to keep sprite 0 overlapping something opaque.


No scrolling at all. I'm back to my fixed-screen RPG idea that I kept ditching in the past.

Good to see you again too Tokumaru! Finding the thread was not easy for me because I couldn't remember the title or terminology used. Thanks for the link!
Re: Forced VBlank at Line 216
by on (#101300)
qbradq wrote:
How do I fix the dot crawl realignment issue though? Doesn't that make the screen look all funky?
The only way to avoid the different dot crawl pattern is to have rendereng enabled at the beginning of the frame. The timing could be tricky, but you could try something like this:

-after the sprite 0 hit on scanline 216, disable rendering;
-when the NMI fires, enable rendering (you can keep writing to VRAM though, since it's VBlank now);
-perform a safe amount of VRAM operations (i.e. don't go past VBlank) and wait for the sprite hit flag to be cleared (this will indicate the start of the frame);
-wait until it's safe to turn rendering off again and do it;
-make more VRAM transfers before enabling rendering on scanline 24 (there's nothing to help you time this, you'll have to use timed code);

Personally, I think this is too much trouble... IMO, the different dot crawl doesn't look bad at all, I'd just live with it. Actually, without scrolling, I think it looks even better than the regular video.

Quote:
Finding the thread was not easy for me because I couldn't remember the title or terminology used.

I mean't it was easy for me (since I remembered enough about it to find it), and that I just can't understand the exact problem with the glitched sprites. I just avoid turning rendering off early as much as I can.
Re: Forced VBlank at Line 216
by on (#101304)
Thanks for the input folks! I'll tinker around with it.

Does anyone know if Nintendulator or another emulator correctly emulates the dot crawl pattern and OAM corruption behaviors? It'll be a while before I get my hardware back together :D
Re: Forced VBlank at Line 216
by on (#101307)
qbradq wrote:
Does anyone know if Nintendulator or another emulator correctly emulates the dot crawl pattern and OAM corruption behaviors?

I'm not sure about OAM corruption, but Blargg's NTSC filter emulates the dot crawl patterns correctly, so any emulator with it will do. Nintendulator doesn't have any filters, AFAIK.
Re: Forced VBlank at Line 216
by on (#101309)
Battletoads uses the "funky" pattern and gets away with it.

What exactly are you doing that needs ~768 bytes copied to VRAM per field, may I ask? Let me guess: a fighting game where sprite cels are swapped into CHR RAM Battletoads-style.
Re: Forced VBlank at Line 216
by on (#101313)
Wow Tepples, I hadn't even done the math yet :D

I've got a 22x22 cell area of the screen that I will be refreshing, plus a few number displays here and there. It's similar to Ultima 5: Warriors of Destiny, but I'm hoping to do it with some different assumptions and limitations, and get it running at 20 FPS. Even 10 should be smooth enough. 48 lines of forced VBlank may be overkill for what I'm trying to do.

Like I said, I'll tinker with it :D

Thanks for all the input!

Oh also I'm ignorant of NTSC filters. What emulators use that? My main fear is the dot-crawl pattern changing back when I'm not doing PPU updates.
Re: Forced VBlank at Line 216
by on (#101315)
qbradq wrote:
I've got a 22x22 cell area of the screen that I will be refreshing, plus a few number displays here and there. It's similar to Ultima 5: Warriors of Destiny, but I'm hoping to do it with some different assumptions and limitations, and get it running at 20 FPS. Even 10 should be smooth enough. 48 lines of forced VBlank may be overkill for what I'm trying to do.

Honestly, you don't need forced blanking at all in this case. At 20fps, you have 3 frames to upload the data (60 / 3 = 20). Each VBlank is approximately 2273 cycles long, so you have a total of 6819 cycles of PPU access, enough for transferring 852 bytes with the fastest possible code (unrolled loops). A 22x22-tile are is just 484 bytes, plus attributes and the numbers, everything should fit comfortably in the time you have (and you won't even need completely unrolled code). Much better than having to deal with complex timed procedures IMO.

Quote:
Oh also I'm ignorant of NTSC filters. What emulators use that?

I use mainly Nestopia to test NTSC artifacts.

Quote:
My main fear is the dot-crawl pattern changing back when I'm not doing PPU updates.

You definitely don't want to switch back and forth. The program should keep the same enabling/disabling procedures even when not uploading data to VRAM.
Re: Forced VBlank at Line 216
by on (#101317)
tepples wrote:
Battletoads uses the "funky" pattern and gets away with it.



Really... never noticed anything unusual. Now I want to look when I get home.

Though it's a Sony PVM with a 358 filter enabled so could be why.
Re: Forced VBlank at Line 216
by on (#101351)
qbradq wrote:
tepples wrote:
The sprite 0 hit and nine sprites bits are cleared on line -1 even if rendering is disabled. The only things skipped are resetting the VRAM address (loopy_v = loopy_t) and the dropped dot used for dot crawl realignment.

No scrolling at all. I'm back to my fixed-screen RPG idea that I kept ditching in the past.


Any project web page for this yet? I keep kicking around the idea for something similar to Super Hydlide but have very few single screen RPGs to reference for ideas. It'd be interesting to see what your take on the sub-genre is.
Re: Forced VBlank at Line 216
by on (#101354)
Well it's not a single-screen RPG in the sense of Hydlide. It uses a fixed display but the map scrolls (in metatile increments) within the display window.

So I've done some experimentation and numbers, and if I try to do it 100% in vblank I can get a maximum of 15 FPS while using over 4KB of code space, or 10 FPS using about 2KB of code space. The issue with these approaches is the input delay. Even though you're getting 15 frames per second you're still waiting 2/15th's of a second before what you did displays on the screen. That may not sound too bad for a turn-based game but in practice it's very noticeable and annoying. That's exactly what I was trying to avoid.

Well anyway, I just found the source code to the zeldroidvania project I was working on. I think I'll go look at that some more :D
Re: Forced VBlank at Line 216
by on (#101357)
Why must the map scroll within a window with a side border, as opposed to a window across the full width of the screen?
Re: Forced VBlank at Line 216
by on (#101361)
Because I'm too lazy to implement 4-directional scrolling :D

Really it's just because I was trying to reproduce the aesthetic of a game built for another platform. If I ever try to produce a game in this genre (tactical RPG with light puzzle solving) I'll do it like Ultima 3.
Re: [Solved] Forced VBlank at Line 216
by on (#101400)
I got this nailed down now. I'm using MMC3's scanline IRQ to disable the display after line 200. I get about 58 scanlines worth of PPU updates in, enough to transfer the entire 32x24 area of the name table I want to use and the attributes and sprite DMA in two frames, and I'm not even having to use unrolled code. The timing is very tight on the first pass, but it works :D

The best part is that the lag is much lower. Best-case is a one frame delay between user input and display, worst-case is three frames. Three frames in a turn-based RPG shouldn't be noticeable.

The only thing that bugs me is that the image is not vertically centered on the screen. See attachment. I could get it down maybe another 10 or 12 scanlines, would look pretty OK, but it'd take unrolled code (like 4KB) and at this point I don't really care that much :D

Another plus is that now that I'm using MMC3 I've got tons of ROM space for data and CHR-ROM, and I can make a test cart out of Kirby's Adventure :P

Edit: The design of the game is such that sprites will never extend past line 192, so that takes care of the OAM corruption issue.
Re: [Solved] Forced VBlank at Line 216
by on (#101402)
qbradq wrote:
I'm using MMC3's scanline IRQ to disable the display after line 200.

Any particular reason why you gave up on the sprite 0 hit and decided to use mapper IRQs? What you're doing now would work just fine with sprite 0 hits too, as long as your frame calculations don't go past scanline 200. Actually, the worst that would happen in case the game logic takes longer than 200 scanlines is you'd miss an opportunity for performing VRAM transfers, effectively causing slow down, but that would probably happen with MMC3 too, because when the IRQ fires and the game logic is not done (meaning the state of VRAM buffers is unknown) you still can't perform video updates.

Quote:
I can make a test cart out of Kirby's Adventure :P

Noooooo! Come on, there are so many crappy MMC3 games, why must you destroy one of the better ones?
Re: [Solved] Forced VBlank at Line 216
by on (#101403)
Yeah, destroy Home Alone. You even get 8K of WRAM with that.
Re: [Solved] Forced VBlank at Line 216
by on (#101404)
I chose to ditch the Sprite 0 hit just so it's more general-purpose. I don't have to be so careful when I'm doing visual effects to make sure there's a non-0 pixel in the right spot, or adjust the sprite location, etc.

Good point about the cart. I don't like Deja Vu and I've got two copies of it :D Kirby's Adventure is a pretty fun game. It'd be like killing a Mega Man 2 cart.

Home Alone doesn't have a battery built in, and I don't feel like hacking one onto a board without one. I'll be doing enough hacking putting a ZIF socket on the thing :D

Thanks for everyone's input! I should have a simple demo to share next week.