MetaMonitorManagerKms: Split up read_current() into logical chunks
Instead of reading all the different state in one huge function, split it up into logical chunks, making it easier to read. https://bugzilla.gnome.org/show_bug.cgi?id=769505
This commit is contained in:
parent
4678c24d83
commit
6940169f46
@ -54,7 +54,10 @@ typedef struct {
|
|||||||
drmModeEncoderPtr *encoders;
|
drmModeEncoderPtr *encoders;
|
||||||
drmModeEncoderPtr current_encoder;
|
drmModeEncoderPtr current_encoder;
|
||||||
|
|
||||||
/* bitmasks of encoder position in the resources array */
|
/*
|
||||||
|
* Bitmasks of encoder position in the resources array (used during clone
|
||||||
|
* setup).
|
||||||
|
*/
|
||||||
uint32_t encoder_mask;
|
uint32_t encoder_mask;
|
||||||
uint32_t enc_clone_mask;
|
uint32_t enc_clone_mask;
|
||||||
|
|
||||||
@ -369,6 +372,33 @@ find_meta_mode (MetaMonitorManager *manager,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_mode (MetaMonitorMode *mode,
|
||||||
|
drmModeModeInfo *drm_mode,
|
||||||
|
long mode_id)
|
||||||
|
{
|
||||||
|
mode->mode_id = mode_id;
|
||||||
|
mode->name = g_strndup (drm_mode->name, DRM_DISPLAY_MODE_LEN);
|
||||||
|
mode->width = drm_mode->hdisplay;
|
||||||
|
mode->height = drm_mode->vdisplay;
|
||||||
|
mode->flags = drm_mode->flags;
|
||||||
|
|
||||||
|
/* Calculate refresh rate in milliHz first for extra precision. */
|
||||||
|
mode->refresh_rate = (drm_mode->clock * 1000000LL) / drm_mode->htotal;
|
||||||
|
mode->refresh_rate += (drm_mode->vtotal / 2);
|
||||||
|
mode->refresh_rate /= drm_mode->vtotal;
|
||||||
|
if (drm_mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||||
|
mode->refresh_rate *= 2;
|
||||||
|
if (drm_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||||
|
mode->refresh_rate /= 2;
|
||||||
|
if (drm_mode->vscan > 1)
|
||||||
|
mode->refresh_rate /= drm_mode->vscan;
|
||||||
|
mode->refresh_rate /= 1000.0;
|
||||||
|
|
||||||
|
mode->driver_private = g_slice_dup (drmModeModeInfo, drm_mode);
|
||||||
|
mode->driver_notify = (GDestroyNotify)meta_monitor_mode_destroy_notify;
|
||||||
|
}
|
||||||
|
|
||||||
static MetaOutput *
|
static MetaOutput *
|
||||||
find_output_by_id (MetaOutput *outputs,
|
find_output_by_id (MetaOutput *outputs,
|
||||||
unsigned n_outputs,
|
unsigned n_outputs,
|
||||||
@ -580,342 +610,250 @@ init_crtc_rotations (MetaMonitorManager *manager,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
init_crtc (MetaCRTC *crtc,
|
||||||
|
MetaMonitorManager *manager,
|
||||||
|
drmModeCrtc *drm_crtc)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
crtc->crtc_id = drm_crtc->crtc_id;
|
||||||
|
crtc->rect.x = drm_crtc->x;
|
||||||
|
crtc->rect.y = drm_crtc->y;
|
||||||
|
crtc->rect.width = drm_crtc->width;
|
||||||
|
crtc->rect.height = drm_crtc->height;
|
||||||
|
crtc->is_dirty = FALSE;
|
||||||
|
crtc->transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||||
|
/* FIXME: implement! */
|
||||||
|
crtc->all_transforms = 1 << META_MONITOR_TRANSFORM_NORMAL;
|
||||||
|
|
||||||
|
if (drm_crtc->mode_valid)
|
||||||
|
{
|
||||||
|
for (i = 0; i < manager->n_modes; i++)
|
||||||
|
{
|
||||||
|
if (drm_mode_equal (&drm_crtc->mode, manager->modes[i].driver_private))
|
||||||
|
{
|
||||||
|
crtc->current_mode = &manager->modes[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crtc->driver_private = g_new0 (MetaCRTCKms, 1);
|
||||||
|
crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_output (MetaOutput *output,
|
||||||
|
MetaMonitorManager *manager,
|
||||||
|
drmModeConnector *connector,
|
||||||
|
MetaOutput *old_output)
|
||||||
{
|
{
|
||||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
drmModeRes *resources;
|
MetaOutputKms *output_kms;
|
||||||
drmModeEncoder **encoders;
|
GArray *crtcs;
|
||||||
GHashTable *modes;
|
GBytes *edid;
|
||||||
GHashTableIter iter;
|
unsigned int i;
|
||||||
drmModeModeInfo *mode;
|
unsigned int crtc_mask;
|
||||||
unsigned int i, j, k;
|
|
||||||
unsigned int n_actual_outputs;
|
|
||||||
int width, height;
|
|
||||||
MetaOutput *old_outputs;
|
|
||||||
unsigned int n_old_outputs;
|
|
||||||
|
|
||||||
resources = drmModeGetResources(manager_kms->fd);
|
output_kms = g_slice_new0 (MetaOutputKms);
|
||||||
modes = g_hash_table_new (drm_mode_hash, drm_mode_equal);
|
output->driver_private = output_kms;
|
||||||
|
output->driver_notify = (GDestroyNotify)meta_output_destroy_notify;
|
||||||
|
|
||||||
manager->max_screen_width = resources->max_width;
|
output->winsys_id = connector->connector_id;
|
||||||
manager->max_screen_height = resources->max_height;
|
output->name = make_output_name (connector);
|
||||||
|
output->width_mm = connector->mmWidth;
|
||||||
|
output->height_mm = connector->mmHeight;
|
||||||
|
|
||||||
manager->power_save_mode = META_POWER_SAVE_ON;
|
switch (connector->subpixel)
|
||||||
|
|
||||||
old_outputs = manager->outputs;
|
|
||||||
n_old_outputs = manager->n_outputs;
|
|
||||||
|
|
||||||
/* Note: we must not free the public structures (output, crtc, monitor
|
|
||||||
mode and monitor info) here, they must be kept alive until the API
|
|
||||||
users are done with them after we emit monitors-changed, and thus
|
|
||||||
are freed by the platform-independent layer. */
|
|
||||||
free_resources (manager_kms);
|
|
||||||
|
|
||||||
manager_kms->n_connectors = resources->count_connectors;
|
|
||||||
manager_kms->connectors = g_new (drmModeConnector *, manager_kms->n_connectors);
|
|
||||||
for (i = 0; i < manager_kms->n_connectors; i++)
|
|
||||||
{
|
{
|
||||||
drmModeConnector *connector;
|
case DRM_MODE_SUBPIXEL_NONE:
|
||||||
|
output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
|
||||||
|
break;
|
||||||
|
case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
|
||||||
|
output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
|
||||||
|
break;
|
||||||
|
case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
|
||||||
|
output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
|
||||||
|
break;
|
||||||
|
case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
|
||||||
|
output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
|
||||||
|
break;
|
||||||
|
case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
|
||||||
|
output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
|
||||||
|
break;
|
||||||
|
case DRM_MODE_SUBPIXEL_UNKNOWN:
|
||||||
|
default:
|
||||||
|
output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
connector = drmModeGetConnector (manager_kms->fd, resources->connectors[i]);
|
output->preferred_mode = NULL;
|
||||||
manager_kms->connectors[i] = connector;
|
output->n_modes = connector->count_modes;
|
||||||
|
output->modes = g_new0 (MetaMonitorMode *, output->n_modes);
|
||||||
|
for (i = 0; i < output->n_modes; i++) {
|
||||||
|
output->modes[i] = find_meta_mode (manager, &connector->modes[i]);
|
||||||
|
if (connector->modes[i].type & DRM_MODE_TYPE_PREFERRED)
|
||||||
|
output->preferred_mode = output->modes[i];
|
||||||
|
}
|
||||||
|
|
||||||
if (connector && connector->connection == DRM_MODE_CONNECTED)
|
if (!output->preferred_mode)
|
||||||
|
output->preferred_mode = output->modes[0];
|
||||||
|
|
||||||
|
output_kms->connector = connector;
|
||||||
|
output_kms->n_encoders = connector->count_encoders;
|
||||||
|
output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
|
||||||
|
|
||||||
|
crtc_mask = ~(unsigned int) 0;
|
||||||
|
for (i = 0; i < output_kms->n_encoders; i++)
|
||||||
|
{
|
||||||
|
output_kms->encoders[i] = drmModeGetEncoder (manager_kms->fd,
|
||||||
|
connector->encoders[i]);
|
||||||
|
if (!output_kms->encoders[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* We only list CRTCs as supported if they are supported by all encoders
|
||||||
|
for this connectors.
|
||||||
|
|
||||||
|
This is what xf86-video-modesetting does (see drmmode_output_init())
|
||||||
|
*/
|
||||||
|
crtc_mask &= output_kms->encoders[i]->possible_crtcs;
|
||||||
|
|
||||||
|
if (output_kms->encoders[i]->encoder_id == connector->encoder_id)
|
||||||
|
output_kms->current_encoder = output_kms->encoders[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
crtcs = g_array_new (FALSE, FALSE, sizeof (MetaCRTC*));
|
||||||
|
|
||||||
|
for (i = 0; i < manager->n_crtcs; i++)
|
||||||
|
{
|
||||||
|
if (crtc_mask & (1 << i))
|
||||||
{
|
{
|
||||||
/* Collect all modes for this connector */
|
MetaCRTC *crtc = &manager->crtcs[i];
|
||||||
for (j = 0; j < (unsigned)connector->count_modes; j++)
|
g_array_append_val (crtcs, crtc);
|
||||||
g_hash_table_add (modes, &connector->modes[j]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
encoders = g_new (drmModeEncoder *, resources->count_encoders);
|
output->n_possible_crtcs = crtcs->len;
|
||||||
for (i = 0; i < (unsigned)resources->count_encoders; i++)
|
output->possible_crtcs = (void*)g_array_free (crtcs, FALSE);
|
||||||
|
|
||||||
|
if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0)
|
||||||
|
{
|
||||||
|
for (i = 0; i < manager->n_crtcs; i++)
|
||||||
|
{
|
||||||
|
if (manager->crtcs[i].crtc_id == output_kms->current_encoder->crtc_id)
|
||||||
|
{
|
||||||
|
output->crtc = &manager->crtcs[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
output->crtc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_output)
|
||||||
|
{
|
||||||
|
output->is_primary = old_output->is_primary;
|
||||||
|
output->is_presentation = old_output->is_presentation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
output->is_primary = FALSE;
|
||||||
|
output->is_presentation = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
find_connector_properties (manager_kms, output_kms);
|
||||||
|
output->suggested_x = output_kms->suggested_x;
|
||||||
|
output->suggested_y = output_kms->suggested_y;
|
||||||
|
output->hotplug_mode_update = output_kms->hotplug_mode_update;
|
||||||
|
|
||||||
|
edid = read_output_edid (manager_kms, output);
|
||||||
|
meta_output_parse_edid (output, edid);
|
||||||
|
g_bytes_unref (edid);
|
||||||
|
|
||||||
|
/* MetaConnectorType matches DRM's connector types */
|
||||||
|
output->connector_type = (MetaConnectorType) connector->connector_type;
|
||||||
|
|
||||||
|
output->scale = get_output_scale (manager, output);
|
||||||
|
|
||||||
|
output_get_tile_info (manager_kms, output);
|
||||||
|
|
||||||
|
/* FIXME: backlight is a very driver specific thing unfortunately,
|
||||||
|
every DDX does its own thing, and the dumb KMS API does not include it.
|
||||||
|
|
||||||
|
For example, xf86-video-intel has a list of paths to probe in /sys/class/backlight
|
||||||
|
(one for each major HW maker, and then some).
|
||||||
|
We can't do the same because we're not root.
|
||||||
|
It might be best to leave backlight out of the story and rely on the setuid
|
||||||
|
helper in gnome-settings-daemon.
|
||||||
|
*/
|
||||||
|
output->backlight_min = 0;
|
||||||
|
output->backlight_max = 0;
|
||||||
|
output->backlight = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
detect_and_setup_output_clones (MetaMonitorManager *manager,
|
||||||
|
drmModeRes *resources)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
drmModeEncoder **encoders;
|
||||||
|
unsigned int i, n_encoders;
|
||||||
|
|
||||||
|
n_encoders = (unsigned int) resources->count_encoders;
|
||||||
|
encoders = g_new (drmModeEncoder *, n_encoders);
|
||||||
|
for (i = 0; i < n_encoders; i++)
|
||||||
encoders[i] = drmModeGetEncoder (manager_kms->fd, resources->encoders[i]);
|
encoders[i] = drmModeGetEncoder (manager_kms->fd, resources->encoders[i]);
|
||||||
|
|
||||||
manager->n_modes = g_hash_table_size (modes);
|
/*
|
||||||
manager->modes = g_new0 (MetaMonitorMode, manager->n_modes);
|
* Setup encoder position mask and encoder clone mask.
|
||||||
g_hash_table_iter_init (&iter, modes);
|
*/
|
||||||
i = 0;
|
|
||||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer)&mode))
|
|
||||||
{
|
|
||||||
MetaMonitorMode *meta_mode;
|
|
||||||
|
|
||||||
meta_mode = &manager->modes[i];
|
|
||||||
|
|
||||||
meta_mode->mode_id = i;
|
|
||||||
meta_mode->name = g_strndup (mode->name, DRM_DISPLAY_MODE_LEN);
|
|
||||||
meta_mode->width = mode->hdisplay;
|
|
||||||
meta_mode->height = mode->vdisplay;
|
|
||||||
meta_mode->flags = mode->flags;
|
|
||||||
|
|
||||||
/* Calculate refresh rate in milliHz first for extra precision. */
|
|
||||||
meta_mode->refresh_rate = (mode->clock * 1000000LL) / mode->htotal;
|
|
||||||
meta_mode->refresh_rate += (mode->vtotal / 2);
|
|
||||||
meta_mode->refresh_rate /= mode->vtotal;
|
|
||||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
|
||||||
meta_mode->refresh_rate *= 2;
|
|
||||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
|
||||||
meta_mode->refresh_rate /= 2;
|
|
||||||
if (mode->vscan > 1)
|
|
||||||
meta_mode->refresh_rate /= mode->vscan;
|
|
||||||
meta_mode->refresh_rate /= 1000.0;
|
|
||||||
|
|
||||||
meta_mode->driver_private = g_slice_dup (drmModeModeInfo, mode);
|
|
||||||
meta_mode->driver_notify = (GDestroyNotify)meta_monitor_mode_destroy_notify;
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
g_hash_table_destroy (modes);
|
|
||||||
|
|
||||||
manager->n_crtcs = resources->count_crtcs;
|
|
||||||
manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs);
|
|
||||||
width = 0; height = 0;
|
|
||||||
for (i = 0; i < (unsigned)resources->count_crtcs; i++)
|
|
||||||
{
|
|
||||||
drmModeCrtc *crtc;
|
|
||||||
MetaCRTC *meta_crtc;
|
|
||||||
|
|
||||||
crtc = drmModeGetCrtc (manager_kms->fd, resources->crtcs[i]);
|
|
||||||
|
|
||||||
meta_crtc = &manager->crtcs[i];
|
|
||||||
|
|
||||||
meta_crtc->crtc_id = crtc->crtc_id;
|
|
||||||
meta_crtc->rect.x = crtc->x;
|
|
||||||
meta_crtc->rect.y = crtc->y;
|
|
||||||
meta_crtc->rect.width = crtc->width;
|
|
||||||
meta_crtc->rect.height = crtc->height;
|
|
||||||
meta_crtc->is_dirty = FALSE;
|
|
||||||
meta_crtc->transform = META_MONITOR_TRANSFORM_NORMAL;
|
|
||||||
/* FIXME: implement! */
|
|
||||||
meta_crtc->all_transforms = 1 << META_MONITOR_TRANSFORM_NORMAL;
|
|
||||||
|
|
||||||
if (crtc->mode_valid)
|
|
||||||
{
|
|
||||||
for (j = 0; j < manager->n_modes; j++)
|
|
||||||
{
|
|
||||||
if (drm_mode_equal (&crtc->mode, manager->modes[j].driver_private))
|
|
||||||
{
|
|
||||||
meta_crtc->current_mode = &manager->modes[j];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
width = MAX (width, meta_crtc->rect.x + meta_crtc->rect.width);
|
|
||||||
height = MAX (height, meta_crtc->rect.y + meta_crtc->rect.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_crtc->driver_private = g_new0 (MetaCRTCKms, 1);
|
|
||||||
meta_crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
|
|
||||||
find_crtc_properties (manager_kms, meta_crtc);
|
|
||||||
init_crtc_rotations (manager, meta_crtc, i);
|
|
||||||
|
|
||||||
drmModeFreeCrtc (crtc);
|
|
||||||
}
|
|
||||||
|
|
||||||
manager->screen_width = width;
|
|
||||||
manager->screen_height = height;
|
|
||||||
|
|
||||||
manager->outputs = g_new0 (MetaOutput, manager_kms->n_connectors);
|
|
||||||
n_actual_outputs = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < manager_kms->n_connectors; i++)
|
|
||||||
{
|
|
||||||
MetaOutput *meta_output, *old_output;
|
|
||||||
MetaOutputKms *output_kms;
|
|
||||||
drmModeConnector *connector;
|
|
||||||
GArray *crtcs;
|
|
||||||
unsigned int crtc_mask;
|
|
||||||
GBytes *edid;
|
|
||||||
|
|
||||||
connector = manager_kms->connectors[i];
|
|
||||||
meta_output = &manager->outputs[n_actual_outputs];
|
|
||||||
|
|
||||||
if (connector && connector->connection == DRM_MODE_CONNECTED)
|
|
||||||
{
|
|
||||||
meta_output->driver_private = output_kms = g_slice_new0 (MetaOutputKms);
|
|
||||||
meta_output->driver_notify = (GDestroyNotify)meta_output_destroy_notify;
|
|
||||||
|
|
||||||
meta_output->winsys_id = connector->connector_id;
|
|
||||||
meta_output->name = make_output_name (connector);
|
|
||||||
meta_output->width_mm = connector->mmWidth;
|
|
||||||
meta_output->height_mm = connector->mmHeight;
|
|
||||||
|
|
||||||
switch (connector->subpixel)
|
|
||||||
{
|
|
||||||
case DRM_MODE_SUBPIXEL_NONE:
|
|
||||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
|
|
||||||
break;
|
|
||||||
case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
|
|
||||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
|
|
||||||
break;
|
|
||||||
case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
|
|
||||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
|
|
||||||
break;
|
|
||||||
case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
|
|
||||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
|
|
||||||
break;
|
|
||||||
case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
|
|
||||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
|
|
||||||
break;
|
|
||||||
case DRM_MODE_SUBPIXEL_UNKNOWN:
|
|
||||||
default:
|
|
||||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_output->preferred_mode = NULL;
|
|
||||||
meta_output->n_modes = connector->count_modes;
|
|
||||||
meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
|
|
||||||
for (j = 0; j < meta_output->n_modes; j++) {
|
|
||||||
meta_output->modes[j] = find_meta_mode (manager, &connector->modes[j]);
|
|
||||||
if (connector->modes[j].type & DRM_MODE_TYPE_PREFERRED)
|
|
||||||
meta_output->preferred_mode = meta_output->modes[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!meta_output->preferred_mode)
|
|
||||||
meta_output->preferred_mode = meta_output->modes[0];
|
|
||||||
|
|
||||||
output_kms->connector = connector;
|
|
||||||
output_kms->n_encoders = connector->count_encoders;
|
|
||||||
output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
|
|
||||||
|
|
||||||
crtc_mask = ~(unsigned int)0;
|
|
||||||
for (j = 0; j < output_kms->n_encoders; j++)
|
|
||||||
{
|
|
||||||
output_kms->encoders[j] = drmModeGetEncoder (manager_kms->fd, connector->encoders[j]);
|
|
||||||
if (!output_kms->encoders[j])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* We only list CRTCs as supported if they are supported by all encoders
|
|
||||||
for this connectors.
|
|
||||||
|
|
||||||
This is what xf86-video-modesetting does (see drmmode_output_init())
|
|
||||||
*/
|
|
||||||
crtc_mask &= output_kms->encoders[j]->possible_crtcs;
|
|
||||||
|
|
||||||
if (output_kms->encoders[j]->encoder_id == connector->encoder_id)
|
|
||||||
output_kms->current_encoder = output_kms->encoders[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
crtcs = g_array_new (FALSE, FALSE, sizeof (MetaCRTC*));
|
|
||||||
|
|
||||||
for (j = 0; j < manager->n_crtcs; j++)
|
|
||||||
{
|
|
||||||
if (crtc_mask & (1 << j))
|
|
||||||
{
|
|
||||||
MetaCRTC *crtc = &manager->crtcs[j];
|
|
||||||
g_array_append_val (crtcs, crtc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_output->n_possible_crtcs = crtcs->len;
|
|
||||||
meta_output->possible_crtcs = (void*)g_array_free (crtcs, FALSE);
|
|
||||||
|
|
||||||
if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0)
|
|
||||||
{
|
|
||||||
for (j = 0; j < manager->n_crtcs; j++)
|
|
||||||
{
|
|
||||||
if (manager->crtcs[j].crtc_id == output_kms->current_encoder->crtc_id)
|
|
||||||
{
|
|
||||||
meta_output->crtc = &manager->crtcs[j];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
meta_output->crtc = NULL;
|
|
||||||
|
|
||||||
old_output = find_output_by_id (old_outputs, n_old_outputs,
|
|
||||||
meta_output->winsys_id);
|
|
||||||
if (old_output)
|
|
||||||
{
|
|
||||||
meta_output->is_primary = old_output->is_primary;
|
|
||||||
meta_output->is_presentation = old_output->is_presentation;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
meta_output->is_primary = FALSE;
|
|
||||||
meta_output->is_presentation = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
find_connector_properties (manager_kms, output_kms);
|
|
||||||
meta_output->suggested_x = output_kms->suggested_x;
|
|
||||||
meta_output->suggested_y = output_kms->suggested_y;
|
|
||||||
meta_output->hotplug_mode_update = output_kms->hotplug_mode_update;
|
|
||||||
|
|
||||||
edid = read_output_edid (manager_kms, meta_output);
|
|
||||||
meta_output_parse_edid (meta_output, edid);
|
|
||||||
g_bytes_unref (edid);
|
|
||||||
|
|
||||||
/* MetaConnectorType matches DRM's connector types */
|
|
||||||
meta_output->connector_type = (MetaConnectorType) connector->connector_type;
|
|
||||||
|
|
||||||
meta_output->scale = get_output_scale (manager, meta_output);
|
|
||||||
|
|
||||||
output_get_tile_info (manager_kms, meta_output);
|
|
||||||
|
|
||||||
/* FIXME: backlight is a very driver specific thing unfortunately,
|
|
||||||
every DDX does its own thing, and the dumb KMS API does not include it.
|
|
||||||
|
|
||||||
For example, xf86-video-intel has a list of paths to probe in /sys/class/backlight
|
|
||||||
(one for each major HW maker, and then some).
|
|
||||||
We can't do the same because we're not root.
|
|
||||||
It might be best to leave backlight out of the story and rely on the setuid
|
|
||||||
helper in gnome-settings-daemon.
|
|
||||||
*/
|
|
||||||
meta_output->backlight_min = 0;
|
|
||||||
meta_output->backlight_max = 0;
|
|
||||||
meta_output->backlight = -1;
|
|
||||||
|
|
||||||
n_actual_outputs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
manager->n_outputs = n_actual_outputs;
|
|
||||||
manager->outputs = g_renew (MetaOutput, manager->outputs, manager->n_outputs);
|
|
||||||
|
|
||||||
/* Sort the outputs for easier handling in MetaMonitorConfig */
|
|
||||||
qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
|
|
||||||
|
|
||||||
/* Now fix the clones.
|
|
||||||
Code mostly inspired by xf86-video-modesetting. */
|
|
||||||
|
|
||||||
/* XXX: intel hardware doesn't usually have clones, but I only have laptops with
|
|
||||||
intel cards, so this code was never tested! */
|
|
||||||
for (i = 0; i < manager->n_outputs; i++)
|
for (i = 0; i < manager->n_outputs; i++)
|
||||||
{
|
{
|
||||||
MetaOutput *meta_output;
|
MetaOutput *output;
|
||||||
MetaOutputKms *output_kms;
|
MetaOutputKms *output_kms;
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
meta_output = &manager->outputs[i];
|
output = &manager->outputs[i];
|
||||||
output_kms = meta_output->driver_private;
|
output_kms = output->driver_private;
|
||||||
|
|
||||||
output_kms->enc_clone_mask = 0xff;
|
output_kms->enc_clone_mask = 0xff;
|
||||||
output_kms->encoder_mask = 0;
|
output_kms->encoder_mask = 0;
|
||||||
|
|
||||||
for (j = 0; j < output_kms->n_encoders; j++)
|
for (j = 0; j < output_kms->n_encoders; j++)
|
||||||
{
|
{
|
||||||
for (k = 0; k < (unsigned)resources->count_encoders; k++)
|
unsigned int k;
|
||||||
{
|
|
||||||
|
for (k = 0; k < n_encoders; k++)
|
||||||
|
{
|
||||||
if (output_kms->encoders[j] && encoders[k] &&
|
if (output_kms->encoders[j] && encoders[k] &&
|
||||||
output_kms->encoders[j]->encoder_id == encoders[k]->encoder_id)
|
output_kms->encoders[j]->encoder_id == encoders[k]->encoder_id)
|
||||||
{
|
{
|
||||||
output_kms->encoder_mask |= (1 << k);
|
output_kms->encoder_mask |= (1 << k);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
output_kms->enc_clone_mask &= output_kms->encoders[j]->possible_clones;
|
output_kms->enc_clone_mask &= output_kms->encoders[j]->possible_clones;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (unsigned)resources->count_encoders; i++)
|
||||||
|
drmModeFreeEncoder (encoders[i]);
|
||||||
|
g_free (encoders);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup MetaOutput <-> MetaOutput clone associations.
|
||||||
|
*/
|
||||||
for (i = 0; i < manager->n_outputs; i++)
|
for (i = 0; i < manager->n_outputs; i++)
|
||||||
{
|
{
|
||||||
MetaOutput *meta_output;
|
MetaOutput *output;
|
||||||
MetaOutputKms *output_kms;
|
MetaOutputKms *output_kms;
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
meta_output = &manager->outputs[i];
|
output = &manager->outputs[i];
|
||||||
output_kms = meta_output->driver_private;
|
output_kms = output->driver_private;
|
||||||
|
|
||||||
if (output_kms->enc_clone_mask == 0)
|
if (output_kms->enc_clone_mask == 0)
|
||||||
continue;
|
continue;
|
||||||
@ -928,7 +866,7 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
|||||||
meta_clone = &manager->outputs[i];
|
meta_clone = &manager->outputs[i];
|
||||||
clone_kms = meta_clone->driver_private;
|
clone_kms = meta_clone->driver_private;
|
||||||
|
|
||||||
if (meta_clone == meta_output)
|
if (meta_clone == output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (clone_kms->encoder_mask == 0)
|
if (clone_kms->encoder_mask == 0)
|
||||||
@ -936,18 +874,198 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
|||||||
|
|
||||||
if (clone_kms->encoder_mask == output_kms->enc_clone_mask)
|
if (clone_kms->encoder_mask == output_kms->enc_clone_mask)
|
||||||
{
|
{
|
||||||
meta_output->n_possible_clones++;
|
output->n_possible_clones++;
|
||||||
meta_output->possible_clones = g_renew (MetaOutput *,
|
output->possible_clones = g_renew (MetaOutput *,
|
||||||
meta_output->possible_clones,
|
output->possible_clones,
|
||||||
meta_output->n_possible_clones);
|
output->n_possible_clones);
|
||||||
meta_output->possible_clones[meta_output->n_possible_clones - 1] = meta_clone;
|
output->possible_clones[output->n_possible_clones - 1] = meta_clone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < (unsigned)resources->count_encoders; i++)
|
static void
|
||||||
drmModeFreeEncoder (encoders[i]);
|
init_connectors (MetaMonitorManager *manager,
|
||||||
g_free (encoders);
|
drmModeRes *resources)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
manager_kms->n_connectors = resources->count_connectors;
|
||||||
|
manager_kms->connectors = g_new (drmModeConnector *, manager_kms->n_connectors);
|
||||||
|
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||||
|
{
|
||||||
|
drmModeConnector *drm_connector;
|
||||||
|
|
||||||
|
drm_connector = drmModeGetConnector (manager_kms->fd,
|
||||||
|
resources->connectors[i]);
|
||||||
|
manager_kms->connectors[i] = drm_connector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_modes (MetaMonitorManager *manager,
|
||||||
|
drmModeRes *resources)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
GHashTable *modes;
|
||||||
|
GHashTableIter iter;
|
||||||
|
drmModeModeInfo *drm_mode;
|
||||||
|
unsigned int i;
|
||||||
|
long mode_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gather all modes on all connected connectors.
|
||||||
|
*/
|
||||||
|
modes = g_hash_table_new (drm_mode_hash, drm_mode_equal);
|
||||||
|
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||||
|
{
|
||||||
|
drmModeConnector *drm_connector;
|
||||||
|
|
||||||
|
drm_connector = manager_kms->connectors[i];
|
||||||
|
if (drm_connector && drm_connector->connection == DRM_MODE_CONNECTED)
|
||||||
|
{
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
|
for (j = 0; j < (unsigned int) drm_connector->count_modes; j++)
|
||||||
|
g_hash_table_add (modes, &drm_connector->modes[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->n_modes = g_hash_table_size (modes);
|
||||||
|
manager->modes = g_new0 (MetaMonitorMode, manager->n_modes);
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, modes);
|
||||||
|
mode_id = 0;
|
||||||
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &drm_mode))
|
||||||
|
{
|
||||||
|
MetaMonitorMode *mode;
|
||||||
|
|
||||||
|
mode = &manager->modes[mode_id];
|
||||||
|
init_mode (mode, drm_mode, (long) mode_id);
|
||||||
|
|
||||||
|
mode_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_destroy (modes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_crtcs (MetaMonitorManager *manager,
|
||||||
|
drmModeRes *resources)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
manager->n_crtcs = resources->count_crtcs;
|
||||||
|
manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs);
|
||||||
|
|
||||||
|
for (i = 0; i < (unsigned)resources->count_crtcs; i++)
|
||||||
|
{
|
||||||
|
drmModeCrtc *drm_crtc;
|
||||||
|
MetaCRTC *crtc;
|
||||||
|
|
||||||
|
drm_crtc = drmModeGetCrtc (manager_kms->fd, resources->crtcs[i]);
|
||||||
|
|
||||||
|
crtc = &manager->crtcs[i];
|
||||||
|
|
||||||
|
init_crtc (crtc, manager, drm_crtc);
|
||||||
|
find_crtc_properties (manager_kms, crtc);
|
||||||
|
init_crtc_rotations (manager, crtc, i);
|
||||||
|
|
||||||
|
drmModeFreeCrtc (drm_crtc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_outputs (MetaMonitorManager *manager,
|
||||||
|
drmModeRes *resources)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
MetaOutput *old_outputs;
|
||||||
|
unsigned int n_old_outputs;
|
||||||
|
unsigned int n_actual_outputs;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
old_outputs = manager->outputs;
|
||||||
|
n_old_outputs = manager->n_outputs;
|
||||||
|
|
||||||
|
manager->outputs = g_new0 (MetaOutput, manager_kms->n_connectors);
|
||||||
|
n_actual_outputs = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||||
|
{
|
||||||
|
drmModeConnector *connector;
|
||||||
|
MetaOutput *output;
|
||||||
|
|
||||||
|
connector = manager_kms->connectors[i];
|
||||||
|
output = &manager->outputs[n_actual_outputs];
|
||||||
|
|
||||||
|
if (connector && connector->connection == DRM_MODE_CONNECTED)
|
||||||
|
{
|
||||||
|
MetaOutput *old_output;
|
||||||
|
|
||||||
|
old_output = find_output_by_id (old_outputs, n_old_outputs,
|
||||||
|
output->winsys_id);
|
||||||
|
init_output (output, manager, connector, old_output);
|
||||||
|
n_actual_outputs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->n_outputs = n_actual_outputs;
|
||||||
|
manager->outputs = g_renew (MetaOutput, manager->outputs, manager->n_outputs);
|
||||||
|
|
||||||
|
/* Sort the outputs for easier handling in MetaMonitorConfig */
|
||||||
|
qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput),
|
||||||
|
compare_outputs);
|
||||||
|
|
||||||
|
detect_and_setup_output_clones (manager, resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
calculate_screen_size (MetaMonitorManager *manager)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
int width = 0, height = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < manager->n_crtcs; i++)
|
||||||
|
{
|
||||||
|
MetaCRTC *crtc = &manager->crtcs[i];
|
||||||
|
|
||||||
|
width = MAX (width, crtc->rect.x + crtc->rect.width);
|
||||||
|
height = MAX (height, crtc->rect.y + crtc->rect.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->screen_width = width;
|
||||||
|
manager->screen_height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
||||||
|
{
|
||||||
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||||
|
drmModeRes *resources;
|
||||||
|
|
||||||
|
resources = drmModeGetResources(manager_kms->fd);
|
||||||
|
|
||||||
|
/* TODO: max screen width only matters for stage views is not enabled. */
|
||||||
|
manager->max_screen_width = resources->max_width;
|
||||||
|
manager->max_screen_height = resources->max_height;
|
||||||
|
|
||||||
|
manager->power_save_mode = META_POWER_SAVE_ON;
|
||||||
|
|
||||||
|
/* Note: we must not free the public structures (output, crtc, monitor
|
||||||
|
mode and monitor info) here, they must be kept alive until the API
|
||||||
|
users are done with them after we emit monitors-changed, and thus
|
||||||
|
are freed by the platform-independent layer. */
|
||||||
|
free_resources (manager_kms);
|
||||||
|
|
||||||
|
init_connectors (manager, resources);
|
||||||
|
init_modes (manager, resources);
|
||||||
|
init_crtcs (manager, resources);
|
||||||
|
init_outputs (manager, resources);
|
||||||
|
|
||||||
|
calculate_screen_size (manager);
|
||||||
|
|
||||||
drmModeFreeResources (resources);
|
drmModeFreeResources (resources);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user