diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index 04ffcf4eb..460c789ea 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -160,6 +160,9 @@ struct _MetaCRTC gboolean is_dirty; MetaCursorReference *cursor; + + gpointer driver_private; + GDestroyNotify driver_notify; }; struct _MetaMonitorMode diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 4ebe80021..90eba4805 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -264,6 +264,21 @@ meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes, g_free (old_modes); } +static void +meta_monitor_manager_free_crtc_array (MetaCRTC *old_crtcs, + int n_old_crtcs) +{ + int i; + + for (i = 0; i < n_old_crtcs; i++) + { + if (old_crtcs[i].driver_notify) + old_crtcs[i].driver_notify (&old_crtcs[i]); + } + + g_free (old_crtcs); +} + static void meta_monitor_manager_finalize (GObject *object) { @@ -271,8 +286,8 @@ meta_monitor_manager_finalize (GObject *object) meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs); meta_monitor_manager_free_mode_array (manager->modes, manager->n_modes); + meta_monitor_manager_free_crtc_array (manager->crtcs, manager->n_crtcs); g_free (manager->monitor_infos); - g_free (manager->crtcs); G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object); } @@ -1199,23 +1214,24 @@ meta_monitor_manager_read_current_config (MetaMonitorManager *manager) MetaOutput *old_outputs; MetaCRTC *old_crtcs; MetaMonitorMode *old_modes; - unsigned int n_old_outputs, n_old_modes; + unsigned int n_old_outputs, n_old_crtcs, n_old_modes; /* Some implementations of read_current use the existing information * we have available, so don't free the old configuration until after * read_current finishes. */ old_outputs = manager->outputs; n_old_outputs = manager->n_outputs; + old_crtcs = manager->crtcs; + n_old_crtcs = manager->n_crtcs; old_modes = manager->modes; n_old_modes = manager->n_modes; - old_crtcs = manager->crtcs; manager->serial++; META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager); meta_monitor_manager_free_output_array (old_outputs, n_old_outputs); meta_monitor_manager_free_mode_array (old_modes, n_old_modes); - g_free (old_crtcs); + meta_monitor_manager_free_crtc_array (old_crtcs, n_old_crtcs); } void diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index a756b8621..999a8980a 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -57,6 +57,12 @@ typedef struct { uint32_t edid_blob_id; } MetaOutputKms; +typedef struct { + uint32_t underscan_prop_id; + uint32_t underscan_hborder_prop_id; + uint32_t underscan_vborder_prop_id; +} MetaCRTCKms; + struct _MetaMonitorManagerKms { MetaMonitorManager parent_instance; @@ -137,6 +143,12 @@ meta_monitor_mode_destroy_notify (MetaMonitorMode *output) g_slice_free (drmModeModeInfo, output->driver_private); } +static void +meta_crtc_destroy_notify (MetaCRTC *crtc) +{ + g_free (crtc->driver_private); +} + static gboolean drm_mode_equal (gconstpointer one, gconstpointer two) @@ -181,29 +193,54 @@ drm_mode_hash (gconstpointer ptr) } static void -find_properties (MetaMonitorManagerKms *manager_kms, - MetaOutputKms *output_kms) +find_connector_properties (MetaMonitorManagerKms *manager_kms, + MetaOutputKms *output_kms) { - drmModePropertyPtr prop; int i; for (i = 0; i < output_kms->connector->count_props; i++) { - prop = drmModeGetProperty (manager_kms->fd, output_kms->connector->props[i]); + drmModePropertyPtr prop = drmModeGetProperty (manager_kms->fd, output_kms->connector->props[i]); if (!prop) continue; - if ((prop->flags & DRM_MODE_PROP_ENUM) && - strcmp(prop->name, "DPMS") == 0) + if ((prop->flags & DRM_MODE_PROP_ENUM) && strcmp (prop->name, "DPMS") == 0) output_kms->dpms_prop_id = prop->prop_id; - else if ((prop->flags & DRM_MODE_PROP_BLOB) && - strcmp (prop->name, "EDID") == 0) + else if ((prop->flags & DRM_MODE_PROP_BLOB) && strcmp (prop->name, "EDID") == 0) output_kms->edid_blob_id = output_kms->connector->prop_values[i]; drmModeFreeProperty (prop); } } +static void +find_crtc_properties (MetaMonitorManagerKms *manager_kms, + MetaCRTC *meta_crtc) +{ + MetaCRTCKms *crtc_kms; + drmModeObjectPropertiesPtr props; + size_t i; + + crtc_kms = meta_crtc->driver_private; + + props = drmModeObjectGetProperties (manager_kms->fd, meta_crtc->crtc_id, DRM_MODE_OBJECT_CRTC); + for (i = 0; i < props->count_props; i++) + { + drmModePropertyPtr prop = drmModeGetProperty (manager_kms->fd, props->props[i]); + if (!prop) + continue; + + if ((prop->flags & DRM_MODE_PROP_ENUM) && strcmp (prop->name, "underscan") == 0) + crtc_kms->underscan_prop_id = prop->prop_id; + else if ((prop->flags & DRM_MODE_PROP_RANGE) && strcmp (prop->name, "underscan hborder") == 0) + crtc_kms->underscan_hborder_prop_id = prop->prop_id; + else if ((prop->flags & DRM_MODE_PROP_RANGE) && strcmp (prop->name, "underscan vborder") == 0) + crtc_kms->underscan_vborder_prop_id = prop->prop_id; + + drmModeFreeProperty (prop); + } +} + static GBytes * read_output_edid (MetaMonitorManagerKms *manager_kms, MetaOutput *output) @@ -417,6 +454,10 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager) meta_crtc = &manager->crtcs[i]; + meta_crtc->driver_private = g_new (MetaCRTCKms, 1); + meta_crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify; + find_crtc_properties (manager_kms, meta_crtc); + meta_crtc->crtc_id = crtc->crtc_id; meta_crtc->rect.x = crtc->x; meta_crtc->rect.y = crtc->y; @@ -567,7 +608,7 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager) meta_output->is_presentation = FALSE; } - find_properties (manager_kms, output_kms); + find_connector_properties (manager_kms, output_kms); edid = read_output_edid (manager_kms, meta_output); meta_output_parse_edid (meta_output, edid); @@ -723,8 +764,9 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, if (output_kms->dpms_prop_id != 0) { - int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->winsys_id, - output_kms->dpms_prop_id, state); + int ok = drmModeObjectSetProperty (manager_kms->fd, meta_output->winsys_id, + DRM_MODE_OBJECT_CONNECTOR, + output_kms->dpms_prop_id, state); if (ok < 0) meta_warning ("Failed to set power save mode for output %s: %s\n", @@ -748,6 +790,48 @@ crtc_free (CoglKmsCrtc *crtc) g_slice_free (CoglKmsCrtc, crtc); } +static void +set_underscan (MetaMonitorManagerKms *manager_kms, + MetaOutput *output) +{ + if (!output->crtc) + return; + + MetaCRTC *crtc = output->crtc; + MetaCRTCKms *crtc_kms = crtc->driver_private; + if (!crtc_kms->underscan_prop_id) + return; + + if (output->is_underscanning) + { + drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, + crtc_kms->underscan_prop_id, (uint64_t) 1); + + if (crtc_kms->underscan_hborder_prop_id) + { + uint64_t value = crtc->current_mode->width * 0.05; + drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, + crtc_kms->underscan_hborder_prop_id, value); + } + if (crtc_kms->underscan_vborder_prop_id) + { + uint64_t value = crtc->current_mode->height * 0.05; + drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, + crtc_kms->underscan_vborder_prop_id, value); + } + + } + else + { + drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, + crtc_kms->underscan_prop_id, (uint64_t) 0); + } +} + static void meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, MetaCRTCInfo **crtcs, @@ -755,6 +839,7 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, MetaOutputInfo **outputs, unsigned int n_outputs) { + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); ClutterBackend *backend; CoglContext *cogl_context; CoglDisplay *cogl_display; @@ -900,6 +985,9 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, output->is_primary = output_info->is_primary; output->is_presentation = output_info->is_presentation; + output->is_underscanning = output_info->is_underscanning; + + set_underscan (manager_kms, output); } /* Disable outputs not mentioned in the list */