video: take Scanline Sync's visible line count from the display mode

The blanking arithmetic used video_st->height as the display's visible
line count. That field is the output window's height, set by
video_driver_set_output_size(), and it equals the display's visible
lines only in fullscreen at native resolution. Anywhere else the aim
is nonsense: a 1080p window on a 2250-line panel computes 1170 lines
of "blanking" and centres the target inside it. The assumption was
inherited from the previous implementation, but this series built the
aim on it without checking.

Read the mode height from the display server at calibration instead,
falling back to the window height only when the server cannot report a
mode. Stored alongside total and period since all three describe the
display and are re-measured together on reinit.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-09-02 05:14:08 +02:00
1 parent 985debc1a4
commit c993b7ac34
1 file changed
+21 -2
+21 -2
View File
@@ -6330,6 +6330,7 @@ typedef struct
double anchor_us; /* time of the last observed vblank */
unsigned anchor_age; /* frames since anchor_us was refreshed */
int total; /* lines including blanking */
int visible; /* lines the display shows; from the mode */
bool locked;
unsigned misses; /* frames that could not make their target */
int target; /* last aim point, clamped frame to frame */
@@ -6391,6 +6392,24 @@ static bool scanline_pll_calibrate(void)
scl_pll.period_us = acc / (double)n;
scl_pll.line_us = scl_pll.period_us / (double)scl_pll.total;
/* The visible line count is the display mode's height, not the
* output window's. video_st->height is the window - it coincides
* with the mode only in fullscreen at native resolution, and the
* blanking arithmetic below is nonsense otherwise: a 1080p window on
* a 2250-line panel would report 1170 lines of blanking. Ask the
* display server for the mode, and fall back to the window only if
* it cannot say. */
{
unsigned w = 0, h = 0;
char unused[8];
if ( video_display_server_get_video_output_size(&w, &h,
unused, sizeof(unused))
&& h > 0 && (int)h < scl_pll.total)
scl_pll.visible = (int)h;
else
scl_pll.visible = (int)video_state_get_ptr()->height;
}
/* Residual offset: predict at a fixed delay and compare with a real
* sample. Averaged rather than medianed to keep this short; the
* jitter is 6-12 lines so the mean is close enough for an offset
@@ -6566,8 +6585,8 @@ VIDEO_NOINLINE static void video_driver_scanline_before_frame(video_driver_state
* the next as well. A sustained change still converges in a few
* frames. */
{
int blank = scl_pll.total - (int)video_st->height;
int centre = (int)video_st->height + (blank > 0 ? blank / 2 : 0);
int blank = scl_pll.total - scl_pll.visible;
int centre = scl_pll.visible + (blank > 0 ? blank / 2 : 0);
int want = centre
- (int)(scl_pll.work_us / scl_pll.line_us)
+ config_get_ptr()->ints.video_scanline_sync_offset;