diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index d4ba085d0..e040c05cc 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -293,6 +293,7 @@ struct drm_mode { struct weston_mode base; drmModeModeInfo mode_info; uint32_t blob_id; + uint8_t vic; }; enum drm_fb_type { diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c index ab0ce11f1..472b2469d 100644 --- a/libweston/backend-drm/modes.c +++ b/libweston/backend-drm/modes.c @@ -100,6 +100,27 @@ drm_to_weston_mode_aspect_ratio(uint32_t drm_mode_flags) } } +static enum di_cta_video_format_picture_aspect_ratio +drm_to_cta_aspect_ratio(uint32_t drm_mode_flags, bool *valid) +{ + *valid = true; + + switch (drm_mode_flags & DRM_MODE_FLAG_PIC_AR_MASK) { + case DRM_MODE_FLAG_PIC_AR_4_3: + return DI_CTA_VIDEO_FORMAT_PICTURE_ASPECT_RATIO_4_3; + case DRM_MODE_FLAG_PIC_AR_16_9: + return DI_CTA_VIDEO_FORMAT_PICTURE_ASPECT_RATIO_16_9; + case DRM_MODE_FLAG_PIC_AR_64_27: + return DI_CTA_VIDEO_FORMAT_PICTURE_ASPECT_RATIO_64_27; + case DRM_MODE_FLAG_PIC_AR_256_135: + return DI_CTA_VIDEO_FORMAT_PICTURE_ASPECT_RATIO_256_135; + case DRM_MODE_FLAG_PIC_AR_NONE: + default: + *valid = false; + return DI_CTA_VIDEO_FORMAT_PICTURE_ASPECT_RATIO_4_3; + } +} + static const char * aspect_ratio_to_string(enum weston_mode_aspect_ratio ratio) { @@ -509,6 +530,85 @@ drm_refresh_rate_mHz(const drmModeModeInfo *info) return refresh; } +static bool +drmmodeinfo_is_fmt(const drmModeModeInfo *info, + const struct di_cta_video_format *fmt) +{ + int vfront = info->vsync_start - info->vdisplay; + int vsync = info->vsync_end - info->vsync_start; + int vback = info->vtotal - info->vsync_end; + int hfront = info->hsync_start - info->hdisplay; + int hsync = info->hsync_end - info->hsync_start; + int hback = info->htotal - info->hsync_end; + uint32_t fmt_clock_khz = fmt->pixel_clock_hz / 1000; + enum di_cta_video_format_sync_polarity hpol, vpol; + bool interlaced = !!(info->flags & DRM_MODE_FLAG_INTERLACE); + enum di_cta_video_format_picture_aspect_ratio info_ar; + bool valid_ar; + + if (info->flags & DRM_MODE_FLAG_PHSYNC) + hpol = DI_CTA_VIDEO_FORMAT_SYNC_POSITIVE; + else if (info->flags & DRM_MODE_FLAG_NHSYNC) + hpol = DI_CTA_VIDEO_FORMAT_SYNC_NEGATIVE; + else + return false; + + if (info->flags & DRM_MODE_FLAG_PVSYNC) + vpol = DI_CTA_VIDEO_FORMAT_SYNC_POSITIVE; + else if (info->flags & DRM_MODE_FLAG_NVSYNC) + vpol = DI_CTA_VIDEO_FORMAT_SYNC_NEGATIVE; + else + return false; + + info_ar = drm_to_cta_aspect_ratio(info->flags, &valid_ar); + if (!valid_ar) + return false; + + /* The clock match is imprecise because it's already rounded off + * in drmModeModeInfo. + */ + if (info->hdisplay != fmt->h_active || + info->vdisplay != fmt->v_active || + hfront != fmt->h_front || + vfront != fmt->v_front || + hsync != fmt->h_sync || + vsync != fmt->v_sync || + hback != fmt->h_back || + vback != fmt->v_back || + info->clock != fmt_clock_khz || + hpol != fmt->h_sync_polarity || + vpol != fmt->v_sync_polarity || + interlaced != fmt->interlaced || + info_ar != fmt->picture_aspect_ratio) + return false; + + return true; +} + +static int +match_cta_mode(const drmModeModeInfo *info) +{ + const struct di_cta_video_format *fmt; + uint8_t vic; + + /* FIXME: Some day we'll probably get this from libdi high- + * level api, but for now we kludge it here. + * + * The stop at 219 works around an off by one bug in some + * releases of libdi, and needs to be 255 when we can + * bump version to ensure the fix. + */ + for (vic = 0; vic < 220; vic++) { + fmt = di_cta_video_format_from_vic(vic); + if (!fmt) + continue; + assert(fmt->vic == vic); + if (drmmodeinfo_is_fmt(info, fmt)) + return vic; + } + return 0; +} + /** * Add a mode to output's mode list * @@ -536,6 +636,8 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info) mode->mode_info = *info; mode->blob_id = 0; + mode->vic = match_cta_mode(info); + if (info->type & DRM_MODE_TYPE_PREFERRED) mode->base.flags |= WL_OUTPUT_MODE_PREFERRED; @@ -583,7 +685,12 @@ drm_output_print_modes(struct drm_output *output) dm = to_drm_mode(m); aspect_ratio = aspect_ratio_to_string(m->aspect_ratio); - weston_log_continue(STAMP_SPACE "%s@%.1f%s%s%s, %.1f MHz\n", + if (dm->vic) + weston_log_continue(STAMP_SPACE "VIC %3d, ", dm->vic); + else + weston_log_continue(STAMP_SPACE " "); + + weston_log_continue("%s@%.1f%s%s%s, %.1f MHz\n", dm->mode_info.name, m->refresh / 1000.0, aspect_ratio, m->flags & WL_OUTPUT_MODE_PREFERRED ?