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:
Jonas Ådahl 2016-08-01 17:25:52 +08:00
parent 4678c24d83
commit 6940169f46

View File

@ -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);
} }