mirror of
https://github.com/brl/mutter.git
synced 2024-12-25 04:22:05 +00:00
backends/native: Move output code to its own file
Move code dealing with MetaOutputKms and related functionality to its own file. Eventually, MetaOutputKms should become a GObject based on MetaOutput, and this commit is in preparation for that. https://bugzilla.gnome.org/show_bug.cgi?id=785381
This commit is contained in:
parent
e0d839aea2
commit
7ea01693a7
@ -457,6 +457,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES += \
|
||||
backends/native/meta-monitor-manager-kms.h \
|
||||
backends/native/meta-launcher.c \
|
||||
backends/native/meta-launcher.h \
|
||||
backends/native/meta-output-kms.c \
|
||||
backends/native/meta-output-kms.h \
|
||||
backends/native/meta-renderer-native.c \
|
||||
backends/native/meta-renderer-native.h \
|
||||
backends/native/meta-stage-native.c \
|
||||
|
@ -51,7 +51,7 @@ common_resolutions = [
|
||||
|
||||
output_lines = [
|
||||
"/* Generated by gen-default-modes.py */\n",
|
||||
"const drmModeModeInfo meta_default_drm_mode_infos[] = {",
|
||||
"static const drmModeModeInfo meta_default_drm_mode_infos[] = {",
|
||||
]
|
||||
|
||||
def sync_flags(hsync, vsync):
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Generated by gen-default-modes.py */
|
||||
|
||||
const drmModeModeInfo meta_default_drm_mode_infos[] = {
|
||||
static const drmModeModeInfo meta_default_drm_mode_infos[] = {
|
||||
{ 38250, 800, 832, 912, 1024, 0, 600, 603, 607, 624, 0, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC, DRM_MODE_TYPE_DEFAULT, "800x600_60.00" },
|
||||
{ 63500, 1024, 1072, 1176, 1328, 0, 768, 771, 775, 798, 0, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC, DRM_MODE_TYPE_DEFAULT, "1024x768_60.00" },
|
||||
{ 81750, 1152, 1216, 1336, 1520, 0, 864, 867, 871, 897, 0, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC, DRM_MODE_TYPE_DEFAULT, "1152x864_60.00" },
|
||||
|
@ -29,6 +29,7 @@
|
||||
#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>
|
||||
@ -39,8 +40,6 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include <meta/main.h>
|
||||
#include <meta/errors.h>
|
||||
@ -51,33 +50,6 @@
|
||||
|
||||
#define ALL_TRANSFORMS (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)
|
||||
#define ALL_TRANSFORMS_MASK ((1 << ALL_TRANSFORMS) - 1)
|
||||
#define SYNC_TOLERANCE 0.01 /* 1 percent */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
drmModeConnector *connector;
|
||||
|
||||
unsigned n_encoders;
|
||||
drmModeEncoderPtr *encoders;
|
||||
drmModeEncoderPtr current_encoder;
|
||||
|
||||
/*
|
||||
* Bitmasks of encoder position in the resources array (used during clone
|
||||
* setup).
|
||||
*/
|
||||
uint32_t encoder_mask;
|
||||
uint32_t enc_clone_mask;
|
||||
|
||||
uint32_t dpms_prop_id;
|
||||
uint32_t edid_blob_id;
|
||||
uint32_t tile_blob_id;
|
||||
|
||||
int suggested_x;
|
||||
int suggested_y;
|
||||
uint32_t hotplug_mode_update;
|
||||
|
||||
gboolean has_scaling;
|
||||
} MetaOutputKms;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -124,6 +96,12 @@ struct _MetaMonitorManagerKmsClass
|
||||
|
||||
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)
|
||||
{
|
||||
@ -144,54 +122,6 @@ compare_outputs (gconstpointer one,
|
||||
return strcmp (o_one->name, o_two->name);
|
||||
}
|
||||
|
||||
static char *
|
||||
make_output_name (drmModeConnector *connector)
|
||||
{
|
||||
static const char * const connector_type_names[] = {
|
||||
"None",
|
||||
"VGA",
|
||||
"DVI-I",
|
||||
"DVI-D",
|
||||
"DVI-A",
|
||||
"Composite",
|
||||
"SVIDEO",
|
||||
"LVDS",
|
||||
"Component",
|
||||
"DIN",
|
||||
"DP",
|
||||
"HDMI",
|
||||
"HDMI-B",
|
||||
"TV",
|
||||
"eDP",
|
||||
"Virtual",
|
||||
"DSI",
|
||||
};
|
||||
|
||||
if (connector->connector_type < G_N_ELEMENTS (connector_type_names))
|
||||
return g_strdup_printf ("%s-%d",
|
||||
connector_type_names[connector->connector_type],
|
||||
connector->connector_type_id);
|
||||
else
|
||||
return g_strdup_printf ("Unknown%d-%d",
|
||||
connector->connector_type,
|
||||
connector->connector_type_id);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_output_destroy_notify (MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms;
|
||||
unsigned i;
|
||||
|
||||
output_kms = output->driver_private;
|
||||
|
||||
for (i = 0; i < output_kms->n_encoders; i++)
|
||||
drmModeFreeEncoder (output_kms->encoders[i]);
|
||||
g_free (output_kms->encoders);
|
||||
|
||||
g_slice_free (MetaOutputKms, output_kms);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_mode_destroy_notify (MetaCrtcMode *mode)
|
||||
{
|
||||
@ -247,44 +177,6 @@ drm_mode_hash (gconstpointer ptr)
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
find_connector_properties (MetaMonitorManagerKms *manager_kms,
|
||||
MetaOutputKms *output_kms)
|
||||
{
|
||||
int i;
|
||||
|
||||
output_kms->hotplug_mode_update = 0;
|
||||
output_kms->suggested_x = -1;
|
||||
output_kms->suggested_y = -1;
|
||||
for (i = 0; i < output_kms->connector->count_props; i++)
|
||||
{
|
||||
drmModePropertyPtr prop = drmModeGetProperty (manager_kms->fd, output_kms->connector->props[i]);
|
||||
if (!prop)
|
||||
continue;
|
||||
|
||||
if ((prop->flags & DRM_MODE_PROP_ENUM) && strcmp (prop->name, "DPMS") == 0)
|
||||
output_kms->dpms_prop_id = prop->prop_id;
|
||||
else if ((prop->flags & DRM_MODE_PROP_BLOB) && strcmp (prop->name, "EDID") == 0)
|
||||
output_kms->edid_blob_id = output_kms->connector->prop_values[i];
|
||||
else if ((prop->flags & DRM_MODE_PROP_BLOB) &&
|
||||
strcmp (prop->name, "TILE") == 0)
|
||||
output_kms->tile_blob_id = output_kms->connector->prop_values[i];
|
||||
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
|
||||
strcmp (prop->name, "suggested X") == 0)
|
||||
output_kms->suggested_x = output_kms->connector->prop_values[i];
|
||||
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
|
||||
strcmp (prop->name, "suggested Y") == 0)
|
||||
output_kms->suggested_y = output_kms->connector->prop_values[i];
|
||||
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
|
||||
strcmp (prop->name, "hotplug_mode_update") == 0)
|
||||
output_kms->hotplug_mode_update = output_kms->connector->prop_values[i];
|
||||
else if (strcmp (prop->name, "scaling mode") == 0)
|
||||
output_kms->has_scaling = TRUE;
|
||||
|
||||
drmModeFreeProperty (prop);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
find_crtc_properties (MetaMonitorManagerKms *manager_kms,
|
||||
MetaCrtc *meta_crtc)
|
||||
@ -316,99 +208,11 @@ find_crtc_properties (MetaMonitorManagerKms *manager_kms,
|
||||
}
|
||||
}
|
||||
|
||||
static drmModePropertyBlobPtr
|
||||
read_edid_blob (MetaMonitorManagerKms *manager_kms,
|
||||
uint32_t edid_blob_id,
|
||||
GError **error)
|
||||
{
|
||||
drmModePropertyBlobPtr edid_blob = NULL;
|
||||
|
||||
edid_blob = drmModeGetPropertyBlob (manager_kms->fd, edid_blob_id);
|
||||
if (!edid_blob)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
||||
"%s", strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return edid_blob;
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
read_output_edid (MetaMonitorManagerKms *manager_kms,
|
||||
MetaOutput *output,
|
||||
GError **error)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
drmModePropertyBlobPtr edid_blob;
|
||||
|
||||
g_assert (output_kms->edid_blob_id != 0);
|
||||
|
||||
edid_blob = read_edid_blob (manager_kms, output_kms->edid_blob_id, error);
|
||||
if (!edid_blob)
|
||||
return NULL;
|
||||
|
||||
if (edid_blob->length == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "EDID blob was empty");
|
||||
drmModeFreePropertyBlob (edid_blob);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_bytes_new_with_free_func (edid_blob->data, edid_blob->length,
|
||||
(GDestroyNotify) drmModeFreePropertyBlob,
|
||||
edid_blob);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_tile_info (MetaMonitorManagerKms *manager_kms,
|
||||
MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
drmModePropertyBlobPtr tile_blob = NULL;
|
||||
int ret;
|
||||
|
||||
if (output_kms->tile_blob_id == 0)
|
||||
return FALSE;
|
||||
|
||||
tile_blob = drmModeGetPropertyBlob (manager_kms->fd, output_kms->tile_blob_id);
|
||||
if (!tile_blob)
|
||||
{
|
||||
meta_warning ("Failed to read TILE of output %s: %s\n", output->name, strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (tile_blob->length > 0)
|
||||
{
|
||||
ret = sscanf ((char *)tile_blob->data, "%d:%d:%d:%d:%d:%d:%d:%d",
|
||||
&output->tile_info.group_id,
|
||||
&output->tile_info.flags,
|
||||
&output->tile_info.max_h_tiles,
|
||||
&output->tile_info.max_v_tiles,
|
||||
&output->tile_info.loc_h_tile,
|
||||
&output->tile_info.loc_v_tile,
|
||||
&output->tile_info.tile_w,
|
||||
&output->tile_info.tile_h);
|
||||
drmModeFreePropertyBlob (tile_blob);
|
||||
|
||||
if (ret != 8)
|
||||
{
|
||||
meta_warning ("Couldn't understand output tile property blob\n");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
drmModeFreePropertyBlob (tile_blob);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static MetaCrtcMode *
|
||||
mode_from_drm_mode (MetaMonitorManager *manager,
|
||||
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)
|
||||
@ -423,8 +227,8 @@ mode_from_drm_mode (MetaMonitorManager *manager,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static float
|
||||
drm_mode_vrefresh (const drmModeModeInfo *mode)
|
||||
float
|
||||
meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *mode)
|
||||
{
|
||||
float refresh = 0.0;
|
||||
|
||||
@ -453,30 +257,13 @@ create_mode (const drmModeModeInfo *drm_mode,
|
||||
mode->width = drm_mode->hdisplay;
|
||||
mode->height = drm_mode->vdisplay;
|
||||
mode->flags = drm_mode->flags;
|
||||
mode->refresh_rate = drm_mode_vrefresh (drm_mode);
|
||||
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;
|
||||
mode->driver_notify = (GDestroyNotify) meta_monitor_mode_destroy_notify;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_modes (const void *one,
|
||||
const void *two)
|
||||
{
|
||||
MetaCrtcMode *a = *(MetaCrtcMode **) one;
|
||||
MetaCrtcMode *b = *(MetaCrtcMode **) two;
|
||||
|
||||
if (a->width != b->width)
|
||||
return a->width > b->width ? -1 : 1;
|
||||
if (a->height != b->height)
|
||||
return a->height > b->height ? -1 : 1;
|
||||
if (a->refresh_rate != b->refresh_rate)
|
||||
return a->refresh_rate > b->refresh_rate ? -1 : 1;
|
||||
|
||||
return g_strcmp0 (b->name, a->name);
|
||||
}
|
||||
|
||||
static MetaOutput *
|
||||
find_output_by_id (GList *outputs,
|
||||
glong id)
|
||||
@ -627,49 +414,6 @@ init_crtc_rotations (MetaMonitorManager *manager,
|
||||
drmModeFreePlaneResources (planes);
|
||||
}
|
||||
|
||||
static void
|
||||
add_common_modes (MetaMonitorManager *manager,
|
||||
MetaOutput *output)
|
||||
{
|
||||
const drmModeModeInfo *drm_mode;
|
||||
GPtrArray *array;
|
||||
unsigned i;
|
||||
unsigned max_hdisplay = 0;
|
||||
unsigned max_vdisplay = 0;
|
||||
float max_vrefresh = 0.0;
|
||||
|
||||
for (i = 0; i < output->n_modes; i++)
|
||||
{
|
||||
drm_mode = output->modes[i]->driver_private;
|
||||
max_hdisplay = MAX (max_hdisplay, drm_mode->hdisplay);
|
||||
max_vdisplay = MAX (max_vdisplay, drm_mode->vdisplay);
|
||||
max_vrefresh = MAX (max_vrefresh, drm_mode_vrefresh (drm_mode));
|
||||
}
|
||||
|
||||
max_vrefresh = MAX (max_vrefresh, 60.0);
|
||||
max_vrefresh *= (1 + SYNC_TOLERANCE);
|
||||
|
||||
array = g_ptr_array_new ();
|
||||
for (i = 0; i < G_N_ELEMENTS (meta_default_drm_mode_infos); i++)
|
||||
{
|
||||
drm_mode = &meta_default_drm_mode_infos[i];
|
||||
if (drm_mode->hdisplay > max_hdisplay ||
|
||||
drm_mode->vdisplay > max_vdisplay ||
|
||||
drm_mode_vrefresh (drm_mode) > max_vrefresh)
|
||||
continue;
|
||||
|
||||
g_ptr_array_add (array, mode_from_drm_mode (manager, drm_mode));
|
||||
}
|
||||
|
||||
output->modes = g_renew (MetaCrtcMode *, output->modes,
|
||||
output->n_modes + array->len);
|
||||
memcpy (output->modes + output->n_modes, array->pdata,
|
||||
array->len * sizeof (MetaCrtcMode *));
|
||||
output->n_modes += array->len;
|
||||
|
||||
g_ptr_array_free (array, TRUE);
|
||||
}
|
||||
|
||||
static MetaCrtc *
|
||||
create_crtc (MetaMonitorManager *manager,
|
||||
drmModeCrtc *drm_crtc)
|
||||
@ -710,268 +454,31 @@ create_crtc (MetaMonitorManager *manager,
|
||||
return crtc;
|
||||
}
|
||||
|
||||
static MetaOutput *
|
||||
create_output (MetaMonitorManager *manager,
|
||||
drmModeConnector *connector,
|
||||
MetaOutput *old_output)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
MetaOutput *output;
|
||||
MetaOutputKms *output_kms;
|
||||
GArray *crtcs;
|
||||
GBytes *edid;
|
||||
GList *l;
|
||||
unsigned int i;
|
||||
unsigned int crtc_mask;
|
||||
|
||||
output = g_object_new (META_TYPE_OUTPUT, NULL);
|
||||
|
||||
output_kms = g_slice_new0 (MetaOutputKms);
|
||||
output->driver_private = output_kms;
|
||||
output->driver_notify = (GDestroyNotify)meta_output_destroy_notify;
|
||||
|
||||
output->monitor_manager = manager;
|
||||
output->winsys_id = connector->connector_id;
|
||||
output->name = make_output_name (connector);
|
||||
output->width_mm = connector->mmWidth;
|
||||
output->height_mm = connector->mmHeight;
|
||||
|
||||
switch (connector->subpixel)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
output->preferred_mode = NULL;
|
||||
output->n_modes = connector->count_modes;
|
||||
output->modes = g_new0 (MetaCrtcMode *, output->n_modes);
|
||||
for (i = 0; i < output->n_modes; i++) {
|
||||
output->modes[i] = mode_from_drm_mode (manager, &connector->modes[i]);
|
||||
if (connector->modes[i].type & DRM_MODE_TYPE_PREFERRED)
|
||||
output->preferred_mode = output->modes[i];
|
||||
}
|
||||
|
||||
if (!output->preferred_mode)
|
||||
output->preferred_mode = output->modes[0];
|
||||
|
||||
output_kms->connector = connector;
|
||||
find_connector_properties (manager_kms, output_kms);
|
||||
|
||||
/* FIXME: MSC feature bit? */
|
||||
/* Presume that if the output supports scaling, then we have
|
||||
* a panel fitter capable of adjusting any mode to suit.
|
||||
*/
|
||||
if (output_kms->has_scaling)
|
||||
add_common_modes (manager, output);
|
||||
|
||||
qsort (output->modes, output->n_modes, sizeof (MetaCrtcMode *), compare_modes);
|
||||
|
||||
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 (l = manager->crtcs, i = 0; l; l = l->next, i++)
|
||||
{
|
||||
if (crtc_mask & (1 << i))
|
||||
{
|
||||
MetaCrtc *crtc = l->data;
|
||||
|
||||
g_array_append_val (crtcs, crtc);
|
||||
}
|
||||
}
|
||||
|
||||
output->n_possible_crtcs = crtcs->len;
|
||||
output->possible_crtcs = (void*)g_array_free (crtcs, FALSE);
|
||||
|
||||
if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0)
|
||||
{
|
||||
for (l = manager->crtcs; l; l = l->next)
|
||||
{
|
||||
MetaCrtc *crtc = l->data;
|
||||
|
||||
if (crtc->crtc_id == output_kms->current_encoder->crtc_id)
|
||||
{
|
||||
output->crtc = crtc;
|
||||
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;
|
||||
}
|
||||
|
||||
output->suggested_x = output_kms->suggested_x;
|
||||
output->suggested_y = output_kms->suggested_y;
|
||||
output->hotplug_mode_update = output_kms->hotplug_mode_update;
|
||||
|
||||
if (output_kms->edid_blob_id != 0)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
edid = read_output_edid (manager_kms, output, &error);
|
||||
if (!edid)
|
||||
{
|
||||
g_warning ("Failed to read EDID blob from %s: %s",
|
||||
output->name, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
edid = NULL;
|
||||
}
|
||||
|
||||
meta_output_parse_edid (output, edid);
|
||||
g_bytes_unref (edid);
|
||||
|
||||
/* MetaConnectorType matches DRM's connector types */
|
||||
output->connector_type = (MetaConnectorType) connector->connector_type;
|
||||
|
||||
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;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static void
|
||||
detect_and_setup_output_clones (MetaMonitorManager *manager,
|
||||
drmModeRes *resources)
|
||||
setup_output_clones (MetaMonitorManager *manager)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
drmModeEncoder **encoders;
|
||||
unsigned int i, n_encoders;
|
||||
GList *l;
|
||||
|
||||
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]);
|
||||
|
||||
/*
|
||||
* Setup encoder position mask and encoder clone mask.
|
||||
*/
|
||||
for (l = manager->outputs; l; l = l->next)
|
||||
{
|
||||
MetaOutput *output = l->data;
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
unsigned int j;
|
||||
|
||||
output_kms->enc_clone_mask = 0xff;
|
||||
output_kms->encoder_mask = 0;
|
||||
|
||||
for (j = 0; j < output_kms->n_encoders; j++)
|
||||
{
|
||||
unsigned int k;
|
||||
|
||||
for (k = 0; k < n_encoders; k++)
|
||||
{
|
||||
if (output_kms->encoders[j] && encoders[k] &&
|
||||
output_kms->encoders[j]->encoder_id == encoders[k]->encoder_id)
|
||||
{
|
||||
output_kms->encoder_mask |= (1 << k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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 (l = manager->outputs; l; l = l->next)
|
||||
{
|
||||
MetaOutput *output = l->data;
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
GList *k;
|
||||
|
||||
if (output_kms->enc_clone_mask == 0)
|
||||
continue;
|
||||
|
||||
for (k = manager->outputs; k; k = k->next)
|
||||
{
|
||||
MetaOutput *clone = k->data;
|
||||
MetaOutputKms *clone_kms = clone->driver_private;
|
||||
MetaOutput *other_output = k->data;
|
||||
|
||||
if (clone == output)
|
||||
if (other_output == output)
|
||||
continue;
|
||||
|
||||
if (clone_kms->encoder_mask == 0)
|
||||
continue;
|
||||
|
||||
if (clone_kms->encoder_mask == output_kms->enc_clone_mask)
|
||||
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] = clone;
|
||||
output->possible_clones[output->n_possible_clones - 1] =
|
||||
other_output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1080,7 +587,7 @@ init_crtcs (MetaMonitorManager *manager,
|
||||
|
||||
static void
|
||||
init_outputs (MetaMonitorManager *manager,
|
||||
drmModeRes *resources)
|
||||
MetaKmsResources *resources)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
GList *old_outputs;
|
||||
@ -1102,7 +609,7 @@ init_outputs (MetaMonitorManager *manager,
|
||||
MetaOutput *old_output;
|
||||
|
||||
old_output = find_output_by_id (old_outputs, connector->connector_id);
|
||||
output = create_output (manager, connector, old_output);
|
||||
output = meta_create_kms_output (manager, connector, resources, old_output);
|
||||
manager->outputs = g_list_prepend (manager->outputs, output);
|
||||
}
|
||||
}
|
||||
@ -1111,19 +618,47 @@ init_outputs (MetaMonitorManager *manager,
|
||||
/* Sort the outputs for easier handling in MetaMonitorConfig */
|
||||
manager->outputs = g_list_sort (manager->outputs, compare_outputs);
|
||||
|
||||
detect_and_setup_output_clones (manager, resources);
|
||||
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);
|
||||
drmModeRes *resources;
|
||||
MetaKmsResources resources;
|
||||
|
||||
resources = drmModeGetResources (manager_kms->fd);
|
||||
meta_kms_resources_init (&resources, manager_kms->fd);
|
||||
|
||||
manager_kms->max_buffer_width = resources->max_width;
|
||||
manager_kms->max_buffer_height = resources->max_height;
|
||||
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;
|
||||
|
||||
@ -1133,43 +668,25 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
||||
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);
|
||||
init_connectors (manager, resources.resources);
|
||||
init_modes (manager, resources.resources);
|
||||
init_crtcs (manager, resources.resources);
|
||||
init_outputs (manager, &resources);
|
||||
|
||||
drmModeFreeResources (resources);
|
||||
meta_kms_resources_release (&resources);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
meta_monitor_manager_kms_read_edid (MetaMonitorManager *manager,
|
||||
MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
GError *error = NULL;
|
||||
GBytes *edid;
|
||||
|
||||
if (output_kms->edid_blob_id == 0)
|
||||
return NULL;
|
||||
|
||||
edid = read_output_edid (manager_kms, output, &error);
|
||||
if (!edid)
|
||||
{
|
||||
g_warning ("Failed to read EDID from '%s': %s",
|
||||
output->name, error->message);
|
||||
g_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return edid;
|
||||
return meta_output_kms_read_edid (output);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
|
||||
MetaPowerSave mode)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
uint64_t state;
|
||||
GList *l;
|
||||
|
||||
@ -1193,18 +710,8 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
|
||||
for (l = manager->outputs; l; l = l->next)
|
||||
{
|
||||
MetaOutput *output = l->data;
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
|
||||
if (output_kms->dpms_prop_id != 0)
|
||||
{
|
||||
int ok = drmModeObjectSetProperty (manager_kms->fd, output->winsys_id,
|
||||
DRM_MODE_OBJECT_CONNECTOR,
|
||||
output_kms->dpms_prop_id, state);
|
||||
|
||||
if (ok < 0)
|
||||
meta_warning ("Failed to set power save mode for output %s: %s\n",
|
||||
output->name, strerror (errno));
|
||||
}
|
||||
meta_output_kms_set_power_save_mode (output, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,9 @@
|
||||
#ifndef META_MONITOR_MANAGER_KMS_H
|
||||
#define META_MONITOR_MANAGER_KMS_H
|
||||
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include "meta-monitor-manager-private.h"
|
||||
|
||||
#define META_TYPE_MONITOR_MANAGER_KMS (meta_monitor_manager_kms_get_type ())
|
||||
@ -30,8 +33,20 @@ G_DECLARE_FINAL_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms,
|
||||
META, MONITOR_MANAGER_KMS,
|
||||
MetaMonitorManager)
|
||||
|
||||
typedef struct _MetaKmsResources
|
||||
{
|
||||
drmModeRes *resources;
|
||||
drmModeEncoder **encoders;
|
||||
unsigned int n_encoders;
|
||||
} MetaKmsResources;
|
||||
|
||||
typedef void (*MetaKmsFlipCallback) (void *user_data);
|
||||
|
||||
int meta_monitor_manager_kms_get_fd (MetaMonitorManagerKms *manager_kms);
|
||||
|
||||
MetaCrtcMode * meta_monitor_manager_kms_get_mode_from_drm_mode (MetaMonitorManagerKms *manager_kms,
|
||||
const drmModeModeInfo *drm_mode);
|
||||
|
||||
gboolean meta_monitor_manager_kms_apply_crtc_mode (MetaMonitorManagerKms *manager_kms,
|
||||
MetaCrtc *crtc,
|
||||
int x,
|
||||
@ -55,4 +70,6 @@ void meta_monitor_manager_kms_pause (MetaMonitorManagerKms *manager_kms);
|
||||
|
||||
void meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms);
|
||||
|
||||
float meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *mode);
|
||||
|
||||
#endif /* META_MONITOR_MANAGER_KMS_H */
|
||||
|
616
src/backends/native/meta-output-kms.c
Normal file
616
src/backends/native/meta-output-kms.c
Normal file
@ -0,0 +1,616 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Red Hat
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/native/meta-output-kms.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "backends/meta-crtc.h"
|
||||
#include "backends/native/meta-default-modes.h"
|
||||
#include "backends/native/meta-monitor-manager-kms.h"
|
||||
|
||||
#define SYNC_TOLERANCE 0.01 /* 1 percent */
|
||||
|
||||
typedef struct _MetaOutputKms
|
||||
{
|
||||
MetaOutput parent;
|
||||
|
||||
drmModeConnector *connector;
|
||||
|
||||
unsigned int n_encoders;
|
||||
drmModeEncoderPtr *encoders;
|
||||
drmModeEncoderPtr current_encoder;
|
||||
|
||||
/*
|
||||
* Bitmasks of encoder position in the resources array (used during clone
|
||||
* setup).
|
||||
*/
|
||||
uint32_t encoder_mask;
|
||||
uint32_t enc_clone_mask;
|
||||
|
||||
uint32_t dpms_prop_id;
|
||||
uint32_t edid_blob_id;
|
||||
uint32_t tile_blob_id;
|
||||
|
||||
int suggested_x;
|
||||
int suggested_y;
|
||||
uint32_t hotplug_mode_update;
|
||||
|
||||
gboolean has_scaling;
|
||||
} MetaOutputKms;
|
||||
|
||||
void
|
||||
meta_output_kms_set_power_save_mode (MetaOutput *output,
|
||||
uint64_t state)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_output_get_monitor_manager (output);
|
||||
MetaMonitorManagerKms *monitor_manager_kms =
|
||||
META_MONITOR_MANAGER_KMS (monitor_manager);
|
||||
|
||||
if (output_kms->dpms_prop_id != 0)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
|
||||
if (drmModeObjectSetProperty (fd, output->winsys_id,
|
||||
DRM_MODE_OBJECT_CONNECTOR,
|
||||
output_kms->dpms_prop_id, state) < 0)
|
||||
g_warning ("Failed to set power save mode for output %s: %s",
|
||||
output->name, strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_output_kms_can_clone (MetaOutput *output,
|
||||
MetaOutput *other_output)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
MetaOutputKms *other_output_kms = other_output->driver_private;
|
||||
|
||||
if (output_kms->enc_clone_mask == 0 ||
|
||||
other_output_kms->enc_clone_mask == 0)
|
||||
return FALSE;
|
||||
|
||||
if (output_kms->encoder_mask != other_output_kms->enc_clone_mask)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static drmModePropertyBlobPtr
|
||||
read_edid_blob (MetaMonitorManagerKms *monitor_manager_kms,
|
||||
uint32_t edid_blob_id,
|
||||
GError **error)
|
||||
{
|
||||
int fd;
|
||||
drmModePropertyBlobPtr edid_blob = NULL;
|
||||
|
||||
fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
|
||||
edid_blob = drmModeGetPropertyBlob (fd, edid_blob_id);
|
||||
if (!edid_blob)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
||||
"%s", strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return edid_blob;
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
read_output_edid (MetaMonitorManagerKms *monitor_manager_kms,
|
||||
MetaOutput *output,
|
||||
GError **error)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
drmModePropertyBlobPtr edid_blob;
|
||||
|
||||
g_assert (output_kms->edid_blob_id != 0);
|
||||
|
||||
edid_blob = read_edid_blob (monitor_manager_kms, output_kms->edid_blob_id, error);
|
||||
if (!edid_blob)
|
||||
return NULL;
|
||||
|
||||
if (edid_blob->length == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "EDID blob was empty");
|
||||
drmModeFreePropertyBlob (edid_blob);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_bytes_new_with_free_func (edid_blob->data, edid_blob->length,
|
||||
(GDestroyNotify) drmModeFreePropertyBlob,
|
||||
edid_blob);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_tile_info (MetaMonitorManagerKms *monitor_manager_kms,
|
||||
MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
int fd;
|
||||
drmModePropertyBlobPtr tile_blob = NULL;
|
||||
|
||||
if (output_kms->tile_blob_id == 0)
|
||||
return FALSE;
|
||||
|
||||
fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
|
||||
tile_blob = drmModeGetPropertyBlob (fd, output_kms->tile_blob_id);
|
||||
if (!tile_blob)
|
||||
{
|
||||
g_warning ("Failed to read TILE of output %s: %s",
|
||||
output->name, strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (tile_blob->length > 0)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sscanf ((char *)tile_blob->data, "%d:%d:%d:%d:%d:%d:%d:%d",
|
||||
&output->tile_info.group_id,
|
||||
&output->tile_info.flags,
|
||||
&output->tile_info.max_h_tiles,
|
||||
&output->tile_info.max_v_tiles,
|
||||
&output->tile_info.loc_h_tile,
|
||||
&output->tile_info.loc_v_tile,
|
||||
&output->tile_info.tile_w,
|
||||
&output->tile_info.tile_h);
|
||||
drmModeFreePropertyBlob (tile_blob);
|
||||
|
||||
if (ret != 8)
|
||||
{
|
||||
g_warning ("Couldn't understand output tile property blob");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
drmModeFreePropertyBlob (tile_blob);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
GBytes *
|
||||
meta_output_kms_read_edid (MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_output_get_monitor_manager (output);
|
||||
MetaMonitorManagerKms *monitor_manager_kms =
|
||||
META_MONITOR_MANAGER_KMS (monitor_manager);
|
||||
GError *error = NULL;
|
||||
GBytes *edid;
|
||||
|
||||
if (output_kms->edid_blob_id == 0)
|
||||
return NULL;
|
||||
|
||||
edid = read_output_edid (monitor_manager_kms, output, &error);
|
||||
if (!edid)
|
||||
{
|
||||
g_warning ("Failed to read EDID from '%s': %s",
|
||||
output->name, error->message);
|
||||
g_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return edid;
|
||||
}
|
||||
|
||||
static void
|
||||
find_connector_properties (MetaMonitorManagerKms *monitor_manager_kms,
|
||||
MetaOutputKms *output_kms)
|
||||
{
|
||||
drmModeConnector *connector = output_kms->connector;
|
||||
int fd;
|
||||
int i;
|
||||
|
||||
fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
|
||||
|
||||
output_kms->hotplug_mode_update = 0;
|
||||
output_kms->suggested_x = -1;
|
||||
output_kms->suggested_y = -1;
|
||||
|
||||
for (i = 0; i < connector->count_props; i++)
|
||||
{
|
||||
drmModePropertyPtr prop = drmModeGetProperty (fd, connector->props[i]);
|
||||
if (!prop)
|
||||
continue;
|
||||
|
||||
if ((prop->flags & DRM_MODE_PROP_ENUM) &&
|
||||
strcmp (prop->name, "DPMS") == 0)
|
||||
output_kms->dpms_prop_id = prop->prop_id;
|
||||
else if ((prop->flags & DRM_MODE_PROP_BLOB) &&
|
||||
strcmp (prop->name, "EDID") == 0)
|
||||
output_kms->edid_blob_id = connector->prop_values[i];
|
||||
else if ((prop->flags & DRM_MODE_PROP_BLOB) &&
|
||||
strcmp (prop->name, "TILE") == 0)
|
||||
output_kms->tile_blob_id = connector->prop_values[i];
|
||||
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
|
||||
strcmp (prop->name, "suggested X") == 0)
|
||||
output_kms->suggested_x = connector->prop_values[i];
|
||||
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
|
||||
strcmp (prop->name, "suggested Y") == 0)
|
||||
output_kms->suggested_y = connector->prop_values[i];
|
||||
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
|
||||
strcmp (prop->name, "hotplug_mode_update") == 0)
|
||||
output_kms->hotplug_mode_update = connector->prop_values[i];
|
||||
else if (strcmp (prop->name, "scaling mode") == 0)
|
||||
output_kms->has_scaling = TRUE;
|
||||
|
||||
drmModeFreeProperty (prop);
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
make_output_name (drmModeConnector *connector)
|
||||
{
|
||||
static const char * const connector_type_names[] = {
|
||||
"None",
|
||||
"VGA",
|
||||
"DVI-I",
|
||||
"DVI-D",
|
||||
"DVI-A",
|
||||
"Composite",
|
||||
"SVIDEO",
|
||||
"LVDS",
|
||||
"Component",
|
||||
"DIN",
|
||||
"DP",
|
||||
"HDMI",
|
||||
"HDMI-B",
|
||||
"TV",
|
||||
"eDP",
|
||||
"Virtual",
|
||||
"DSI",
|
||||
};
|
||||
|
||||
if (connector->connector_type < G_N_ELEMENTS (connector_type_names))
|
||||
return g_strdup_printf ("%s-%d",
|
||||
connector_type_names[connector->connector_type],
|
||||
connector->connector_type_id);
|
||||
else
|
||||
return g_strdup_printf ("Unknown%d-%d",
|
||||
connector->connector_type,
|
||||
connector->connector_type_id);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_output_destroy_notify (MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms;
|
||||
unsigned i;
|
||||
|
||||
output_kms = output->driver_private;
|
||||
|
||||
for (i = 0; i < output_kms->n_encoders; i++)
|
||||
drmModeFreeEncoder (output_kms->encoders[i]);
|
||||
g_free (output_kms->encoders);
|
||||
|
||||
g_slice_free (MetaOutputKms, output_kms);
|
||||
}
|
||||
|
||||
static void
|
||||
add_common_modes (MetaOutput *output,
|
||||
MetaMonitorManagerKms *monitor_manager_kms)
|
||||
{
|
||||
GPtrArray *array;
|
||||
unsigned i;
|
||||
unsigned max_hdisplay = 0;
|
||||
unsigned max_vdisplay = 0;
|
||||
float max_refresh_rate = 0.0;
|
||||
|
||||
for (i = 0; i < output->n_modes; i++)
|
||||
{
|
||||
const drmModeModeInfo *drm_mode;
|
||||
float refresh_rate;
|
||||
|
||||
drm_mode = output->modes[i]->driver_private;
|
||||
refresh_rate = meta_calculate_drm_mode_refresh_rate (drm_mode);
|
||||
max_hdisplay = MAX (max_hdisplay, drm_mode->hdisplay);
|
||||
max_vdisplay = MAX (max_vdisplay, drm_mode->vdisplay);
|
||||
max_refresh_rate = MAX (max_refresh_rate, refresh_rate);
|
||||
}
|
||||
|
||||
max_refresh_rate = MAX (max_refresh_rate, 60.0);
|
||||
max_refresh_rate *= (1 + SYNC_TOLERANCE);
|
||||
|
||||
array = g_ptr_array_new ();
|
||||
for (i = 0; i < G_N_ELEMENTS (meta_default_drm_mode_infos); i++)
|
||||
{
|
||||
const drmModeModeInfo *drm_mode;
|
||||
float refresh_rate;
|
||||
MetaCrtcMode *crtc_mode;
|
||||
|
||||
drm_mode = &meta_default_drm_mode_infos[i];
|
||||
refresh_rate = meta_calculate_drm_mode_refresh_rate (drm_mode);
|
||||
if (drm_mode->hdisplay > max_hdisplay ||
|
||||
drm_mode->vdisplay > max_vdisplay ||
|
||||
refresh_rate > max_refresh_rate)
|
||||
continue;
|
||||
|
||||
crtc_mode = meta_monitor_manager_kms_get_mode_from_drm_mode (monitor_manager_kms,
|
||||
drm_mode);
|
||||
g_ptr_array_add (array, crtc_mode);
|
||||
}
|
||||
|
||||
output->modes = g_renew (MetaCrtcMode *, output->modes,
|
||||
output->n_modes + array->len);
|
||||
memcpy (output->modes + output->n_modes, array->pdata,
|
||||
array->len * sizeof (MetaCrtcMode *));
|
||||
output->n_modes += array->len;
|
||||
|
||||
g_ptr_array_free (array, TRUE);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_modes (const void *one,
|
||||
const void *two)
|
||||
{
|
||||
MetaCrtcMode *a = *(MetaCrtcMode **) one;
|
||||
MetaCrtcMode *b = *(MetaCrtcMode **) two;
|
||||
|
||||
if (a->width != b->width)
|
||||
return a->width > b->width ? -1 : 1;
|
||||
if (a->height != b->height)
|
||||
return a->height > b->height ? -1 : 1;
|
||||
if (a->refresh_rate != b->refresh_rate)
|
||||
return a->refresh_rate > b->refresh_rate ? -1 : 1;
|
||||
|
||||
return g_strcmp0 (b->name, a->name);
|
||||
}
|
||||
|
||||
static void
|
||||
init_output_modes (MetaOutput *output,
|
||||
MetaMonitorManagerKms *monitor_manager_kms)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
unsigned int i;
|
||||
|
||||
output->preferred_mode = NULL;
|
||||
output->n_modes = output_kms->connector->count_modes;
|
||||
output->modes = g_new0 (MetaCrtcMode *, output->n_modes);
|
||||
for (i = 0; i < output->n_modes; i++)
|
||||
{
|
||||
drmModeModeInfo *drm_mode;
|
||||
MetaCrtcMode *crtc_mode;
|
||||
|
||||
drm_mode = &output_kms->connector->modes[i];
|
||||
crtc_mode =
|
||||
meta_monitor_manager_kms_get_mode_from_drm_mode (monitor_manager_kms,
|
||||
drm_mode);
|
||||
output->modes[i] = crtc_mode;
|
||||
if (output_kms->connector->modes[i].type & DRM_MODE_TYPE_PREFERRED)
|
||||
output->preferred_mode = output->modes[i];
|
||||
}
|
||||
|
||||
if (!output->preferred_mode)
|
||||
output->preferred_mode = output->modes[0];
|
||||
}
|
||||
|
||||
MetaOutput *
|
||||
meta_create_kms_output (MetaMonitorManager *monitor_manager,
|
||||
drmModeConnector *connector,
|
||||
MetaKmsResources *resources,
|
||||
MetaOutput *old_output)
|
||||
{
|
||||
MetaMonitorManagerKms *monitor_manager_kms =
|
||||
META_MONITOR_MANAGER_KMS (monitor_manager);
|
||||
MetaOutput *output;
|
||||
MetaOutputKms *output_kms;
|
||||
GArray *crtcs;
|
||||
GBytes *edid;
|
||||
GList *l;
|
||||
unsigned int i;
|
||||
unsigned int crtc_mask;
|
||||
int fd;
|
||||
|
||||
output = g_object_new (META_TYPE_OUTPUT, NULL);
|
||||
|
||||
output_kms = g_slice_new0 (MetaOutputKms);
|
||||
output->driver_private = output_kms;
|
||||
output->driver_notify = (GDestroyNotify) meta_output_destroy_notify;
|
||||
|
||||
output->monitor_manager = monitor_manager;
|
||||
output->winsys_id = connector->connector_id;
|
||||
output->name = make_output_name (connector);
|
||||
output->width_mm = connector->mmWidth;
|
||||
output->height_mm = connector->mmHeight;
|
||||
|
||||
switch (connector->subpixel)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
output_kms->connector = connector;
|
||||
find_connector_properties (monitor_manager_kms, output_kms);
|
||||
|
||||
init_output_modes (output, monitor_manager_kms);
|
||||
|
||||
/* FIXME: MSC feature bit? */
|
||||
/* Presume that if the output supports scaling, then we have
|
||||
* a panel fitter capable of adjusting any mode to suit.
|
||||
*/
|
||||
if (output_kms->has_scaling)
|
||||
add_common_modes (output, monitor_manager_kms);
|
||||
|
||||
qsort (output->modes, output->n_modes,
|
||||
sizeof (MetaCrtcMode *), compare_modes);
|
||||
|
||||
output_kms->n_encoders = connector->count_encoders;
|
||||
output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
|
||||
|
||||
fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
|
||||
|
||||
crtc_mask = ~(unsigned int) 0;
|
||||
for (i = 0; i < output_kms->n_encoders; i++)
|
||||
{
|
||||
output_kms->encoders[i] = drmModeGetEncoder (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 (l = monitor_manager->crtcs, i = 0; l; l = l->next, i++)
|
||||
{
|
||||
if (crtc_mask & (1 << i))
|
||||
{
|
||||
MetaCrtc *crtc = l->data;
|
||||
|
||||
g_array_append_val (crtcs, crtc);
|
||||
}
|
||||
}
|
||||
|
||||
output->n_possible_crtcs = crtcs->len;
|
||||
output->possible_crtcs = (void*)g_array_free (crtcs, FALSE);
|
||||
|
||||
if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0)
|
||||
{
|
||||
for (l = monitor_manager->crtcs; l; l = l->next)
|
||||
{
|
||||
MetaCrtc *crtc = l->data;
|
||||
|
||||
if (crtc->crtc_id == output_kms->current_encoder->crtc_id)
|
||||
{
|
||||
output->crtc = crtc;
|
||||
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;
|
||||
}
|
||||
|
||||
output->suggested_x = output_kms->suggested_x;
|
||||
output->suggested_y = output_kms->suggested_y;
|
||||
output->hotplug_mode_update = output_kms->hotplug_mode_update;
|
||||
|
||||
if (output_kms->edid_blob_id != 0)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
edid = read_output_edid (monitor_manager_kms, output, &error);
|
||||
if (!edid)
|
||||
{
|
||||
g_warning ("Failed to read EDID blob from %s: %s",
|
||||
output->name, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
edid = NULL;
|
||||
}
|
||||
|
||||
meta_output_parse_edid (output, edid);
|
||||
g_bytes_unref (edid);
|
||||
|
||||
/* MetaConnectorType matches DRM's connector types */
|
||||
output->connector_type = (MetaConnectorType) connector->connector_type;
|
||||
|
||||
output_get_tile_info (monitor_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;
|
||||
|
||||
output_kms->enc_clone_mask = 0xff;
|
||||
output_kms->encoder_mask = 0;
|
||||
|
||||
for (i = 0; i < output_kms->n_encoders; i++)
|
||||
{
|
||||
drmModeEncoder *output_encoder = output_kms->encoders[i];
|
||||
unsigned int j;
|
||||
|
||||
for (j = 0; j < resources->n_encoders; j++)
|
||||
{
|
||||
drmModeEncoder *encoder = resources->encoders[j];
|
||||
|
||||
if (output_encoder && encoder &&
|
||||
output_encoder->encoder_id == encoder->encoder_id)
|
||||
{
|
||||
output_kms->encoder_mask |= (1 << j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
output_kms->enc_clone_mask &= output_encoder->possible_clones;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
41
src/backends/native/meta-output-kms.h
Normal file
41
src/backends/native/meta-output-kms.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Red Hat
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef META_OUTPUT_KMS_H
|
||||
#define META_OUTPUT_KMS_H
|
||||
|
||||
#include "backends/meta-output.h"
|
||||
#include "backends/native/meta-monitor-manager-kms.h"
|
||||
|
||||
void meta_output_kms_set_power_save_mode (MetaOutput *output,
|
||||
uint64_t state);
|
||||
|
||||
gboolean meta_output_kms_can_clone (MetaOutput *output,
|
||||
MetaOutput *other_output);
|
||||
|
||||
GBytes * meta_output_kms_read_edid (MetaOutput *output);
|
||||
|
||||
MetaOutput * meta_create_kms_output (MetaMonitorManager *monitor_manager,
|
||||
drmModeConnector *connector,
|
||||
MetaKmsResources *resources,
|
||||
MetaOutput *old_output);
|
||||
|
||||
#endif /* META_OUTPUT_KMS_H */
|
Loading…
Reference in New Issue
Block a user