From vice-emu
Jump to navigation Jump to search

Interlace emulation in vice (WIP page)

The following emulated chips can output interlace:

  • VDC (C128)
  • VIC (VIC20 - NTSC only))
  • CRTC (PET)
  • VICIIe via timing tricks(C128)
  • ?

Actually implemented (AFAIK)

  • VDC (3.3 release)

Current Problems

  • Aside from VDC no other chips support interlace at all
  • Renderers don't support interlace at all
  • Interlace effectively doubles the output resolution but we don't support this in any way
  • There is no vertical offsetting of the alternate fields so they just overwrite each other every frame resulting in a lot of flicker

Possible Solutions

My suggestion is that we modify the renderers as follows:

1x1 renderers

No change as there's no scope here to increase the resolution

1x2 renderers (default for VDC) & 2x4 renderers (default for VDC with double size)

Make these renderers "Interlace aware" by knowing if the current output is a) interlaced and b) if the current field is even or odd

If the output is interlaced then because these renderers are outputting 2 lines for every input raster line, we modify them so that:

  • when drawing an even field they draw each raster line at the top of each line pair with a black line below it. This is exactly what we do now (without doublescan).
  • when drawing odd fields they draw it at the bottom of each line pair with a black line above.

This effectively doubles the resolution as needed for interlace and correctly positions each field vertically.

That kind of assumes doublescan is disabled. I suggest that when interlace is enabled that doublescan becomes irrelevant and is ignored.

If we just do the above then we will have an interlaced output which will still flicker but the resolution will now be correct and the fields will be displayed with the correct offset.

The other thing to consider is handling the previous field and blending it with the new one to eliminate the flicker (de-interlacing effectively) This depends on whether the target buffer we are rendering to contains the previous frame.

  • If it does then only draw the new field lines in their appropriate position. This will result in a flicker free output
  • If the previous frame is accessible in a readable way (e.g. if we are double buffering and can access the alternate buffer) then we could read the previous fields from the last frame and copy them into the new frame in the appropriate position, as well as the new current field.
  • If the target buffer doesn't contain the previous frame and the previous frame is not accessible then we will just have a flickering output but that's still better than nothing.

CRT renderers

My initial thoughts are that if we can blend with the previous field, that we darken the previous field to emulate the phosphor decay of a CRT. This could be done efficiently by right shifting the RGB values or if the output is YUV right shifting the Y (luminance) component to halve the brightness of the previous field.

On modern hardware there are probably much faster ways using alpha blending of the 2 fields.

Random Implementation info

  • As above VDC is the only chip that attempts to actually interlace it's output so is the only candidate for testing anything
  • Testprog - load testprogs/vdc/vdcattr/vdcattr.prg in x128 and hit "i" for interlace test. There's a screenshot in the same folder of roughly expected output. e.g. the bottom half of screen being garbage is expected.
  • The interlace and current field is in VDC struct as follows:
    • vdc.interlace is a flag as to whether we are interlaced or not
    • the current field is not directly available but can be obtained by calculating (vdc.frame_counter & 1) - if that's zero you are in an even frame, if 1 an odd frame

vdc.c could be easily updated to put those 2 bits of info into the raster or canvas structures or wherever they are best accessed by the render code.

  • I can see that the video canvas is passed through to at least video_canvas_render() in src/video/video-canvas.c which suggests that might be where it belongs. It's accesible from vdc.c via vdc.raster.canvas