Interlace mode (LSMx=3)

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Near
Very interested
Posts: 109
Joined: Thu Feb 28, 2008 4:45 pm

Re: Interlace mode (LSMx=3)

Post by Near » Tue Aug 22, 2017 7:34 am

Pretty sure there should be a thick line of background color at the split (about four scanlines or so (forgot the exact amount), since that's how long it takes to reload the whole sprite table with forced blanking). Seems to match the area that is broken.
Then the video I watched was probably from a bad emulator recording. But well, sprite fetching or not, that's background tile data in the middle of the screen, so it's unclear why there'd be four full black lines.

The actual start of the black line's a little off in higan, which is most likely because I have a pixel-based renderer, but start rendering the scanline too early (literally at Hcounter=0) ... that part should be addressed if I ever get FIFO and scanline-timing in properly.
It will work, but the resolution of sprite positioning will be half of what it should be. For instance, you won't be able to position a sprite's first line on a line that's in the bottom field (short of modifying the SAT between fields anyway).
Oh, okay then. For whatever reason, having a mostly working implementation using halving of Vscroll/Y-coords made it way easier for me to adapt the code to doubling Y/height instead. So, that issue's resolved, thanks!
This code is not correct in two ways. First, the weird bit swapping thing happens in both interlace mode (i.e. whenever LSM0=1). Second, double resolution mode (LSMx=3) actually does introduce a new bit 0 to the vcounter and pushes the other bits up one.
Boy, that's super weird for LSMx=1 mode.

So then, how's this?

Code: Select all

  //counter
  case 0xc00008: case 0xc0000a: case 0xc0000c: case 0xc0000e: {
    auto vcounter = state.vcounter;
    if(io.interlaceMode.bit(0)) {
      if(io.interlaceMode.bit(1)) vcounter <<= 1;
      vcounter.bit(0) = vcounter.bit(8);
    }
    return vcounter << 8 | (state.hdot >> 1) << 0;
  }
The return is uint16, so d8 of vcounter gets clipped off in the end, and in LSMx=3, d0 is set to d8.

Maybe I'm doing the d0<>d8 swap late, and it should be before vcounter<<=1 in LSMx=3 mode?
This bit is forced to zero whenever LSM0=0.
... I guessed an emulator behavior correctly? On my first try ...??

Quick, someone check the ground to see if hell just froze over :D

Eke
Very interested
Posts: 884
Joined: Wed Feb 28, 2007 2:57 pm
Contact:

Re: Interlace mode (LSMx=3)

Post by Eke » Tue Aug 22, 2017 8:17 am

Mask of Destiny wrote:
Tue Aug 22, 2017 12:01 am
Eke wrote:
Mon Aug 21, 2017 11:13 pm
What I think you are missing, as far as I can tell:

- for vscroll, value read from VSRAM must be shifted right by one (VSRAM width is 11-bit but bit0 is ignored in interlaced mode 2) before being added to vcounter value (9-bit)

- for sprites, when preparing the sprites list (i.e looking which sprites will be visible on the next line), sprite ypos value read from SAT cache must also be shifted right by one (value is 10-bit but bit0 is ignored) before being compared/substracted to vcounter value (9-bit)
This doesn't seem quite right as it would imply you don't actually have full resolution scrolling/positioning in this mode. Instead, what you probably want to do is multiply the vcounter value by 2 and add 1 if you're on the "lower" field (I'm uncertain as to whether this is the odd or even field though).

If you go this route though, you will have to adjust the coordinate for the top of the screen for sprites (256 instead of 128).
Maybe you are right, I'm not sure, it's just that it's not how it is done in Genesis Plus GX (I do the former method I described) and AFAIK there is no issue or jittering when scrolling (even in Wii port where the interlaced fields are output just like the real thing). Did you verified this theory on real hardware?
It could indeed be 9-bit vcounter value is first shifted left by one and odd/even field added THEN full 11-bit vscroll value is added (or full 10-bit sprite ypos value is substracted). Or maybe just for sprites?
The only remaining issue is that the first few scanlines (4-5 or so) after the screen split seem to be rather glitchy. But that's most likely going to be a much more complicated timing issue =(
[EDIT: actually, Youtube playthroughs seem to indicate it's an issue with the actual game ...? o_O]
The issue occurring on real hardware is a bit different though, it has to do with display being disabled then re-enabled in the middle of the screen and sprite processing being interrupted/restarted consequently. The result is that some sprite pixels from the lower (non-visible) line of the top screen can be visible in the upper line of the bottom screen (especially visible when you make the character jump). This is due to sprites for line N being parsed during line N-1, rendered during HBLANK preceding line N in a 320 pixels-wide sprite buffer and that sprite buffer being emptied in sync with pixel output. When display is disabled, none of these sprite processing steps occur so depending on when this is enabled/disabled, you could still have sprites from another line in the parsed list and in the sprite buffer.
Last question, though ... is this correct for counter read-out? Sonic 2 doesn't use it, and I don't know of any other interlace "mode 2" game.
You can also read this thread which has detailed description of HVcounter values output in various modes.
viewtopic.php?f=22&t=768
So then, how's this?
Seems correct to me.
Here is the similar code I use:

Code: Select all

  /* Interlaced modes */
  if (interlaced)
  {
    /* Interlace mode 2 (Sonic the Hedgehog 2, Combat Cars) */
    vc <<= im2_flag;

    /* Replace bit 0 with bit 8 */
    vc = (vc & ~1) | ((vc >> 8) & 1);
  }

  /* return HCounter in LSB & VCounter in MSB */
  data |= ((vc & 0xff) << 8);

Sik
Very interested
Posts: 939
Joined: Thu Apr 10, 2008 3:03 pm
Contact:

Re: Interlace mode (LSMx=3)

Post by Sik » Tue Aug 22, 2017 8:48 am

byuu wrote:
Tue Aug 22, 2017 7:34 am
Pretty sure there should be a thick line of background color at the split (about four scanlines or so (forgot the exact amount), since that's how long it takes to reload the whole sprite table with forced blanking). Seems to match the area that is broken.
Then the video I watched was probably from a bad emulator recording. But well, sprite fetching or not, that's background tile data in the middle of the screen, so it's unclear why there'd be four full black lines.
The game disables display, loads the sprite table, then reenables display (hence why solid background color should show up instead, it's rendering nothing). For some reason display isn't getting disabled here, otherwise there'd be a thick solid line (not thin) in the middle of the screen.
Sik is pronounced as "seek", not as "sick".

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Re: Interlace mode (LSMx=3)

Post by TmEE co.(TM) » Tue Aug 22, 2017 9:31 am

This is what you're supposed to get :
http://www.tmeeco.eu/SMD/Sonic2interlace0.jpg (shows one field only)
http://www.tmeeco.eu/SMD/Sonic2interlace1.jpg (shows both, yay exposure shenanigans)
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

Mask of Destiny
Very interested
Posts: 615
Joined: Thu Nov 30, 2006 6:30 am

Re: Interlace mode (LSMx=3)

Post by Mask of Destiny » Tue Aug 22, 2017 6:07 pm

Eke wrote:
Tue Aug 22, 2017 8:17 am
Did you verified this theory on real hardware?
I'll run a proper test tonight, but it would be quite bizarre for them to include the hardware necessary to store and use an extra bit on the MSB side if they're just going to discard a bit on the LSB side. The difference in the behavior of the HV counter port between the LSMx=1 and LSMx=3 case is also suggestive.

Mask of Destiny
Very interested
Posts: 615
Joined: Thu Nov 30, 2006 6:30 am

Re: Interlace mode (LSMx=3)

Post by Mask of Destiny » Wed Aug 23, 2017 3:45 am

Test confirms that both vscroll and sprites use the least significant bit in double resolution interlace (LSMx=3) mode. The way it works is that a bar is displayed on Plane A with an even scroll value and a sprite is displayed at that Y+1 (well +257 due to the difference in coordinate system). Further down the same bar is displayed on Plane B with an odd scroll value and a sprite is displayed at that Y-1 (+255 technically as above). In the first case, the sprite starts 1 pixel below the bar and in the second case it's reversed. Here's what it should look like:
Image
Note: I've included a screenshot of BlastEm rather than from hardware because my capture card is garbage, but I have confirmed that hardware behaves the same.

And here's the test ROM: Binary, Source

With some cleverness, it should be possible to make a test that makes it more obvious whether you've got it right, but I was in a bit of a hurry with this.

Post Reply