Commit f2d9a110 authored by Jonas Ådahl's avatar Jonas Ådahl Committed by Georges Basile Stavracas Neto

output/kms: Outsource connector state fetching to MetaKmsConnector

As with CRTC state, variable connector state is now fetched via the
MetaKmsConnector. The existance of a connector state is equivalent of
the connector being connected. MetaOutputKms is changed to fetch
variable connector state via MetaKmsConnector intsead of KMS directly.
The drmModeConnector is still used for constructing the MetaOutputKms to
find properties used for applying configuration.

#548
!525
parent 596376c4
......@@ -166,6 +166,14 @@ find_property_index (MetaGpu *gpu,
return -1;
}
MetaKmsCrtc *
meta_crtc_kms_get_kms_crtc (MetaCrtc *crtc)
{
MetaCrtcKms *crtc_kms = crtc->driver_private;
return crtc_kms->kms_crtc;
}
/**
* meta_crtc_kms_get_modifiers:
* @crtc: a #MetaCrtc object that has to be a #MetaCrtcKms
......
......@@ -45,6 +45,8 @@ gboolean meta_crtc_kms_is_transform_handled (MetaCrtc *crtc,
void meta_crtc_kms_apply_transform (MetaCrtc *crtc);
MetaKmsCrtc * meta_crtc_kms_get_kms_crtc (MetaCrtc *crtc);
GArray * meta_crtc_kms_get_modifiers (MetaCrtc *crtc,
uint32_t format);
......
......@@ -737,8 +737,7 @@ init_frame_clock (MetaGpuKms *gpu_kms)
}
static void
init_outputs (MetaGpuKms *gpu_kms,
MetaKmsResources *resources)
init_outputs (MetaGpuKms *gpu_kms)
{
MetaGpu *gpu = META_GPU (gpu_kms);
GList *old_outputs;
......@@ -770,7 +769,6 @@ init_outputs (MetaGpuKms *gpu_kms,
output = meta_create_kms_output (gpu_kms,
kms_connector,
connector,
resources,
old_output,
&error);
if (!output)
......@@ -862,7 +860,7 @@ meta_gpu_kms_read_current (MetaGpu *gpu,
init_connectors (gpu_kms, resources.resources);
init_modes (gpu_kms, resources.resources);
init_crtcs (gpu_kms);
init_outputs (gpu_kms, &resources);
init_outputs (gpu_kms);
init_frame_clock (gpu_kms);
meta_kms_resources_release (&resources);
......
......@@ -22,6 +22,9 @@
#include "backends/native/meta-kms-types.h"
void meta_kms_connector_update_state (MetaKmsConnector *connector,
drmModeRes *drm_resources);
MetaKmsConnector * meta_kms_connector_new (MetaKmsImplDevice *impl_device,
drmModeConnector *drm_connector,
drmModeRes *drm_resources);
......
......@@ -24,6 +24,7 @@
#include <errno.h>
#include "backends/native/meta-kms-device-private.h"
#include "backends/native/meta-kms-impl-device.h"
struct _MetaKmsConnector
......@@ -35,6 +36,8 @@ struct _MetaKmsConnector
uint32_t id;
MetaConnectorType type;
char *name;
MetaKmsConnectorState *current_state;
};
G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT)
......@@ -63,6 +66,377 @@ meta_kms_connector_get_name (MetaKmsConnector *connector)
return connector->name;
}
gboolean
meta_kms_connector_can_clone (MetaKmsConnector *connector,
MetaKmsConnector *other_connector)
{
MetaKmsConnectorState *state = connector->current_state;
MetaKmsConnectorState *other_state = other_connector->current_state;
if (state->common_possible_clones == 0 ||
other_state->common_possible_clones == 0)
return FALSE;
if (state->encoder_device_idxs != other_state->encoder_device_idxs)
return FALSE;
return TRUE;
}
const MetaKmsConnectorState *
meta_kms_connector_get_current_state (MetaKmsConnector *connector)
{
return connector->current_state;
}
static void
set_panel_orientation (MetaKmsConnectorState *state,
drmModePropertyPtr prop,
uint64_t orientation)
{
const char *name;
name = prop->enums[orientation].name;
if (strcmp (name, "Upside Down") == 0)
{
state->panel_orientation_transform = META_MONITOR_TRANSFORM_180;
}
else if (strcmp (name, "Left Side Up") == 0)
{
/* Left side up, rotate 90 degrees counter clockwise to correct */
state->panel_orientation_transform = META_MONITOR_TRANSFORM_90;
}
else if (strcmp (name, "Right Side Up") == 0)
{
/* Right side up, rotate 270 degrees counter clockwise to correct */
state->panel_orientation_transform = META_MONITOR_TRANSFORM_270;
}
else
{
state->panel_orientation_transform = META_MONITOR_TRANSFORM_NORMAL;
}
}
static void
state_set_properties (MetaKmsConnectorState *state,
MetaKmsImplDevice *impl_device,
drmModeConnector *drm_connector)
{
int fd;
int i;
fd = meta_kms_impl_device_get_fd (impl_device);
for (i = 0; i < drm_connector->count_props; i++)
{
drmModePropertyPtr prop;
prop = drmModeGetProperty (fd, drm_connector->props[i]);
if (!prop)
continue;
if ((prop->flags & DRM_MODE_PROP_RANGE) &&
strcmp (prop->name, "suggested X") == 0)
state->suggested_x = drm_connector->prop_values[i];
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
strcmp (prop->name, "suggested Y") == 0)
state->suggested_y = drm_connector->prop_values[i];
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
strcmp (prop->name, "hotplug_mode_update") == 0)
state->hotplug_mode_update = drm_connector->prop_values[i];
else if (strcmp (prop->name, "scaling mode") == 0)
state->has_scaling = TRUE;
else if ((prop->flags & DRM_MODE_PROP_ENUM) &&
strcmp (prop->name, "panel orientation") == 0)
set_panel_orientation (state, prop, drm_connector->prop_values[i]);
drmModeFreeProperty (prop);
}
}
static CoglSubpixelOrder
drm_subpixel_order_to_cogl_subpixel_order (drmModeSubPixel subpixel)
{
switch (subpixel)
{
case DRM_MODE_SUBPIXEL_NONE:
return COGL_SUBPIXEL_ORDER_NONE;
break;
case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
return COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
break;
case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
return COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
break;
case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
return COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
break;
case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
return COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
break;
case DRM_MODE_SUBPIXEL_UNKNOWN:
return COGL_SUBPIXEL_ORDER_UNKNOWN;
}
return COGL_SUBPIXEL_ORDER_UNKNOWN;
}
static void
state_set_edid (MetaKmsConnectorState *state,
MetaKmsConnector *connector,
MetaKmsImplDevice *impl_device,
uint32_t blob_id)
{
int fd;
drmModePropertyBlobPtr edid_blob;
GBytes *edid_data;
fd = meta_kms_impl_device_get_fd (impl_device);
edid_blob = drmModeGetPropertyBlob (fd, blob_id);
if (!edid_blob)
{
g_warning ("Failed to read EDID of connector %s: %s",
connector->name, g_strerror (errno));
return;
}
edid_data = g_bytes_new (edid_blob->data, edid_blob->length);
drmModeFreePropertyBlob (edid_blob);
state->edid_data = edid_data;
}
static void
state_set_tile_info (MetaKmsConnectorState *state,
MetaKmsConnector *connector,
MetaKmsImplDevice *impl_device,
uint32_t blob_id)
{
int fd;
drmModePropertyBlobPtr tile_blob;
state->tile_info = (MetaTileInfo) { 0 };
fd = meta_kms_impl_device_get_fd (impl_device);
tile_blob = drmModeGetPropertyBlob (fd, blob_id);
if (!tile_blob)
{
g_warning ("Failed to read TILE of connector %s: %s",
connector->name, strerror (errno));
return;
}
if (tile_blob->length > 0)
{
if (sscanf ((char *) tile_blob->data, "%d:%d:%d:%d:%d:%d:%d:%d",
&state->tile_info.group_id,
&state->tile_info.flags,
&state->tile_info.max_h_tiles,
&state->tile_info.max_v_tiles,
&state->tile_info.loc_h_tile,
&state->tile_info.loc_v_tile,
&state->tile_info.tile_w,
&state->tile_info.tile_h) != 8)
{
g_warning ("Couldn't understand TILE property blob of connector %s",
connector->name);
state->tile_info = (MetaTileInfo) { 0 };
}
}
drmModeFreePropertyBlob (tile_blob);
}
static void
state_set_blobs (MetaKmsConnectorState *state,
MetaKmsConnector *connector,
MetaKmsImplDevice *impl_device,
drmModeConnector *drm_connector)
{
int fd;
int i;
fd = meta_kms_impl_device_get_fd (impl_device);
for (i = 0; i < drm_connector->count_props; i++)
{
drmModePropertyPtr prop;
prop = drmModeGetProperty (fd, drm_connector->props[i]);
if (!prop)
continue;
if (prop->flags & DRM_MODE_PROP_BLOB)
{
uint32_t blob_id;
blob_id = drm_connector->prop_values[i];
if (blob_id)
{
if (strcmp (prop->name, "EDID") == 0)
state_set_edid (state, connector, impl_device, blob_id);
else if (strcmp (prop->name, "TILE") == 0)
state_set_tile_info (state, connector, impl_device, blob_id);
}
}
drmModeFreeProperty (prop);
}
}
static void
state_set_physical_dimensions (MetaKmsConnectorState *state,
drmModeConnector *drm_connector)
{
state->width_mm = drm_connector->mmWidth;
state->height_mm = drm_connector->mmHeight;
}
static void
state_set_modes (MetaKmsConnectorState *state,
drmModeConnector *drm_connector)
{
state->modes =
g_memdup (drm_connector->modes,
drm_connector->count_modes * sizeof (drmModeModeInfo));
state->n_modes = drm_connector->count_modes;
}
static void
set_encoder_device_idx_bit (uint32_t *encoder_device_idxs,
uint32_t encoder_id,
MetaKmsImplDevice *impl_device,
drmModeRes *drm_resources)
{
int fd;
int i;
fd = meta_kms_impl_device_get_fd (impl_device);
for (i = 0; i < drm_resources->count_encoders; i++)
{
drmModeEncoder *drm_encoder;
drm_encoder = drmModeGetEncoder (fd, drm_resources->encoders[i]);
if (!drm_encoder)
continue;
if (drm_encoder->encoder_id == encoder_id)
{
*encoder_device_idxs |= (1 << i);
break;
}
}
}
static void
state_set_crtc_state (MetaKmsConnectorState *state,
drmModeConnector *drm_connector,
MetaKmsImplDevice *impl_device,
drmModeRes *drm_resources)
{
int fd;
int i;
uint32_t common_possible_crtcs;
uint32_t common_possible_clones;
uint32_t encoder_device_idxs;
fd = meta_kms_impl_device_get_fd (impl_device);
common_possible_crtcs = UINT32_MAX;
common_possible_clones = UINT32_MAX;
encoder_device_idxs = 0;
for (i = 0; i < drm_connector->count_encoders; i++)
{
drmModeEncoder *drm_encoder;
drm_encoder = drmModeGetEncoder (fd, drm_connector->encoders[i]);
if (!drm_encoder)
continue;
common_possible_crtcs &= drm_encoder->possible_crtcs;
common_possible_clones &= drm_encoder->possible_clones;
set_encoder_device_idx_bit (&encoder_device_idxs,
drm_encoder->encoder_id,
impl_device,
drm_resources);
if (drm_connector->encoder_id == drm_encoder->encoder_id)
state->current_crtc_id = drm_encoder->crtc_id;
}
state->common_possible_crtcs = common_possible_crtcs;
state->common_possible_clones = common_possible_clones;
state->encoder_device_idxs = encoder_device_idxs;
}
static MetaKmsConnectorState *
meta_kms_connector_state_new (void)
{
MetaKmsConnectorState *state;
state = g_new0 (MetaKmsConnectorState, 1);
state->suggested_x = -1;
state->suggested_y = -1;
return state;
}
static void
meta_kms_connector_state_free (MetaKmsConnectorState *state)
{
g_clear_pointer (&state->edid_data, g_bytes_unref);
g_free (state->modes);
g_free (state);
}
static void
meta_kms_connector_read_state (MetaKmsConnector *connector,
MetaKmsImplDevice *impl_device,
drmModeConnector *drm_connector,
drmModeRes *drm_resources)
{
MetaKmsConnectorState *state;
g_clear_pointer (&connector->current_state, meta_kms_connector_state_free);
if (drm_connector->connection != DRM_MODE_CONNECTED)
return;
state = meta_kms_connector_state_new ();
state_set_blobs (state, connector, impl_device, drm_connector);
state_set_properties (state, impl_device, drm_connector);
state->subpixel_order =
drm_subpixel_order_to_cogl_subpixel_order (drm_connector->subpixel);
state_set_physical_dimensions (state, drm_connector);
state_set_modes (state, drm_connector);
state_set_crtc_state (state, drm_connector, impl_device, drm_resources);
connector->current_state = state;
}
void
meta_kms_connector_update_state (MetaKmsConnector *connector,
drmModeRes *drm_resources)
{
MetaKmsImplDevice *impl_device;
drmModeConnector *drm_connector;
impl_device = meta_kms_device_get_impl_device (connector->device);
drm_connector = drmModeGetConnector (meta_kms_impl_device_get_fd (impl_device),
connector->id);
meta_kms_connector_read_state (connector, impl_device,
drm_connector,
drm_resources);
}
static char *
make_connector_name (drmModeConnector *drm_connector)
{
......@@ -109,6 +483,10 @@ meta_kms_connector_new (MetaKmsImplDevice *impl_device,
connector->type = (MetaConnectorType) drm_connector->connector_type;
connector->name = make_connector_name (drm_connector);
meta_kms_connector_read_state (connector, impl_device,
drm_connector,
drm_resources);
return connector;
}
......@@ -117,6 +495,7 @@ meta_kms_connector_finalize (GObject *object)
{
MetaKmsConnector *connector = META_KMS_CONNECTOR (object);
g_clear_pointer (&connector->current_state, meta_kms_connector_state_free);
g_free (connector->name);
G_OBJECT_CLASS (meta_kms_connector_parent_class)->finalize (object);
......
......@@ -24,13 +24,41 @@
#include <stdint.h>
#include <xf86drmMode.h>
#include "backends/native/meta-kms-types.h"
#include "backends/meta-output.h"
#include "backends/native/meta-kms-types.h"
#define META_TYPE_KMS_CONNECTOR (meta_kms_connector_get_type ())
G_DECLARE_FINAL_TYPE (MetaKmsConnector, meta_kms_connector,
META, KMS_CONNECTOR, GObject)
typedef struct _MetaKmsConnectorState
{
uint32_t current_crtc_id;
uint32_t common_possible_crtcs;
uint32_t common_possible_clones;
uint32_t encoder_device_idxs;
drmModeModeInfo *modes;
int n_modes;
uint32_t width_mm;
uint32_t height_mm;
MetaTileInfo tile_info;
GBytes *edid_data;
gboolean has_scaling;
CoglSubpixelOrder subpixel_order;
int suggested_x;
int suggested_y;
gboolean hotplug_mode_update;
MetaMonitorTransform panel_orientation_transform;
} MetaKmsConnectorState;
MetaKmsDevice * meta_kms_connector_get_device (MetaKmsConnector *connector);
MetaConnectorType meta_kms_connector_get_connector_type (MetaKmsConnector *connector);
......@@ -39,4 +67,9 @@ uint32_t meta_kms_connector_get_id (MetaKmsConnector *connector);
const char * meta_kms_connector_get_name (MetaKmsConnector *connector);
gboolean meta_kms_connector_can_clone (MetaKmsConnector *connector,
MetaKmsConnector *other_connector);
const MetaKmsConnectorState * meta_kms_connector_get_current_state (MetaKmsConnector *connector);
#endif /* META_KMS_CONNECTOR_H */
......@@ -219,10 +219,16 @@ init_planes (MetaKmsImplDevice *impl_device)
void
meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device)
{
drmModeRes *drm_resources;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
drm_resources = drmModeGetResources (impl_device->fd);
g_list_foreach (impl_device->crtcs, (GFunc) meta_kms_crtc_update_state,
NULL);
g_list_foreach (impl_device->connectors, (GFunc) meta_kms_connector_update_state,
drm_resources);
drmModeFreeResources (drm_resources);
}
MetaKmsImplDevice *
......
......@@ -44,26 +44,11 @@ typedef struct _MetaOutputKms
drmModeConnector *connector;
/*
* 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;
uint32_t underscan_prop_id;
uint32_t underscan_hborder_prop_id;
uint32_t underscan_vborder_prop_id;
int suggested_x;
int suggested_y;
uint32_t hotplug_mode_update;
gboolean has_scaling;
} MetaOutputKms;
void
......@@ -156,177 +141,37 @@ meta_output_kms_can_clone (MetaOutput *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 (MetaGpuKms *gpu_kms,
uint32_t edid_blob_id,
GError **error)
{
int fd;
drmModePropertyBlobPtr edid_blob = NULL;
fd = meta_gpu_kms_get_fd (gpu_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 (MetaGpuKms *gpu_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 (gpu_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 (MetaGpuKms *gpu_kms,
MetaOutput *output)
{
MetaOutputKms *output_kms = output->driver_private;
int fd;