diff --git a/src/backends/native/meta-kms-utils.c b/src/backends/native/meta-kms-utils.c index 1c58db83d..2289cfa91 100644 --- a/src/backends/native/meta-kms-utils.c +++ b/src/backends/native/meta-kms-utils.c @@ -47,6 +47,27 @@ meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *drm_mode) return numerator / denominator; } +int64_t +meta_calculate_drm_mode_vblank_duration_us (const drmModeModeInfo *drm_mode) +{ + int64_t value; + + if (drm_mode->htotal <= 0 || drm_mode->vtotal <= 0) + return 0; + + /* Convert to int64_t early. */ + value = drm_mode->vtotal - drm_mode->vdisplay; + value *= drm_mode->htotal; + + if (drm_mode->flags & DRM_MODE_FLAG_DBLSCAN) + value *= 2; + + /* Round the duration up as it is used for buffer swap deadline computation. */ + value = (value * 1000 + drm_mode->clock - 1) / drm_mode->clock; + + return value; +} + /** * meta_drm_format_to_string: * @tmp: temporary buffer diff --git a/src/backends/native/meta-kms-utils.h b/src/backends/native/meta-kms-utils.h index c22ceaaa0..2f2bad1f9 100644 --- a/src/backends/native/meta-kms-utils.h +++ b/src/backends/native/meta-kms-utils.h @@ -34,6 +34,9 @@ typedef struct _MetaDrmFormatBuf META_EXPORT_TEST float meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *drm_mode); +META_EXPORT_TEST +int64_t meta_calculate_drm_mode_vblank_duration_us (const drmModeModeInfo *drm_mode); + const char * meta_drm_format_to_string (MetaDrmFormatBuf *tmp, uint32_t drm_format); diff --git a/src/tests/kms-utils-unit-tests.c b/src/tests/kms-utils-unit-tests.c index 324166d68..40b768b3e 100644 --- a/src/tests/kms-utils-unit-tests.c +++ b/src/tests/kms-utils-unit-tests.c @@ -26,9 +26,9 @@ typedef struct { drmModeModeInfo drm_mode; float expected_refresh_rate; -} ModeInfoTestCase; +} RefreshRateTestCase; -static const ModeInfoTestCase test_cases[] = { +static const RefreshRateTestCase refresh_rate_test_cases[] = { /* "cvt 640 480" */ { .drm_mode = { @@ -125,9 +125,9 @@ meta_test_kms_refresh_rate (void) { size_t index; - for (index = 0; index < G_N_ELEMENTS(test_cases); index++) + for (index = 0; index < G_N_ELEMENTS (refresh_rate_test_cases); index++) { - const ModeInfoTestCase *test_case = test_cases + index; + const RefreshRateTestCase *test_case = refresh_rate_test_cases + index; float refresh_rate; refresh_rate = @@ -138,6 +138,105 @@ meta_test_kms_refresh_rate (void) } } +typedef struct +{ + drmModeModeInfo drm_mode; + int64_t expected_vblank_duration_us; +} VblankDurationTestCase; + +static const VblankDurationTestCase vblank_duration_test_cases[] = { + /* "cvt 640 480" */ + { + .drm_mode = { + .clock = 23975, + .hdisplay = 640, + .hsync_start = 664, + .hsync_end = 720, + .htotal = 800, + .vdisplay = 480, + .vsync_start = 483, + .vsync_end = 487, + .vtotal = 500, + .vscan = 0, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC, + }, + .expected_vblank_duration_us = 668, + }, + + /* "cvt 640 480" with htotal 0 */ + { + .drm_mode = { + .clock = 23975, + .hdisplay = 640, + .hsync_start = 664, + .hsync_end = 720, + .htotal = 0, + .vdisplay = 480, + .vsync_start = 483, + .vsync_end = 487, + .vtotal = 500, + .vscan = 0, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC, + }, + .expected_vblank_duration_us = 0, + }, + + /* "cvt 640 480" with vtotal 0 */ + { + .drm_mode = { + .clock = 23975, + .hdisplay = 640, + .hsync_start = 664, + .hsync_end = 720, + .htotal = 800, + .vdisplay = 480, + .vsync_start = 483, + .vsync_end = 487, + .vtotal = 0, + .vscan = 0, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC, + }, + .expected_vblank_duration_us = 0, + }, + + /* "cvt 640 480" with DBLSCAN */ + { + .drm_mode = { + .clock = 23975, + .hdisplay = 640, + .hsync_start = 664, + .hsync_end = 720, + .htotal = 800, + .vdisplay = 480, + .vsync_start = 483, + .vsync_end = 487, + .vtotal = 500, + .vscan = 0, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_DBLSCAN, + }, + .expected_vblank_duration_us = 1335, + }, +}; + +static void +meta_test_kms_vblank_duration (void) +{ + size_t index; + + for (index = 0; index < G_N_ELEMENTS (vblank_duration_test_cases); index++) + { + const VblankDurationTestCase *test_case = vblank_duration_test_cases + index; + int64_t vblank_duration_us; + + vblank_duration_us = + meta_calculate_drm_mode_vblank_duration_us (&test_case->drm_mode); + g_assert_cmpint (vblank_duration_us, + ==, + test_case->expected_vblank_duration_us); + } +} + static void meta_test_kms_update_fixed16 (void) { @@ -152,6 +251,8 @@ init_kms_utils_tests (void) { g_test_add_func ("/backends/native/kms/refresh-rate", meta_test_kms_refresh_rate); + g_test_add_func ("/backends/native/kms/vblank-duration", + meta_test_kms_vblank_duration); g_test_add_func ("/backends/native/kms/update/fixed16", meta_test_kms_update_fixed16); }