mirror of
https://github.com/brl/mutter.git
synced 2024-11-28 11:00:54 -05:00
cfee58798e
Instead of passing it around or fetching the singleton, keep a pointer to the monitor manager that owns the CRTC. This will eventually be replaced with a per GPU/graphics card object. https://bugzilla.gnome.org/show_bug.cgi?id=785381
1443 lines
41 KiB
C
1443 lines
41 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
/*
|
|
* Copyright (C) 2013 Red Hat Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*
|
|
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "meta-monitor-manager-kms.h"
|
|
#include "meta-monitor-config-manager.h"
|
|
#include "meta-crtc.h"
|
|
#include "meta-output.h"
|
|
#include "meta-backend-private.h"
|
|
#include "meta-renderer-native.h"
|
|
#include "meta-output-kms.h"
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <clutter/clutter.h>
|
|
|
|
#include <drm.h>
|
|
#include <errno.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
|
|
#include <meta/main.h>
|
|
#include <meta/errors.h>
|
|
|
|
#include <gudev/gudev.h>
|
|
|
|
#include "meta-default-modes.h"
|
|
|
|
#define ALL_TRANSFORMS (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)
|
|
#define ALL_TRANSFORMS_MASK ((1 << ALL_TRANSFORMS) - 1)
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t underscan_prop_id;
|
|
uint32_t underscan_hborder_prop_id;
|
|
uint32_t underscan_vborder_prop_id;
|
|
uint32_t primary_plane_id;
|
|
uint32_t rotation_prop_id;
|
|
uint32_t rotation_map[ALL_TRANSFORMS];
|
|
uint32_t all_hw_transforms;
|
|
} MetaCrtcKms;
|
|
|
|
typedef struct
|
|
{
|
|
GSource source;
|
|
|
|
gpointer fd_tag;
|
|
MetaMonitorManagerKms *manager_kms;
|
|
} MetaKmsSource;
|
|
|
|
struct _MetaMonitorManagerKms
|
|
{
|
|
MetaMonitorManager parent_instance;
|
|
|
|
int fd;
|
|
MetaKmsSource *source;
|
|
|
|
drmModeConnector **connectors;
|
|
unsigned int n_connectors;
|
|
|
|
GUdevClient *udev;
|
|
guint uevent_handler_id;
|
|
|
|
gboolean page_flips_not_supported;
|
|
|
|
int max_buffer_width;
|
|
int max_buffer_height;
|
|
};
|
|
|
|
struct _MetaMonitorManagerKmsClass
|
|
{
|
|
MetaMonitorManagerClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, META_TYPE_MONITOR_MANAGER);
|
|
|
|
int
|
|
meta_monitor_manager_kms_get_fd (MetaMonitorManagerKms *manager_kms)
|
|
{
|
|
return manager_kms->fd;
|
|
}
|
|
|
|
static void
|
|
free_resources (MetaMonitorManagerKms *manager_kms)
|
|
{
|
|
unsigned i;
|
|
|
|
for (i = 0; i < manager_kms->n_connectors; i++)
|
|
drmModeFreeConnector (manager_kms->connectors[i]);
|
|
|
|
g_free (manager_kms->connectors);
|
|
}
|
|
|
|
static int
|
|
compare_outputs (gconstpointer one,
|
|
gconstpointer two)
|
|
{
|
|
const MetaOutput *o_one = one, *o_two = two;
|
|
|
|
return strcmp (o_one->name, o_two->name);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_mode_destroy_notify (MetaCrtcMode *mode)
|
|
{
|
|
g_slice_free (drmModeModeInfo, mode->driver_private);
|
|
}
|
|
|
|
static void
|
|
meta_crtc_destroy_notify (MetaCrtc *crtc)
|
|
{
|
|
g_free (crtc->driver_private);
|
|
}
|
|
|
|
static gboolean
|
|
drm_mode_equal (gconstpointer one,
|
|
gconstpointer two)
|
|
{
|
|
const drmModeModeInfo *m_one = one;
|
|
const drmModeModeInfo *m_two = two;
|
|
|
|
return m_one->clock == m_two->clock &&
|
|
m_one->hdisplay == m_two->hdisplay &&
|
|
m_one->hsync_start == m_two->hsync_start &&
|
|
m_one->hsync_end == m_two->hsync_end &&
|
|
m_one->htotal == m_two->htotal &&
|
|
m_one->hskew == m_two->hskew &&
|
|
m_one->vdisplay == m_two->vdisplay &&
|
|
m_one->vsync_start == m_two->vsync_start &&
|
|
m_one->vsync_end == m_two->vsync_end &&
|
|
m_one->vtotal == m_two->vtotal &&
|
|
m_one->vscan == m_two->vscan &&
|
|
m_one->vrefresh == m_two->vrefresh &&
|
|
m_one->flags == m_two->flags &&
|
|
m_one->type == m_two->type &&
|
|
strncmp (m_one->name, m_two->name, DRM_DISPLAY_MODE_LEN) == 0;
|
|
}
|
|
|
|
static guint
|
|
drm_mode_hash (gconstpointer ptr)
|
|
{
|
|
const drmModeModeInfo *mode = ptr;
|
|
guint hash = 0;
|
|
|
|
/* We don't include the name in the hash because it's generally
|
|
derived from the other fields (hdisplay, vdisplay and flags)
|
|
*/
|
|
|
|
hash ^= mode->clock;
|
|
hash ^= mode->hdisplay ^ mode->hsync_start ^ mode->hsync_end;
|
|
hash ^= mode->vdisplay ^ mode->vsync_start ^ mode->vsync_end;
|
|
hash ^= mode->vrefresh;
|
|
hash ^= mode->flags ^ mode->type;
|
|
|
|
return hash;
|
|
}
|
|
|
|
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);
|
|
if (!props)
|
|
return;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
MetaCrtcMode *
|
|
meta_monitor_manager_kms_get_mode_from_drm_mode (MetaMonitorManagerKms *manager_kms,
|
|
const drmModeModeInfo *drm_mode)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
|
|
GList *l;
|
|
|
|
for (l = manager->modes; l; l = l->next)
|
|
{
|
|
MetaCrtcMode *mode = l->data;
|
|
|
|
if (drm_mode_equal (drm_mode, mode->driver_private))
|
|
return mode;
|
|
}
|
|
|
|
g_assert_not_reached ();
|
|
return NULL;
|
|
}
|
|
|
|
float
|
|
meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *mode)
|
|
{
|
|
float refresh = 0.0;
|
|
|
|
if (mode->htotal > 0 && mode->vtotal > 0)
|
|
{
|
|
/* Calculate refresh rate in milliHz first for extra precision. */
|
|
refresh = (mode->clock * 1000000LL) / mode->htotal;
|
|
refresh += (mode->vtotal / 2);
|
|
refresh /= mode->vtotal;
|
|
if (mode->vscan > 1)
|
|
refresh /= mode->vscan;
|
|
refresh /= 1000.0;
|
|
}
|
|
return refresh;
|
|
}
|
|
|
|
static MetaCrtcMode *
|
|
create_mode (const drmModeModeInfo *drm_mode,
|
|
long mode_id)
|
|
{
|
|
MetaCrtcMode *mode;
|
|
|
|
mode = g_object_new (META_TYPE_CRTC_MODE, NULL);
|
|
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;
|
|
mode->refresh_rate = meta_calculate_drm_mode_refresh_rate (drm_mode);
|
|
mode->driver_private = g_slice_dup (drmModeModeInfo, drm_mode);
|
|
mode->driver_notify = (GDestroyNotify) meta_monitor_mode_destroy_notify;
|
|
|
|
return mode;
|
|
}
|
|
|
|
static MetaOutput *
|
|
find_output_by_id (GList *outputs,
|
|
glong id)
|
|
{
|
|
GList *l;
|
|
|
|
for (l = outputs; l; l = l->next)
|
|
{
|
|
MetaOutput *output = l->data;
|
|
|
|
if (output->winsys_id == id)
|
|
return output;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int
|
|
find_property_index (MetaMonitorManager *manager,
|
|
drmModeObjectPropertiesPtr props,
|
|
const gchar *prop_name,
|
|
drmModePropertyPtr *found)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < props->count_props; i++)
|
|
{
|
|
drmModePropertyPtr prop;
|
|
|
|
prop = drmModeGetProperty (manager_kms->fd, props->props[i]);
|
|
if (!prop)
|
|
continue;
|
|
|
|
if (strcmp (prop->name, prop_name) == 0)
|
|
{
|
|
*found = prop;
|
|
return i;
|
|
}
|
|
|
|
drmModeFreeProperty (prop);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void
|
|
parse_transforms (MetaMonitorManager *manager,
|
|
drmModePropertyPtr prop,
|
|
MetaCrtc *crtc)
|
|
{
|
|
MetaCrtcKms *crtc_kms = crtc->driver_private;
|
|
int i;
|
|
|
|
for (i = 0; i < prop->count_enums; i++)
|
|
{
|
|
int cur = -1;
|
|
|
|
if (strcmp (prop->enums[i].name, "rotate-0") == 0)
|
|
cur = META_MONITOR_TRANSFORM_NORMAL;
|
|
else if (strcmp (prop->enums[i].name, "rotate-90") == 0)
|
|
cur = META_MONITOR_TRANSFORM_90;
|
|
else if (strcmp (prop->enums[i].name, "rotate-180") == 0)
|
|
cur = META_MONITOR_TRANSFORM_180;
|
|
else if (strcmp (prop->enums[i].name, "rotate-270") == 0)
|
|
cur = META_MONITOR_TRANSFORM_270;
|
|
|
|
if (cur != -1)
|
|
{
|
|
crtc_kms->all_hw_transforms |= 1 << cur;
|
|
crtc_kms->rotation_map[cur] = 1 << prop->enums[i].value;
|
|
}
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
is_primary_plane (MetaMonitorManager *manager,
|
|
drmModeObjectPropertiesPtr props)
|
|
{
|
|
drmModePropertyPtr prop;
|
|
int idx;
|
|
|
|
idx = find_property_index (manager, props, "type", &prop);
|
|
if (idx < 0)
|
|
return FALSE;
|
|
|
|
drmModeFreeProperty (prop);
|
|
return props->prop_values[idx] == DRM_PLANE_TYPE_PRIMARY;
|
|
}
|
|
|
|
static void
|
|
init_crtc_rotations (MetaMonitorManager *manager,
|
|
MetaCrtc *crtc,
|
|
unsigned int idx)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
|
drmModeObjectPropertiesPtr props;
|
|
drmModePlaneRes *planes;
|
|
drmModePlane *drm_plane;
|
|
MetaCrtcKms *crtc_kms;
|
|
unsigned int i;
|
|
|
|
crtc_kms = crtc->driver_private;
|
|
|
|
planes = drmModeGetPlaneResources(manager_kms->fd);
|
|
if (planes == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < planes->count_planes; i++)
|
|
{
|
|
drmModePropertyPtr prop;
|
|
|
|
drm_plane = drmModeGetPlane (manager_kms->fd, planes->planes[i]);
|
|
|
|
if (!drm_plane)
|
|
continue;
|
|
|
|
if ((drm_plane->possible_crtcs & (1 << idx)))
|
|
{
|
|
props = drmModeObjectGetProperties (manager_kms->fd,
|
|
drm_plane->plane_id,
|
|
DRM_MODE_OBJECT_PLANE);
|
|
|
|
if (props && is_primary_plane (manager, props))
|
|
{
|
|
int rotation_idx;
|
|
|
|
crtc_kms->primary_plane_id = drm_plane->plane_id;
|
|
rotation_idx = find_property_index (manager, props, "rotation", &prop);
|
|
|
|
if (rotation_idx >= 0)
|
|
{
|
|
crtc_kms->rotation_prop_id = props->props[rotation_idx];
|
|
parse_transforms (manager, prop, crtc);
|
|
drmModeFreeProperty (prop);
|
|
}
|
|
}
|
|
|
|
if (props)
|
|
drmModeFreeObjectProperties (props);
|
|
}
|
|
|
|
drmModeFreePlane (drm_plane);
|
|
}
|
|
|
|
crtc->all_transforms |= crtc_kms->all_hw_transforms;
|
|
|
|
drmModeFreePlaneResources (planes);
|
|
}
|
|
|
|
static MetaCrtc *
|
|
create_crtc (MetaMonitorManager *manager,
|
|
drmModeCrtc *drm_crtc)
|
|
{
|
|
MetaCrtc *crtc;
|
|
|
|
crtc = g_object_new (META_TYPE_CRTC, NULL);
|
|
|
|
crtc->monitor_manager = manager;
|
|
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;
|
|
crtc->all_transforms = meta_is_stage_views_enabled () ?
|
|
ALL_TRANSFORMS_MASK : META_MONITOR_TRANSFORM_NORMAL;
|
|
|
|
if (drm_crtc->mode_valid)
|
|
{
|
|
GList *l;
|
|
|
|
for (l = manager->modes; l; l = l->next)
|
|
{
|
|
MetaCrtcMode *mode = l->data;
|
|
|
|
if (drm_mode_equal (&drm_crtc->mode, mode->driver_private))
|
|
{
|
|
crtc->current_mode = mode;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
crtc->driver_private = g_new0 (MetaCrtcKms, 1);
|
|
crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
|
|
|
|
return crtc;
|
|
}
|
|
|
|
static void
|
|
setup_output_clones (MetaMonitorManager *manager)
|
|
{
|
|
GList *l;
|
|
|
|
for (l = manager->outputs; l; l = l->next)
|
|
{
|
|
MetaOutput *output = l->data;
|
|
GList *k;
|
|
|
|
for (k = manager->outputs; k; k = k->next)
|
|
{
|
|
MetaOutput *other_output = k->data;
|
|
|
|
if (other_output == output)
|
|
continue;
|
|
|
|
if (meta_output_kms_can_clone (output, other_output))
|
|
{
|
|
output->n_possible_clones++;
|
|
output->possible_clones = g_renew (MetaOutput *,
|
|
output->possible_clones,
|
|
output->n_possible_clones);
|
|
output->possible_clones[output->n_possible_clones - 1] =
|
|
other_output;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
init_connectors (MetaMonitorManager *manager,
|
|
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->modes = NULL;
|
|
|
|
g_hash_table_iter_init (&iter, modes);
|
|
mode_id = 0;
|
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &drm_mode))
|
|
{
|
|
MetaCrtcMode *mode;
|
|
|
|
mode = create_mode (drm_mode, (long) mode_id);
|
|
manager->modes = g_list_append (manager->modes, mode);
|
|
|
|
mode_id++;
|
|
}
|
|
|
|
g_hash_table_destroy (modes);
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (meta_default_drm_mode_infos); i++)
|
|
{
|
|
MetaCrtcMode *mode;
|
|
|
|
mode = create_mode (&meta_default_drm_mode_infos[i], (long) mode_id);
|
|
manager->modes = g_list_append (manager->modes, mode);
|
|
|
|
mode_id++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
init_crtcs (MetaMonitorManager *manager,
|
|
drmModeRes *resources)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
|
unsigned int i;
|
|
|
|
manager->crtcs = NULL;
|
|
|
|
for (i = 0; i < (unsigned)resources->count_crtcs; i++)
|
|
{
|
|
drmModeCrtc *drm_crtc;
|
|
MetaCrtc *crtc;
|
|
|
|
drm_crtc = drmModeGetCrtc (manager_kms->fd, resources->crtcs[i]);
|
|
|
|
crtc = create_crtc (manager, drm_crtc);
|
|
find_crtc_properties (manager_kms, crtc);
|
|
init_crtc_rotations (manager, crtc, i);
|
|
|
|
drmModeFreeCrtc (drm_crtc);
|
|
|
|
manager->crtcs = g_list_append (manager->crtcs, crtc);
|
|
}
|
|
}
|
|
|
|
static void
|
|
init_outputs (MetaMonitorManager *manager,
|
|
MetaKmsResources *resources)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
|
GList *old_outputs;
|
|
unsigned int i;
|
|
|
|
old_outputs = manager->outputs;
|
|
|
|
manager->outputs = NULL;
|
|
|
|
for (i = 0; i < manager_kms->n_connectors; i++)
|
|
{
|
|
drmModeConnector *connector;
|
|
|
|
connector = manager_kms->connectors[i];
|
|
|
|
if (connector && connector->connection == DRM_MODE_CONNECTED)
|
|
{
|
|
MetaOutput *output;
|
|
MetaOutput *old_output;
|
|
|
|
old_output = find_output_by_id (old_outputs, connector->connector_id);
|
|
output = meta_create_kms_output (manager, connector, resources, old_output);
|
|
manager->outputs = g_list_prepend (manager->outputs, output);
|
|
}
|
|
}
|
|
|
|
|
|
/* Sort the outputs for easier handling in MetaMonitorConfig */
|
|
manager->outputs = g_list_sort (manager->outputs, compare_outputs);
|
|
|
|
setup_output_clones (manager);
|
|
}
|
|
|
|
static void
|
|
meta_kms_resources_init (MetaKmsResources *resources,
|
|
int fd)
|
|
{
|
|
drmModeRes *drm_resources;
|
|
unsigned int i;
|
|
|
|
drm_resources = drmModeGetResources (fd);
|
|
resources->resources = drm_resources;
|
|
|
|
resources->n_encoders = (unsigned int) drm_resources->count_encoders;
|
|
resources->encoders = g_new (drmModeEncoder *, resources->n_encoders);
|
|
for (i = 0; i < resources->n_encoders; i++)
|
|
resources->encoders[i] = drmModeGetEncoder (fd, drm_resources->encoders[i]);
|
|
}
|
|
|
|
static void
|
|
meta_kms_resources_release (MetaKmsResources *resources)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < resources->n_encoders; i++)
|
|
drmModeFreeEncoder (resources->encoders[i]);
|
|
g_free (resources->encoders);
|
|
|
|
drmModeFreeResources (resources->resources);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
|
MetaKmsResources resources;
|
|
|
|
meta_kms_resources_init (&resources, manager_kms->fd);
|
|
|
|
manager_kms->max_buffer_width = resources.resources->max_width;
|
|
manager_kms->max_buffer_height = resources.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.resources);
|
|
init_modes (manager, resources.resources);
|
|
init_crtcs (manager, resources.resources);
|
|
init_outputs (manager, &resources);
|
|
|
|
meta_kms_resources_release (&resources);
|
|
}
|
|
|
|
static GBytes *
|
|
meta_monitor_manager_kms_read_edid (MetaMonitorManager *manager,
|
|
MetaOutput *output)
|
|
{
|
|
return meta_output_kms_read_edid (output);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
|
|
MetaPowerSave mode)
|
|
{
|
|
uint64_t state;
|
|
GList *l;
|
|
|
|
switch (mode) {
|
|
case META_POWER_SAVE_ON:
|
|
state = DRM_MODE_DPMS_ON;
|
|
break;
|
|
case META_POWER_SAVE_STANDBY:
|
|
state = DRM_MODE_DPMS_STANDBY;
|
|
break;
|
|
case META_POWER_SAVE_SUSPEND:
|
|
state = DRM_MODE_DPMS_SUSPEND;
|
|
break;
|
|
case META_POWER_SAVE_OFF:
|
|
state = DRM_MODE_DPMS_OFF;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
for (l = manager->outputs; l; l = l->next)
|
|
{
|
|
MetaOutput *output = l->data;
|
|
|
|
meta_output_kms_set_power_save_mode (output, state);
|
|
}
|
|
}
|
|
|
|
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_ensure_initial_config (MetaMonitorManager *manager)
|
|
{
|
|
MetaMonitorsConfig *config;
|
|
|
|
config = meta_monitor_manager_ensure_configured (manager);
|
|
|
|
meta_monitor_manager_update_logical_state (manager, config);
|
|
}
|
|
|
|
static void
|
|
apply_crtc_assignments (MetaMonitorManager *manager,
|
|
MetaCrtcInfo **crtcs,
|
|
unsigned int n_crtcs,
|
|
MetaOutputInfo **outputs,
|
|
unsigned int n_outputs)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
|
unsigned i;
|
|
GList *l;
|
|
|
|
for (i = 0; i < n_crtcs; i++)
|
|
{
|
|
MetaCrtcInfo *crtc_info = crtcs[i];
|
|
MetaCrtc *crtc = crtc_info->crtc;
|
|
MetaCrtcKms *crtc_kms = crtc->driver_private;
|
|
MetaMonitorTransform hw_transform;
|
|
|
|
crtc->is_dirty = TRUE;
|
|
|
|
if (crtc_info->mode == NULL)
|
|
{
|
|
crtc->rect.x = 0;
|
|
crtc->rect.y = 0;
|
|
crtc->rect.width = 0;
|
|
crtc->rect.height = 0;
|
|
crtc->current_mode = NULL;
|
|
}
|
|
else
|
|
{
|
|
MetaCrtcMode *mode;
|
|
unsigned int j;
|
|
int width, height;
|
|
|
|
mode = crtc_info->mode;
|
|
|
|
if (meta_monitor_transform_is_rotated (crtc_info->transform))
|
|
{
|
|
width = mode->height;
|
|
height = mode->width;
|
|
}
|
|
else
|
|
{
|
|
width = mode->width;
|
|
height = mode->height;
|
|
}
|
|
|
|
crtc->rect.x = crtc_info->x;
|
|
crtc->rect.y = crtc_info->y;
|
|
crtc->rect.width = width;
|
|
crtc->rect.height = height;
|
|
crtc->current_mode = mode;
|
|
crtc->transform = crtc_info->transform;
|
|
|
|
for (j = 0; j < crtc_info->outputs->len; j++)
|
|
{
|
|
MetaOutput *output = g_ptr_array_index (crtc_info->outputs, j);
|
|
|
|
output->is_dirty = TRUE;
|
|
output->crtc = crtc;
|
|
}
|
|
}
|
|
|
|
if (crtc_kms->all_hw_transforms & (1 << crtc->transform))
|
|
hw_transform = crtc->transform;
|
|
else
|
|
hw_transform = META_MONITOR_TRANSFORM_NORMAL;
|
|
|
|
if (drmModeObjectSetProperty (manager_kms->fd,
|
|
crtc_kms->primary_plane_id,
|
|
DRM_MODE_OBJECT_PLANE,
|
|
crtc_kms->rotation_prop_id,
|
|
crtc_kms->rotation_map[hw_transform]) != 0)
|
|
{
|
|
g_warning ("Failed to apply DRM plane transform %d: %m", hw_transform);
|
|
|
|
/* Blacklist this HW transform, we want to fallback to our
|
|
* fallbacks in this case.
|
|
*/
|
|
crtc_kms->all_hw_transforms &= ~(1 << hw_transform);
|
|
}
|
|
}
|
|
/* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE,
|
|
because they weren't seen in the first loop) */
|
|
for (l = manager->crtcs; l; l = l->next)
|
|
{
|
|
MetaCrtc *crtc = l->data;
|
|
|
|
crtc->logical_monitor = NULL;
|
|
|
|
if (crtc->is_dirty)
|
|
{
|
|
crtc->is_dirty = FALSE;
|
|
continue;
|
|
}
|
|
|
|
crtc->rect.x = 0;
|
|
crtc->rect.y = 0;
|
|
crtc->rect.width = 0;
|
|
crtc->rect.height = 0;
|
|
crtc->current_mode = NULL;
|
|
}
|
|
|
|
for (i = 0; i < n_outputs; i++)
|
|
{
|
|
MetaOutputInfo *output_info = outputs[i];
|
|
MetaOutput *output = output_info->output;
|
|
|
|
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 */
|
|
for (l = manager->outputs; l; l = l->next)
|
|
{
|
|
MetaOutput *output = l->data;
|
|
|
|
if (output->is_dirty)
|
|
{
|
|
output->is_dirty = FALSE;
|
|
continue;
|
|
}
|
|
|
|
output->crtc = NULL;
|
|
output->is_primary = FALSE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
update_screen_size (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config)
|
|
{
|
|
GList *l;
|
|
int screen_width = 0;
|
|
int screen_height = 0;
|
|
|
|
for (l = config->logical_monitor_configs; l; l = l->next)
|
|
{
|
|
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
|
|
int right_edge;
|
|
int bottom_edge;
|
|
|
|
right_edge = (logical_monitor_config->layout.width +
|
|
logical_monitor_config->layout.x);
|
|
if (right_edge > screen_width)
|
|
screen_width = right_edge;
|
|
|
|
bottom_edge = (logical_monitor_config->layout.height +
|
|
logical_monitor_config->layout.y);
|
|
if (bottom_edge > screen_height)
|
|
screen_height = bottom_edge;
|
|
}
|
|
|
|
manager->screen_width = screen_width;
|
|
manager->screen_height = screen_height;
|
|
}
|
|
|
|
static gboolean
|
|
meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager,
|
|
MetaMonitorsConfig *config,
|
|
MetaMonitorsConfigMethod method,
|
|
GError **error)
|
|
{
|
|
GPtrArray *crtc_infos;
|
|
GPtrArray *output_infos;
|
|
|
|
if (!config)
|
|
{
|
|
manager->screen_width = META_MONITOR_MANAGER_MIN_SCREEN_WIDTH;
|
|
manager->screen_height = META_MONITOR_MANAGER_MIN_SCREEN_HEIGHT;
|
|
meta_monitor_manager_rebuild (manager, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
if (!meta_monitor_config_manager_assign (manager, config,
|
|
&crtc_infos, &output_infos,
|
|
error))
|
|
return FALSE;
|
|
|
|
if (method == META_MONITORS_CONFIG_METHOD_VERIFY)
|
|
{
|
|
g_ptr_array_free (crtc_infos, TRUE);
|
|
g_ptr_array_free (output_infos, TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
apply_crtc_assignments (manager,
|
|
(MetaCrtcInfo **) crtc_infos->pdata,
|
|
crtc_infos->len,
|
|
(MetaOutputInfo **) output_infos->pdata,
|
|
output_infos->len);
|
|
|
|
g_ptr_array_free (crtc_infos, TRUE);
|
|
g_ptr_array_free (output_infos, TRUE);
|
|
|
|
update_screen_size (manager, config);
|
|
meta_monitor_manager_rebuild (manager, config);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager *manager,
|
|
MetaCrtc *crtc,
|
|
gsize *size,
|
|
unsigned short **red,
|
|
unsigned short **green,
|
|
unsigned short **blue)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
|
drmModeCrtc *kms_crtc;
|
|
|
|
kms_crtc = drmModeGetCrtc (manager_kms->fd, crtc->crtc_id);
|
|
|
|
*size = kms_crtc->gamma_size;
|
|
*red = g_new (unsigned short, *size);
|
|
*green = g_new (unsigned short, *size);
|
|
*blue = g_new (unsigned short, *size);
|
|
|
|
drmModeCrtcGetGamma (manager_kms->fd, crtc->crtc_id, *size, *red, *green, *blue);
|
|
|
|
drmModeFreeCrtc (kms_crtc);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
|
|
MetaCrtc *crtc,
|
|
gsize size,
|
|
unsigned short *red,
|
|
unsigned short *green,
|
|
unsigned short *blue)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
|
|
|
drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue);
|
|
}
|
|
|
|
static void
|
|
handle_hotplug_event (MetaMonitorManager *manager)
|
|
{
|
|
meta_monitor_manager_read_current_state (manager);
|
|
meta_monitor_manager_on_hotplug (manager);
|
|
}
|
|
|
|
static void
|
|
on_uevent (GUdevClient *client,
|
|
const char *action,
|
|
GUdevDevice *device,
|
|
gpointer user_data)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (user_data);
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
|
|
|
|
if (!g_udev_device_get_property_as_boolean (device, "HOTPLUG"))
|
|
return;
|
|
|
|
handle_hotplug_event (manager);
|
|
}
|
|
|
|
static gboolean
|
|
kms_event_check (GSource *source)
|
|
{
|
|
MetaKmsSource *kms_source = (MetaKmsSource *) source;
|
|
|
|
return g_source_query_unix_fd (source, kms_source->fd_tag) & G_IO_IN;
|
|
}
|
|
|
|
static gboolean
|
|
kms_event_dispatch (GSource *source,
|
|
GSourceFunc callback,
|
|
gpointer user_data)
|
|
{
|
|
MetaKmsSource *kms_source = (MetaKmsSource *) source;
|
|
|
|
meta_monitor_manager_kms_wait_for_flip (kms_source->manager_kms);
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
}
|
|
|
|
static GSourceFuncs kms_event_funcs = {
|
|
NULL,
|
|
kms_event_check,
|
|
kms_event_dispatch
|
|
};
|
|
|
|
static void
|
|
meta_monitor_manager_kms_connect_uevent_handler (MetaMonitorManagerKms *manager_kms)
|
|
{
|
|
manager_kms->uevent_handler_id = g_signal_connect (manager_kms->udev,
|
|
"uevent",
|
|
G_CALLBACK (on_uevent),
|
|
manager_kms);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_kms_disconnect_uevent_handler (MetaMonitorManagerKms *manager_kms)
|
|
{
|
|
g_signal_handler_disconnect (manager_kms->udev,
|
|
manager_kms->uevent_handler_id);
|
|
manager_kms->uevent_handler_id = 0;
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_kms_pause (MetaMonitorManagerKms *manager_kms)
|
|
{
|
|
meta_monitor_manager_kms_disconnect_uevent_handler (manager_kms);
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
|
|
|
|
meta_monitor_manager_kms_connect_uevent_handler (manager_kms);
|
|
handle_hotplug_event (manager);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
MetaRenderer *renderer = meta_backend_get_renderer (backend);
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
|
|
GSource *source;
|
|
|
|
manager_kms->fd = meta_renderer_native_get_kms_fd (renderer_native);
|
|
|
|
drmSetClientCap (manager_kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
|
|
|
|
const char *subsystems[2] = { "drm", NULL };
|
|
manager_kms->udev = g_udev_client_new (subsystems);
|
|
meta_monitor_manager_kms_connect_uevent_handler (manager_kms);
|
|
|
|
source = g_source_new (&kms_event_funcs, sizeof (MetaKmsSource));
|
|
manager_kms->source = (MetaKmsSource *) source;
|
|
manager_kms->source->fd_tag = g_source_add_unix_fd (source,
|
|
manager_kms->fd,
|
|
G_IO_IN | G_IO_ERR);
|
|
manager_kms->source->manager_kms = manager_kms;
|
|
g_source_attach (source, NULL);
|
|
}
|
|
|
|
static void
|
|
get_crtc_connectors (MetaMonitorManager *manager,
|
|
MetaCrtc *crtc,
|
|
uint32_t **connectors,
|
|
unsigned int *n_connectors)
|
|
{
|
|
GArray *connectors_array = g_array_new (FALSE, FALSE, sizeof (uint32_t));
|
|
GList *l;
|
|
|
|
for (l = manager->outputs; l; l = l->next)
|
|
{
|
|
MetaOutput *output = l->data;
|
|
|
|
if (output->crtc == crtc)
|
|
g_array_append_val (connectors_array, output->winsys_id);
|
|
}
|
|
|
|
*n_connectors = connectors_array->len;
|
|
*connectors = (uint32_t *) g_array_free (connectors_array, FALSE);
|
|
}
|
|
|
|
gboolean
|
|
meta_monitor_manager_kms_apply_crtc_mode (MetaMonitorManagerKms *manager_kms,
|
|
MetaCrtc *crtc,
|
|
int x,
|
|
int y,
|
|
uint32_t fb_id)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
|
|
uint32_t *connectors;
|
|
unsigned int n_connectors;
|
|
drmModeModeInfo *mode;
|
|
|
|
get_crtc_connectors (manager, crtc, &connectors, &n_connectors);
|
|
|
|
if (connectors)
|
|
mode = crtc->current_mode->driver_private;
|
|
else
|
|
mode = NULL;
|
|
|
|
if (drmModeSetCrtc (manager_kms->fd,
|
|
crtc->crtc_id,
|
|
fb_id,
|
|
x, y,
|
|
connectors, n_connectors,
|
|
mode) != 0)
|
|
{
|
|
g_warning ("Failed to set CRTC mode %s: %m", crtc->current_mode->name);
|
|
return FALSE;
|
|
}
|
|
|
|
g_free (connectors);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
invoke_flip_closure (GClosure *flip_closure)
|
|
{
|
|
GValue param = G_VALUE_INIT;
|
|
|
|
g_value_init (¶m, G_TYPE_POINTER);
|
|
g_value_set_pointer (¶m, flip_closure);
|
|
g_closure_invoke (flip_closure, NULL, 1, ¶m, NULL);
|
|
g_closure_unref (flip_closure);
|
|
}
|
|
|
|
gboolean
|
|
meta_monitor_manager_kms_is_crtc_active (MetaMonitorManagerKms *manager_kms,
|
|
MetaCrtc *crtc)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
|
|
GList *l;
|
|
gboolean connected_crtc_found;
|
|
|
|
if (manager->power_save_mode != META_POWER_SAVE_ON)
|
|
return FALSE;
|
|
|
|
connected_crtc_found = FALSE;
|
|
for (l = manager->outputs; l; l = l->next)
|
|
{
|
|
MetaOutput *output = l->data;
|
|
|
|
if (output->crtc == crtc)
|
|
{
|
|
connected_crtc_found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!connected_crtc_found)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
meta_monitor_manager_kms_flip_crtc (MetaMonitorManagerKms *manager_kms,
|
|
MetaCrtc *crtc,
|
|
int x,
|
|
int y,
|
|
uint32_t fb_id,
|
|
GClosure *flip_closure,
|
|
gboolean *fb_in_use)
|
|
{
|
|
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
|
|
uint32_t *connectors;
|
|
unsigned int n_connectors;
|
|
int ret = -1;
|
|
|
|
g_assert (manager->power_save_mode == META_POWER_SAVE_ON);
|
|
|
|
get_crtc_connectors (manager, crtc, &connectors, &n_connectors);
|
|
g_assert (n_connectors > 0);
|
|
|
|
if (!manager_kms->page_flips_not_supported)
|
|
{
|
|
ret = drmModePageFlip (manager_kms->fd,
|
|
crtc->crtc_id,
|
|
fb_id,
|
|
DRM_MODE_PAGE_FLIP_EVENT,
|
|
flip_closure);
|
|
if (ret != 0 && ret != -EACCES)
|
|
{
|
|
g_warning ("Failed to flip: %s", strerror (-ret));
|
|
manager_kms->page_flips_not_supported = TRUE;
|
|
}
|
|
}
|
|
|
|
if (manager_kms->page_flips_not_supported)
|
|
{
|
|
if (meta_monitor_manager_kms_apply_crtc_mode (manager_kms,
|
|
crtc,
|
|
x, y,
|
|
fb_id))
|
|
{
|
|
*fb_in_use = TRUE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (ret != 0)
|
|
return FALSE;
|
|
|
|
*fb_in_use = TRUE;
|
|
g_closure_ref (flip_closure);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
page_flip_handler (int fd,
|
|
unsigned int frame,
|
|
unsigned int sec,
|
|
unsigned int usec,
|
|
void *data)
|
|
{
|
|
GClosure *flip_closure = data;
|
|
|
|
invoke_flip_closure (flip_closure);
|
|
}
|
|
|
|
void
|
|
meta_monitor_manager_kms_wait_for_flip (MetaMonitorManagerKms *manager_kms)
|
|
{
|
|
drmEventContext evctx;
|
|
|
|
if (manager_kms->page_flips_not_supported)
|
|
return;
|
|
|
|
memset (&evctx, 0, sizeof evctx);
|
|
evctx.version = DRM_EVENT_CONTEXT_VERSION;
|
|
evctx.page_flip_handler = page_flip_handler;
|
|
drmHandleEvent (manager_kms->fd, &evctx);
|
|
}
|
|
|
|
static gboolean
|
|
meta_monitor_manager_kms_is_transform_handled (MetaMonitorManager *manager,
|
|
MetaCrtc *crtc,
|
|
MetaMonitorTransform transform)
|
|
{
|
|
MetaCrtcKms *crtc_kms = crtc->driver_private;
|
|
|
|
if ((1 << transform) & crtc_kms->all_hw_transforms)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static float
|
|
meta_monitor_manager_kms_calculate_monitor_mode_scale (MetaMonitorManager *manager,
|
|
MetaMonitor *monitor,
|
|
MetaMonitorMode *monitor_mode)
|
|
{
|
|
return meta_monitor_calculate_mode_scale (monitor, monitor_mode);
|
|
}
|
|
|
|
static float *
|
|
meta_monitor_manager_kms_calculate_supported_scales (MetaMonitorManager *manager,
|
|
MetaLogicalMonitorLayoutMode layout_mode,
|
|
MetaMonitor *monitor,
|
|
MetaMonitorMode *monitor_mode,
|
|
int *n_supported_scales)
|
|
{
|
|
MetaMonitorScalesConstraint constraints =
|
|
META_MONITOR_SCALES_CONSTRAINT_NONE;
|
|
|
|
switch (layout_mode)
|
|
{
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
|
|
break;
|
|
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
|
|
constraints |= META_MONITOR_SCALES_CONSTRAINT_NO_FRAC;
|
|
break;
|
|
}
|
|
|
|
return meta_monitor_calculate_supported_scales (monitor, monitor_mode,
|
|
constraints,
|
|
n_supported_scales);
|
|
}
|
|
|
|
static MetaMonitorManagerCapability
|
|
meta_monitor_manager_kms_get_capabilities (MetaMonitorManager *manager)
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
MetaSettings *settings = meta_backend_get_settings (backend);
|
|
MetaRenderer *renderer = meta_backend_get_renderer (backend);
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
|
|
MetaMonitorManagerCapability capabilities =
|
|
META_MONITOR_MANAGER_CAPABILITY_NONE;
|
|
|
|
if (meta_settings_is_experimental_feature_enabled (
|
|
settings,
|
|
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER))
|
|
capabilities |= META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE;
|
|
|
|
switch (meta_renderer_native_get_mode (renderer_native))
|
|
{
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
|
capabilities |= META_MONITOR_MANAGER_CAPABILITY_MIRRORING;
|
|
break;
|
|
#ifdef HAVE_EGL_DEVICE
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
return capabilities;
|
|
}
|
|
|
|
static gboolean
|
|
meta_monitor_manager_kms_get_max_screen_size (MetaMonitorManager *manager,
|
|
int *max_width,
|
|
int *max_height)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
|
|
|
if (meta_is_stage_views_enabled ())
|
|
return FALSE;
|
|
|
|
*max_width = manager_kms->max_buffer_width;
|
|
*max_height = manager_kms->max_buffer_height;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static MetaLogicalMonitorLayoutMode
|
|
meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager)
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
MetaSettings *settings = meta_backend_get_settings (backend);
|
|
|
|
if (!meta_is_stage_views_enabled ())
|
|
return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
|
|
|
|
if (meta_settings_is_experimental_feature_enabled (
|
|
settings,
|
|
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER))
|
|
return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
|
|
else
|
|
return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_kms_dispose (GObject *object)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
|
|
|
|
g_clear_object (&manager_kms->udev);
|
|
|
|
G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_kms_finalize (GObject *object)
|
|
{
|
|
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
|
|
|
|
free_resources (manager_kms);
|
|
g_source_destroy ((GSource *) manager_kms->source);
|
|
|
|
G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
|
|
{
|
|
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->dispose = meta_monitor_manager_kms_dispose;
|
|
object_class->finalize = meta_monitor_manager_kms_finalize;
|
|
|
|
manager_class->read_current = meta_monitor_manager_kms_read_current;
|
|
manager_class->read_edid = meta_monitor_manager_kms_read_edid;
|
|
manager_class->ensure_initial_config = meta_monitor_manager_kms_ensure_initial_config;
|
|
manager_class->apply_monitors_config = meta_monitor_manager_kms_apply_monitors_config;
|
|
manager_class->set_power_save_mode = meta_monitor_manager_kms_set_power_save_mode;
|
|
manager_class->get_crtc_gamma = meta_monitor_manager_kms_get_crtc_gamma;
|
|
manager_class->set_crtc_gamma = meta_monitor_manager_kms_set_crtc_gamma;
|
|
manager_class->is_transform_handled = meta_monitor_manager_kms_is_transform_handled;
|
|
manager_class->calculate_monitor_mode_scale = meta_monitor_manager_kms_calculate_monitor_mode_scale;
|
|
manager_class->calculate_supported_scales = meta_monitor_manager_kms_calculate_supported_scales;
|
|
manager_class->get_capabilities = meta_monitor_manager_kms_get_capabilities;
|
|
manager_class->get_max_screen_size = meta_monitor_manager_kms_get_max_screen_size;
|
|
manager_class->get_default_layout_mode = meta_monitor_manager_kms_get_default_layout_mode;
|
|
}
|