One of my recent projects was to get my PC to output 480i signals to my recently acquired Trinitron TV for running modern and historical games on a CRT TV (I'd definitely be better served by a monitor, but I didn't have one and still don't :( ). I learned many interesting but otherwise-irrelevant bits of trivia from this experience:

- A modeline used to output 480i SDTV-compatible signals (525 scanlines) from a PC, differs from the same resolution's modeline under Coordinated Video Timings (arachnoid.com generates a 516-line modeline for 480i, and Linux's cvt tool doesn't document its interlacing flag because interlacing is not part of VGA or something).

- DVI and HDMI signals are effectively continuous signals with CRT-like timings, translated into digital signals (discrete-time at your GPU's configured dot clock, and quantized) and encoded using TMDS with special pixel values on the blue channel (outside of the 0-255 range) for hblank and vblank. Whereas DP signals are packetized in some manner I haven't researched.

- One common way to output 480i is through HDMI-to-component converters. But 480i has a too low pixel clock below the HDMI spec's minimum timing, and many GPUs cannot put out such a slow signal or converters cannot understand it. (I wonder how DP-to-component would fare, given it's packet-based and might not suffer from a minimum dot clock readable by the receiver chip.) A common workaround recommended by the developers "CRT Emudriver" (AMD GPU drivers modded by in-place binary patching) is to set a 2560x240p or 480i "super resolution", then configure emulators and games to output stretched signals. Unfortunately, neither non-RetroArch games nor Windows's CRT Emudriver cannot rescale their image to non-square pixels and their 1440x480 images were squashed to a 4:3 aspect ratio, so I had to switch to Linux and xrandr for square images.

- I had to pick 1440x480i because otherwise the vblank pulses generated by my AliExpress HDMI-to-component converter were insufficiently staggered between interlaced and non-interlaced scanlines. Since I don't have an oscilloscope, I diagnosed this by piping the sync-on-green composite signal into my motherboard's 192khz line-in capture, then recording in Audacity and comparing to correct NTSC timings (the vertical serrations should be evenly spaced and they weren't).

- The Linux amdgpu driver is well capable of outputting a 1440x240p resolution (there are many NTSC modelines, with varying undesirable horizontal offsets and stretching, and vertical offsets), and xrandr is an excellent way to scale a 1280x960 framebuffer to 1440x240 or such (which is scaled back to square aspect ratio on-screen). Unfortunately Linux amdgpu's dc driver for its display controller (compatible with atomic modesetting) has missing support for interlacing, the easiest workaround being to pass `amdgpu.dc=0` to the Linux kernel command line (this disables atomic modesetting, switches to the legacy display controller driver, breaks HDMI audio, and makes the mouse cursor unaffected by Redshift so Plasma's text cursor becomes practically invisible on white text fields).

- - I debugged this extensively at https://gitlab.freedesktop.org/drm/amd/-/issues/1636, but failed to solve the problem. If I hack the driver to force interlacing on (not realizing I needed interleaving as well), the resulting analog signal repeats the first scanline hundreds of times followed by a birth-defect serration pulse, which I would be unsurprised if it would physically destroy some CRTs. I recorded a video (epilepsy warning) at https://www.youtube.com/watch?v=GoQ9q1lwKHI.

- - Antonio Giner claims to have a fix for interlacing in amdgpu.dc=1 mode, for his GroovyArcade arcade CRT distribution, but it's not upstreamed, it doesn't currently work on my GPU, and I never did get around to porting it to my older RX 570, finding the correct modeline, and testing that it works. Turns out modern games like Stray aren't optimized for interlaced displays (vsync caused horrendous input lag) or 480-line-tall screens (HUD elements and jump prompts are too small to see), who would've known! I do think Celeste would work fairly well in 240p mode, but I haven't gotten around to testing that either (in either amdgpu.dc=0 or porting my patch).

- Compensating for CRT television overscan (since modern games like Stray draw HUD elements like jump prompts right on the edge of the screen) is a nightmare. On amdgpu, xrandr's underscan option can only take off <=128 pixels evenly split between the left and right, or the top and bottom. Worse yet, the display controller outputs eg. 1340x460 of non-black image, by downscaling (in hardware?) a second time from the 1440x480 framebuffer downscaled in software from 1280x960, creating unnecessary vertical blur.

- - Since I don't know how to perform both downscaling steps in hardware with unmodified amdgpu drivers (like a non-square-pixel VSR), I opted to perform both downscaling steps in software, by writing a shell script to kill plasmashell and open a full-screen mpv showing a black .png file on a 1440x1030 framebuffer, then use KWin rules to overlay a 1280x960 borderless window of Stray at a precise position over mpv (with black mpv borders on all 4 sides), use xrandr to downscale 1440x1030 to 1440x480i, then kill mpv once Stray exits. It's a terrible setup and I wish there was a better way. But CRTs and overscan is dead, interlacing is dead, 640x480 is dead, and only a fool or experimenter (or someone with complex-trauma depression seeking comfort in nostalgia and cats) would try hooking up modern computers and games to triply-dead CRT SDTVs and expecting them to work.