@@ -679,6 +679,12 @@ namespace platf {
679679
680680 kms::print (plane.get (), fb.get (), crtc.get ());
681681
682+ if (crtc->mode .clock && crtc->mode .htotal && crtc->mode .vtotal ) {
683+ vblank_period = std::chrono::nanoseconds (
684+ (int64_t )(1e9 * crtc->mode .htotal * crtc->mode .vtotal / ((double ) crtc->mode .clock * 1000.0 )));
685+ } else {
686+ vblank_period = delay;
687+ }
682688 img_width = fb->width ;
683689 img_height = fb->height ;
684690 img_offset_x = crtc->x ;
@@ -1104,6 +1110,7 @@ namespace platf {
11041110 mem_type_e mem_type;
11051111
11061112 std::chrono::nanoseconds delay;
1113+ std::chrono::nanoseconds vblank_period; // display refresh period from CRTC mode
11071114
11081115 int img_width, img_height;
11091116 int img_offset_x, img_offset_y;
@@ -1172,18 +1179,13 @@ namespace platf {
11721179 vbl.request .type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | (crtc_index << DRM_VBLANK_HIGH_CRTC_SHIFT));
11731180 vbl.request .sequence = 1 ;
11741181 if (drmWaitVBlank (card.fd .el , &vbl) == 0 ) {
1175- // DRM vblank time is CLOCK_MONOTONIC, same as steady_clock on Linux
11761182 auto vblank_time = std::chrono::seconds (vbl.reply .tval_sec ) + std::chrono::microseconds (vbl.reply .tval_usec );
11771183 vblank_timestamp = std::chrono::steady_clock::time_point (std::chrono::duration_cast<std::chrono::steady_clock::duration>(vblank_time));
11781184
1179- // Skip frame if display Hz > client FPS (e.g., 120Hz display, 60fps stream)
1180- if (*vblank_timestamp < next_frame) {
1185+ if (*vblank_timestamp < next_frame && next_frame - *vblank_timestamp > vblank_period / 2 ) {
11811186 continue ;
11821187 }
1183- next_frame += delay;
1184- if (next_frame < *vblank_timestamp) {
1185- next_frame = *vblank_timestamp + delay;
1186- }
1188+ next_frame = *vblank_timestamp + delay;
11871189 } else {
11881190 // Vblank wait failed, fall back to timer-based delay
11891191 auto now = std::chrono::steady_clock::now ();
@@ -1435,14 +1437,10 @@ namespace platf {
14351437 auto vblank_time = std::chrono::seconds (vbl.reply .tval_sec ) + std::chrono::microseconds (vbl.reply .tval_usec );
14361438 vblank_timestamp = std::chrono::steady_clock::time_point (std::chrono::duration_cast<std::chrono::steady_clock::duration>(vblank_time));
14371439
1438- // Skip frame if display Hz > client FPS (e.g., 120Hz display, 60fps stream)
1439- if (*vblank_timestamp < next_frame) {
1440+ if (*vblank_timestamp < next_frame && next_frame - *vblank_timestamp > vblank_period / 2 ) {
14401441 continue ;
14411442 }
1442- next_frame += delay;
1443- if (next_frame < *vblank_timestamp) {
1444- next_frame = *vblank_timestamp + delay;
1445- }
1443+ next_frame = *vblank_timestamp + delay;
14461444 } else {
14471445 // Vblank wait failed, fall back to timer-based delay
14481446 auto now = std::chrono::steady_clock::now ();
0 commit comments