- This is something I have to test on the real Intellivision. With the emulator on this machine, JZintv, drops 1%-2% of frames. And block copy is probably the most cycle intensive part of the frame. And I'm unsure how much cpu cycle is left before wait on that frame, and prefer the game to run at 60fps if possible. I did some technique that let me guess where the beam is at by writing to the border color before wait and after wait. After a wait, I used border 0, then before the wait I used border 4. If the border doesn't flash, it means that the intellivision is still drawing the screen and deny the write to the register.
It doesn't necessarily have to be the scrolling skipping (I just checked in the debugger, and STIC writes are not dropped except when moving many sprites on screen -- and that was clearing the collision register of MOB #0, so that's not it). It is most likely screen "tearing" which occurs when the copy block does not stay ahead of the STIC pre-fetch to draw the frame.
As you know (but for the benefit of others) the scrolling mechanic works like this:
- Every frame you shift then screen by one pixel via the "horizontal/vertical delay" register of the STIC.
- When you have shifted 8 pixels, an entire column/row has been moved, so...
- you draw a new column/row on the appropriate edge,
- and shift the entire screen one card in the direction of scrolling.
- You then reset the horizontal/vertical delay register to zero and start again with step #1.
Concurrently, the STIC drawing of the screen works like this:
- On every Vertical Blank (VBLANK) period of the TV raster, it interrupts the CPU giving it a chance to update the STIC and graphics memory. This "VBLANK Period" is divided into two:
- VBLANK 1 - in which the CPU gets access to the graphics bus and the STIC registers. We normally update MOB, Scroll, and other STIC registers here.
- VBLANK 2 - in which the CPU still has access to the graphics bus, but not to the STIC itself. We normally update GRAM here.
- Right after VBLANK 2 completes, the CPU starts "pre-fetching" card data from the BACKTAB and populating its FIFO which ultimately will be used to guide the raster.
- This pre-fetching is done periodically through active display, and is done from top-to-bottom, left-to-right, i.e., in BACKTAB address order.
The trick to smooth scrolling is to get your horizontal/vertical delay updates (step #1 in scrolling algorithm above) during VBLANK 1, and to keep your screen shifts (step #2 in scrolling algorithm above) ahead of the pre-fetching requests of the STIC. If you let the STIC overrun you, the updated BACKTAB will not make it to the next frame, and will instead have to wait an entire other frame.
In practice, there should be plenty of time, since copy loops are much faster than the interval of BUSRQ pre-fetching interrupts. The critical thing is to start as early as possible so that you can stay ahead. Once you have that lead, you're probably safe, but if you miss it -- even if you catch up -- you would have missed the updating of some BACKTAB cards.
Note that we're not talking about the BACKTAB not getting updated. The updates happen as you do them (unlike GRAM when you miss the VBLANK window). We're merely talking about those updates making it to the next frame sent to the TV raster. Missing the pre-fetch means that the old data would be used for those cards when drawing the next frame.
As you may imagine, this results in the screen either "jumping" between frames, or in "tearing" when some parts belong to the new frame and others to the old frame.
This is why IntyBASIC reserves 20 cards for scrolling, even if you are scrolling horizontally: in order to draw the top row as quickly as possible and stay ahead of the BUSRQ pre-fetch requests.
All that said, I also recommend you test your game on the Intellivision just to rule out any jzIntv quirks or PC-induced latency. This is usually a hard problem to troubleshoot. In my experience, the best way to handle this is to have as much stuff pre-calculated on a previous frame, and make sure to optimize the top of your game loop (i.e., after calling WAIT) to do all it needs to do. Critical stuff are, in order:
- MOB registers
- Scroll registers
- GRAM updates
- Scroll screen shifts
The first two must be done at the tipity-top, there's no way around it; you need VBLANK 1 for that. The last two need to be coordinated so that your graphics and background can be updated adequately with minimal impact. Who has priority depends on your preference, but if there are not enough cycles to do both, you'll have to be aware that one will be affected.
P.S. To intvnut and other experts: I wrote the above from memory with the best of intentions to simplify the very technical aspects of the issue and help programmers deal with smooth scrolling. If I got something wrong or inaccurate, please let me know so that I can correct it.
Edited by DZ-Jay, Sat Jul 7, 2018 6:59 AM.