Compare commits
	
		
			30 Commits
		
	
	
		
			wip/carlos
			...
			wip/gbsnet
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					cf9136ecd6 | ||
| 
						 | 
					6f436023ed | ||
| 
						 | 
					d147cc3ece | ||
| 
						 | 
					f980445a54 | ||
| 
						 | 
					5977c1a183 | ||
| 
						 | 
					ff6ef0edc4 | ||
| 
						 | 
					9583632bd0 | ||
| 
						 | 
					0a1ea1407e | ||
| 
						 | 
					8ba01d3373 | ||
| 
						 | 
					a47d42f2c6 | ||
| 
						 | 
					1a0f53f5d2 | ||
| 
						 | 
					f627676878 | ||
| 
						 | 
					66079b676f | ||
| 
						 | 
					c3acb5a6e9 | ||
| 
						 | 
					dbcb6e3341 | ||
| 
						 | 
					1f3210f795 | ||
| 
						 | 
					a0eac7b417 | ||
| 
						 | 
					b9e1e28db8 | ||
| 
						 | 
					3532766c3e | ||
| 
						 | 
					881f7a07dc | ||
| 
						 | 
					a5e8aae839 | ||
| 
						 | 
					7dbe79474b | ||
| 
						 | 
					02b549bd0d | ||
| 
						 | 
					a56a6a43aa | ||
| 
						 | 
					45190c46b5 | ||
| 
						 | 
					23ef452721 | ||
| 
						 | 
					174387c4ea | ||
| 
						 | 
					db50205b1f | ||
| 
						 | 
					63c3631850 | ||
| 
						 | 
					fc87b6137c | 
@@ -181,4 +181,11 @@ void meta_backend_notify_keymap_layout_group_changed (MetaBackend *backend,
 | 
			
		||||
 | 
			
		||||
void meta_backend_notify_ui_scaling_factor_changed (MetaBackend *backend);
 | 
			
		||||
 | 
			
		||||
META_EXPORT_TEST
 | 
			
		||||
void meta_backend_add_gpu (MetaBackend *backend,
 | 
			
		||||
                           MetaGpu     *gpu);
 | 
			
		||||
 | 
			
		||||
META_EXPORT_TEST
 | 
			
		||||
GList * meta_backend_get_gpus (MetaBackend *backend);
 | 
			
		||||
 | 
			
		||||
#endif /* META_BACKEND_PRIVATE_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -89,6 +89,7 @@ enum
 | 
			
		||||
  KEYMAP_LAYOUT_GROUP_CHANGED,
 | 
			
		||||
  LAST_DEVICE_CHANGED,
 | 
			
		||||
  LID_IS_CLOSED_CHANGED,
 | 
			
		||||
  GPU_ADDED,
 | 
			
		||||
 | 
			
		||||
  N_SIGNALS
 | 
			
		||||
};
 | 
			
		||||
@@ -138,6 +139,8 @@ struct _MetaBackendPrivate
 | 
			
		||||
  ClutterBackend *clutter_backend;
 | 
			
		||||
  ClutterActor *stage;
 | 
			
		||||
 | 
			
		||||
  GList *gpus;
 | 
			
		||||
 | 
			
		||||
  gboolean is_pointer_position_initialized;
 | 
			
		||||
 | 
			
		||||
  guint device_update_idle_id;
 | 
			
		||||
@@ -175,6 +178,8 @@ meta_backend_finalize (GObject *object)
 | 
			
		||||
  MetaBackend *backend = META_BACKEND (object);
 | 
			
		||||
  MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
 | 
			
		||||
 | 
			
		||||
  g_list_free_full (priv->gpus, g_object_unref);
 | 
			
		||||
 | 
			
		||||
  g_clear_object (&priv->monitor_manager);
 | 
			
		||||
  g_clear_object (&priv->orientation_manager);
 | 
			
		||||
  g_clear_object (&priv->input_settings);
 | 
			
		||||
@@ -752,6 +757,18 @@ meta_backend_class_init (MetaBackendClass *klass)
 | 
			
		||||
                  0,
 | 
			
		||||
                  NULL, NULL, NULL,
 | 
			
		||||
                  G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
 | 
			
		||||
  /**
 | 
			
		||||
   * MetaBackend::gpu-added: (skip)
 | 
			
		||||
   * @backend: the #MetaBackend
 | 
			
		||||
   * @gpu: the #MetaGpu
 | 
			
		||||
   */
 | 
			
		||||
  signals[GPU_ADDED] =
 | 
			
		||||
    g_signal_new ("gpu-added",
 | 
			
		||||
                  G_TYPE_FROM_CLASS (klass),
 | 
			
		||||
                  G_SIGNAL_RUN_LAST,
 | 
			
		||||
                  0,
 | 
			
		||||
                  NULL, NULL, NULL,
 | 
			
		||||
                  G_TYPE_NONE, 1, META_TYPE_GPU);
 | 
			
		||||
 | 
			
		||||
  mutter_stage_views = g_getenv ("MUTTER_STAGE_VIEWS");
 | 
			
		||||
  stage_views_disabled = g_strcmp0 (mutter_stage_views, "0") == 0;
 | 
			
		||||
@@ -1399,3 +1416,22 @@ meta_backend_notify_keymap_layout_group_changed (MetaBackend *backend,
 | 
			
		||||
  g_signal_emit (backend, signals[KEYMAP_LAYOUT_GROUP_CHANGED], 0,
 | 
			
		||||
                 locked_group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_backend_add_gpu (MetaBackend *backend,
 | 
			
		||||
                      MetaGpu     *gpu)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
 | 
			
		||||
 | 
			
		||||
  priv->gpus = g_list_append (priv->gpus, gpu);
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (backend, signals[GPU_ADDED], 0, gpu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_backend_get_gpus (MetaBackend *backend)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
 | 
			
		||||
 | 
			
		||||
  return priv->gpus;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,13 +23,14 @@
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-gpu.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "backends/meta-output.h"
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  PROP_0,
 | 
			
		||||
 | 
			
		||||
  PROP_MONITOR_MANAGER,
 | 
			
		||||
  PROP_BACKEND,
 | 
			
		||||
 | 
			
		||||
  PROP_LAST
 | 
			
		||||
};
 | 
			
		||||
@@ -38,7 +39,7 @@ static GParamSpec *obj_props[PROP_LAST];
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaGpuPrivate
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *monitor_manager;
 | 
			
		||||
  MetaBackend *backend;
 | 
			
		||||
 | 
			
		||||
  GList *outputs;
 | 
			
		||||
  GList *crtcs;
 | 
			
		||||
@@ -88,12 +89,12 @@ meta_gpu_read_current (MetaGpu  *gpu,
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaMonitorManager *
 | 
			
		||||
meta_gpu_get_monitor_manager (MetaGpu *gpu)
 | 
			
		||||
MetaBackend *
 | 
			
		||||
meta_gpu_get_backend (MetaGpu *gpu)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpuPrivate *priv = meta_gpu_get_instance_private (gpu);
 | 
			
		||||
 | 
			
		||||
  return priv->monitor_manager;
 | 
			
		||||
  return priv->backend;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
@@ -158,8 +159,8 @@ meta_gpu_set_property (GObject      *object,
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_MONITOR_MANAGER:
 | 
			
		||||
      priv->monitor_manager = g_value_get_object (value);
 | 
			
		||||
    case PROP_BACKEND:
 | 
			
		||||
      priv->backend = g_value_get_object (value);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
@@ -177,8 +178,8 @@ meta_gpu_get_property (GObject    *object,
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_MONITOR_MANAGER:
 | 
			
		||||
      g_value_set_object (value, priv->monitor_manager);
 | 
			
		||||
    case PROP_BACKEND:
 | 
			
		||||
      g_value_set_object (value, priv->backend);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
@@ -212,11 +213,11 @@ meta_gpu_class_init (MetaGpuClass *klass)
 | 
			
		||||
  object_class->get_property = meta_gpu_get_property;
 | 
			
		||||
  object_class->finalize = meta_gpu_finalize;
 | 
			
		||||
 | 
			
		||||
  obj_props[PROP_MONITOR_MANAGER] =
 | 
			
		||||
    g_param_spec_object ("monitor-manager",
 | 
			
		||||
                         "monitor-manager",
 | 
			
		||||
                         "MetaMonitorManager",
 | 
			
		||||
                         META_TYPE_MONITOR_MANAGER,
 | 
			
		||||
  obj_props[PROP_BACKEND] =
 | 
			
		||||
    g_param_spec_object ("backend",
 | 
			
		||||
                         "backend",
 | 
			
		||||
                         "MetaBackend",
 | 
			
		||||
                         META_TYPE_BACKEND,
 | 
			
		||||
                         G_PARAM_READWRITE |
 | 
			
		||||
                         G_PARAM_CONSTRUCT_ONLY |
 | 
			
		||||
                         G_PARAM_STATIC_STRINGS);
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ META_EXPORT_TEST
 | 
			
		||||
gboolean meta_gpu_has_hotplug_mode_update (MetaGpu *gpu);
 | 
			
		||||
 | 
			
		||||
META_EXPORT_TEST
 | 
			
		||||
MetaMonitorManager * meta_gpu_get_monitor_manager (MetaGpu *gpu);
 | 
			
		||||
MetaBackend * meta_gpu_get_backend (MetaGpu *gpu);
 | 
			
		||||
 | 
			
		||||
META_EXPORT_TEST
 | 
			
		||||
GList * meta_gpu_get_outputs (MetaGpu *gpu);
 | 
			
		||||
 
 | 
			
		||||
@@ -242,6 +242,7 @@ foreach_crtc (MetaMonitor         *monitor,
 | 
			
		||||
  ForeachCrtcData *data = user_data;
 | 
			
		||||
 | 
			
		||||
  data->func (data->logical_monitor,
 | 
			
		||||
              monitor_crtc_mode->output,
 | 
			
		||||
              meta_output_get_assigned_crtc (monitor_crtc_mode->output),
 | 
			
		||||
              data->user_data);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -63,6 +63,7 @@ G_DECLARE_FINAL_TYPE (MetaLogicalMonitor, meta_logical_monitor,
 | 
			
		||||
                      GObject)
 | 
			
		||||
 | 
			
		||||
typedef void (* MetaLogicalMonitorCrtcFunc) (MetaLogicalMonitor *logical_monitor,
 | 
			
		||||
                                             MetaOutput         *output,
 | 
			
		||||
                                             MetaCrtc           *crtc,
 | 
			
		||||
                                             gpointer            user_data);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,8 +47,6 @@ struct _MetaMonitorManagerDummy
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager parent_instance;
 | 
			
		||||
 | 
			
		||||
  MetaGpu *gpu;
 | 
			
		||||
 | 
			
		||||
  gboolean is_transform_handled;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -98,6 +96,14 @@ create_mode (CrtcModeSpec *spec,
 | 
			
		||||
  return mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaGpu *
 | 
			
		||||
get_gpu (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
 | 
			
		||||
  return META_GPU (meta_backend_get_gpus (backend)->data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
append_monitor (MetaMonitorManager *manager,
 | 
			
		||||
                GList             **modes,
 | 
			
		||||
@@ -105,8 +111,7 @@ append_monitor (MetaMonitorManager *manager,
 | 
			
		||||
                GList             **outputs,
 | 
			
		||||
                float               scale)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerDummy *manager_dummy = META_MONITOR_MANAGER_DUMMY (manager);
 | 
			
		||||
  MetaGpu *gpu = manager_dummy->gpu;
 | 
			
		||||
  MetaGpu *gpu = get_gpu (manager);
 | 
			
		||||
  CrtcModeSpec default_specs[] = {
 | 
			
		||||
    {
 | 
			
		||||
      .width = 800,
 | 
			
		||||
@@ -246,8 +251,7 @@ append_tiled_monitor (MetaMonitorManager *manager,
 | 
			
		||||
                      GList             **outputs,
 | 
			
		||||
                      int                 scale)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerDummy *manager_dummy = META_MONITOR_MANAGER_DUMMY (manager);
 | 
			
		||||
  MetaGpu *gpu = manager_dummy->gpu;
 | 
			
		||||
  MetaGpu *gpu = get_gpu (manager);
 | 
			
		||||
  CrtcModeSpec mode_specs[] = {
 | 
			
		||||
    {
 | 
			
		||||
      .width = 800,
 | 
			
		||||
@@ -371,8 +375,7 @@ meta_output_dummy_notify_destroy (MetaOutput *output)
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_dummy_read_current (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerDummy *manager_dummy = META_MONITOR_MANAGER_DUMMY (manager);
 | 
			
		||||
  MetaGpu *gpu = manager_dummy->gpu;
 | 
			
		||||
  MetaGpu *gpu = get_gpu (manager);
 | 
			
		||||
  unsigned int num_monitors = 1;
 | 
			
		||||
  float *monitor_scales = NULL;
 | 
			
		||||
  const char *num_monitors_str;
 | 
			
		||||
@@ -495,7 +498,6 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
                        MetaOutputInfo    **outputs,
 | 
			
		||||
                        unsigned int        n_outputs)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerDummy *manager_dummy = META_MONITOR_MANAGER_DUMMY (manager);
 | 
			
		||||
  GList *l;
 | 
			
		||||
  unsigned i;
 | 
			
		||||
 | 
			
		||||
@@ -560,7 +562,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable CRTCs not mentioned in the list */
 | 
			
		||||
  for (l = meta_gpu_get_crtcs (manager_dummy->gpu); l; l = l->next)
 | 
			
		||||
  for (l = meta_gpu_get_crtcs (get_gpu (manager)); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaCrtc *crtc = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -580,7 +582,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable outputs not mentioned in the list */
 | 
			
		||||
  for (l = meta_gpu_get_outputs (manager_dummy->gpu); l; l = l->next)
 | 
			
		||||
  for (l = meta_gpu_get_outputs (get_gpu (manager)); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *output = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -772,11 +774,32 @@ meta_monitor_manager_dummy_get_default_layout_mode (MetaMonitorManager *manager)
 | 
			
		||||
    return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_dummy_constructed (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerDummy *manager_dummy = META_MONITOR_MANAGER_DUMMY (object);
 | 
			
		||||
  const char *nested_offscreen_transform;
 | 
			
		||||
  GObjectClass *parent_object_class =
 | 
			
		||||
    G_OBJECT_CLASS (meta_monitor_manager_dummy_parent_class);
 | 
			
		||||
 | 
			
		||||
  parent_object_class->constructed (object);
 | 
			
		||||
 | 
			
		||||
  nested_offscreen_transform =
 | 
			
		||||
    g_getenv ("MUTTER_DEBUG_NESTED_OFFSCREEN_TRANSFORM");
 | 
			
		||||
  if (g_strcmp0 (nested_offscreen_transform, "1") == 0)
 | 
			
		||||
    manager_dummy->is_transform_handled = FALSE;
 | 
			
		||||
  else
 | 
			
		||||
    manager_dummy->is_transform_handled = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
  MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->constructed = meta_monitor_manager_dummy_constructed;
 | 
			
		||||
 | 
			
		||||
  manager_class->ensure_initial_config = meta_monitor_manager_dummy_ensure_initial_config;
 | 
			
		||||
  manager_class->apply_monitors_config = meta_monitor_manager_dummy_apply_monitors_config;
 | 
			
		||||
  manager_class->is_transform_handled = meta_monitor_manager_dummy_is_transform_handled;
 | 
			
		||||
@@ -790,27 +813,14 @@ meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass)
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_dummy_init (MetaMonitorManagerDummy *manager_dummy)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_dummy);
 | 
			
		||||
  const char *nested_offscreen_transform;
 | 
			
		||||
 | 
			
		||||
  nested_offscreen_transform =
 | 
			
		||||
    g_getenv ("MUTTER_DEBUG_NESTED_OFFSCREEN_TRANSFORM");
 | 
			
		||||
  if (g_strcmp0 (nested_offscreen_transform, "1") == 0)
 | 
			
		||||
    manager_dummy->is_transform_handled = FALSE;
 | 
			
		||||
  else
 | 
			
		||||
    manager_dummy->is_transform_handled = TRUE;
 | 
			
		||||
 | 
			
		||||
  manager_dummy->gpu = g_object_new (META_TYPE_GPU_DUMMY,
 | 
			
		||||
                                     "monitor-manager", manager,
 | 
			
		||||
                                     NULL);
 | 
			
		||||
  meta_monitor_manager_add_gpu (manager, manager_dummy->gpu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_gpu_dummy_read_current (MetaGpu  *gpu,
 | 
			
		||||
                             GError  **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager = meta_gpu_get_monitor_manager (gpu);
 | 
			
		||||
  MetaBackend *backend = meta_gpu_get_backend (gpu);
 | 
			
		||||
  MetaMonitorManager *manager = meta_backend_get_monitor_manager (backend);
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_dummy_read_current (manager);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -121,8 +121,6 @@ struct _MetaMonitorManager
 | 
			
		||||
  int screen_width;
 | 
			
		||||
  int screen_height;
 | 
			
		||||
 | 
			
		||||
  GList *gpus;
 | 
			
		||||
 | 
			
		||||
  GList *monitors;
 | 
			
		||||
 | 
			
		||||
  GList *logical_monitors;
 | 
			
		||||
@@ -248,6 +246,7 @@ struct _MetaMonitorManagerClass
 | 
			
		||||
  MetaLogicalMonitorLayoutMode (*get_default_layout_mode) (MetaMonitorManager *);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
META_EXPORT_TEST
 | 
			
		||||
MetaBackend *       meta_monitor_manager_get_backend (MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
void                meta_monitor_manager_setup (MetaMonitorManager *manager);
 | 
			
		||||
@@ -295,12 +294,6 @@ MetaMonitor *       meta_monitor_manager_get_monitor_from_connector (MetaMonitor
 | 
			
		||||
META_EXPORT_TEST
 | 
			
		||||
GList *             meta_monitor_manager_get_monitors      (MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
META_EXPORT_TEST
 | 
			
		||||
void                meta_monitor_manager_add_gpu (MetaMonitorManager *manager,
 | 
			
		||||
                                                  MetaGpu            *gpu);
 | 
			
		||||
META_EXPORT_TEST
 | 
			
		||||
GList *             meta_monitor_manager_get_gpus (MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
void                meta_monitor_manager_get_screen_size   (MetaMonitorManager *manager,
 | 
			
		||||
                                                            int                *width,
 | 
			
		||||
                                                            int                *height);
 | 
			
		||||
 
 | 
			
		||||
@@ -511,9 +511,11 @@ meta_monitor_manager_apply_monitors_config (MetaMonitorManager      *manager,
 | 
			
		||||
gboolean
 | 
			
		||||
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  GList *gpus;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = manager->gpus; l; l = l->next)
 | 
			
		||||
  gpus = meta_backend_get_gpus (manager->backend);
 | 
			
		||||
  for (l = gpus; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpu *gpu = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -794,7 +796,6 @@ meta_monitor_manager_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
 | 
			
		||||
 | 
			
		||||
  g_list_free_full (manager->gpus, g_object_unref);
 | 
			
		||||
  g_list_free_full (manager->logical_monitors, g_object_unref);
 | 
			
		||||
 | 
			
		||||
  g_signal_handler_disconnect (manager->backend,
 | 
			
		||||
@@ -1063,10 +1064,12 @@ static GList *
 | 
			
		||||
combine_gpu_lists (MetaMonitorManager    *manager,
 | 
			
		||||
                   GList              * (*list_getter) (MetaGpu *gpu))
 | 
			
		||||
{
 | 
			
		||||
  GList *gpus;
 | 
			
		||||
  GList *list = NULL;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = manager->gpus; l; l = l->next)
 | 
			
		||||
  gpus = meta_backend_get_gpus (manager->backend);
 | 
			
		||||
  for (l = gpus; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpu *gpu = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -2676,26 +2679,6 @@ meta_monitor_manager_get_monitors (MetaMonitorManager *manager)
 | 
			
		||||
  return manager->monitors;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_monitor_manager_add_gpu:
 | 
			
		||||
 * @manager: A #MetaMonitorManager object
 | 
			
		||||
 *
 | 
			
		||||
 * Should only be called by subclasses. Adds a #MetaGpu to the internal list of
 | 
			
		||||
 * GPU's.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_add_gpu (MetaMonitorManager *manager,
 | 
			
		||||
                              MetaGpu            *gpu)
 | 
			
		||||
{
 | 
			
		||||
  manager->gpus = g_list_append (manager->gpus, gpu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_monitor_manager_get_gpus (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  return manager->gpus;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
 | 
			
		||||
                                      int                *width,
 | 
			
		||||
@@ -2717,6 +2700,7 @@ meta_monitor_manager_get_power_save_mode (MetaMonitorManager *manager)
 | 
			
		||||
static void
 | 
			
		||||
rebuild_monitors (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  GList *gpus;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  if (manager->monitors)
 | 
			
		||||
@@ -2725,7 +2709,8 @@ rebuild_monitors (MetaMonitorManager *manager)
 | 
			
		||||
      manager->monitors = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (l = manager->gpus; l; l = l->next)
 | 
			
		||||
  gpus = meta_backend_get_gpus (manager->backend);
 | 
			
		||||
  for (l = gpus; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpu *gpu = l->data;
 | 
			
		||||
      GList *k;
 | 
			
		||||
@@ -2740,7 +2725,7 @@ rebuild_monitors (MetaMonitorManager *manager)
 | 
			
		||||
                {
 | 
			
		||||
                  MetaMonitorTiled *monitor_tiled;
 | 
			
		||||
 | 
			
		||||
                  monitor_tiled = meta_monitor_tiled_new (gpu, output);
 | 
			
		||||
                  monitor_tiled = meta_monitor_tiled_new (gpu, manager, output);
 | 
			
		||||
                  manager->monitors = g_list_append (manager->monitors,
 | 
			
		||||
                                                     monitor_tiled);
 | 
			
		||||
                }
 | 
			
		||||
@@ -2797,7 +2782,7 @@ meta_monitor_manager_real_read_current_state (MetaMonitorManager *manager)
 | 
			
		||||
 | 
			
		||||
  manager->serial++;
 | 
			
		||||
 | 
			
		||||
  for (l = manager->gpus; l; l = l->next)
 | 
			
		||||
  for (l = meta_backend_get_gpus (manager->backend); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpu *gpu = l->data;
 | 
			
		||||
      GError *error = NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@ enum _MetaMonitorTransform
 | 
			
		||||
  META_MONITOR_TRANSFORM_FLIPPED_180,
 | 
			
		||||
  META_MONITOR_TRANSFORM_FLIPPED_270,
 | 
			
		||||
};
 | 
			
		||||
#define META_MONITOR_N_TRANSFORMS (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)
 | 
			
		||||
 | 
			
		||||
/* Returns true if transform causes width and height to be inverted
 | 
			
		||||
   This is true for the odd transforms in the enum */
 | 
			
		||||
 
 | 
			
		||||
@@ -90,6 +90,8 @@ struct _MetaMonitorTiled
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitor parent;
 | 
			
		||||
 | 
			
		||||
  MetaMonitorManager *monitor_manager;
 | 
			
		||||
 | 
			
		||||
  uint32_t tile_group_id;
 | 
			
		||||
 | 
			
		||||
  /* The tile (0, 0) output. */
 | 
			
		||||
@@ -1177,9 +1179,9 @@ meta_monitor_tiled_generate_modes (MetaMonitorTiled *monitor_tiled)
 | 
			
		||||
 | 
			
		||||
MetaMonitorTiled *
 | 
			
		||||
meta_monitor_tiled_new (MetaGpu            *gpu,
 | 
			
		||||
                        MetaMonitorManager *monitor_manager,
 | 
			
		||||
                        MetaOutput         *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *monitor_manager;
 | 
			
		||||
  MetaMonitorTiled *monitor_tiled;
 | 
			
		||||
  MetaMonitor *monitor;
 | 
			
		||||
  MetaMonitorPrivate *monitor_priv;
 | 
			
		||||
@@ -1200,7 +1202,7 @@ meta_monitor_tiled_new (MetaGpu    *gpu,
 | 
			
		||||
 | 
			
		||||
  meta_monitor_generate_spec (monitor);
 | 
			
		||||
 | 
			
		||||
  monitor_manager = meta_gpu_get_monitor_manager (gpu);
 | 
			
		||||
  monitor_tiled->monitor_manager = monitor_manager;
 | 
			
		||||
  meta_monitor_manager_tiled_monitor_added (monitor_manager,
 | 
			
		||||
                                            META_MONITOR (monitor_tiled));
 | 
			
		||||
 | 
			
		||||
@@ -1286,14 +1288,10 @@ meta_monitor_tiled_calculate_crtc_pos (MetaMonitor          *monitor,
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_tiled_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitor *monitor = META_MONITOR (object);
 | 
			
		||||
  MetaMonitorPrivate *monitor_priv =
 | 
			
		||||
    meta_monitor_get_instance_private (monitor);
 | 
			
		||||
  MetaMonitorManager *monitor_manager;
 | 
			
		||||
  MetaMonitorTiled *monitor_tiled = META_MONITOR_TILED (object);
 | 
			
		||||
 | 
			
		||||
  monitor_manager = meta_gpu_get_monitor_manager (monitor_priv->gpu);
 | 
			
		||||
  meta_monitor_manager_tiled_monitor_removed (monitor_manager,
 | 
			
		||||
                                              monitor);
 | 
			
		||||
  meta_monitor_manager_tiled_monitor_removed (monitor_tiled->monitor_manager,
 | 
			
		||||
                                              META_MONITOR (monitor_tiled));
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_monitor_tiled_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -97,6 +97,7 @@ G_DECLARE_FINAL_TYPE (MetaMonitorTiled, meta_monitor_tiled,
 | 
			
		||||
 | 
			
		||||
META_EXPORT_TEST
 | 
			
		||||
MetaMonitorTiled * meta_monitor_tiled_new (MetaGpu            *gpu,
 | 
			
		||||
                                           MetaMonitorManager *monitor_manager,
 | 
			
		||||
                                           MetaOutput         *output);
 | 
			
		||||
 | 
			
		||||
META_EXPORT_TEST
 | 
			
		||||
 
 | 
			
		||||
@@ -113,7 +113,9 @@ meta_screen_cast_monitor_stream_new (MetaScreenCastSession     *session,
 | 
			
		||||
                                     GError                   **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = meta_monitor_get_gpu (monitor);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
 | 
			
		||||
  MetaBackend *backend = meta_gpu_get_backend (gpu);
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  MetaScreenCastMonitorStream *monitor_stream;
 | 
			
		||||
 | 
			
		||||
  if (!meta_monitor_is_active (monitor))
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								src/backends/native/meta-backend-native-types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/backends/native/meta-backend-native-types.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_BACKEND_NATIVE_TYPES_H
 | 
			
		||||
#define META_BACKEND_NATIVE_TYPES_H
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaBackendNative MetaBackendNative;
 | 
			
		||||
 | 
			
		||||
#endif /* META_BACKEND_NATIVE_TYPES_H */
 | 
			
		||||
@@ -51,6 +51,8 @@
 | 
			
		||||
#include "backends/native/meta-clutter-backend-native.h"
 | 
			
		||||
#include "backends/native/meta-cursor-renderer-native.h"
 | 
			
		||||
#include "backends/native/meta-input-settings-native.h"
 | 
			
		||||
#include "backends/native/meta-kms.h"
 | 
			
		||||
#include "backends/native/meta-kms-device.h"
 | 
			
		||||
#include "backends/native/meta-launcher.h"
 | 
			
		||||
#include "backends/native/meta-monitor-manager-kms.h"
 | 
			
		||||
#include "backends/native/meta-renderer-native.h"
 | 
			
		||||
@@ -62,14 +64,14 @@
 | 
			
		||||
struct _MetaBackendNative
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend parent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaBackendNativePrivate
 | 
			
		||||
{
 | 
			
		||||
  MetaLauncher *launcher;
 | 
			
		||||
  MetaUdev *udev;
 | 
			
		||||
  MetaKms *kms;
 | 
			
		||||
  MetaBarrierManagerNative *barrier_manager;
 | 
			
		||||
 | 
			
		||||
  guint udev_device_added_handler_id;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _MetaBackendNativePrivate MetaBackendNativePrivate;
 | 
			
		||||
 | 
			
		||||
static GInitableIface *initable_parent_iface;
 | 
			
		||||
 | 
			
		||||
@@ -77,17 +79,23 @@ static void
 | 
			
		||||
initable_iface_init (GInitableIface *initable_iface);
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE_WITH_CODE (MetaBackendNative, meta_backend_native, META_TYPE_BACKEND,
 | 
			
		||||
                         G_ADD_PRIVATE (MetaBackendNative)
 | 
			
		||||
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
 | 
			
		||||
                                                initable_iface_init))
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
disconnect_udev_device_added_handler (MetaBackendNative *native);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_native_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendNative *native = META_BACKEND_NATIVE (object);
 | 
			
		||||
  MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
 | 
			
		||||
 | 
			
		||||
  meta_launcher_free (priv->launcher);
 | 
			
		||||
  if (native->udev_device_added_handler_id)
 | 
			
		||||
    disconnect_udev_device_added_handler (native);
 | 
			
		||||
 | 
			
		||||
  g_clear_object (&native->udev);
 | 
			
		||||
  g_clear_object (&native->kms);
 | 
			
		||||
  meta_launcher_free (native->launcher);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
@@ -99,10 +107,8 @@ constrain_to_barriers (ClutterInputDevice *device,
 | 
			
		||||
                       float              *new_y)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendNative *native = META_BACKEND_NATIVE (meta_get_backend ());
 | 
			
		||||
  MetaBackendNativePrivate *priv =
 | 
			
		||||
    meta_backend_native_get_instance_private (native);
 | 
			
		||||
 | 
			
		||||
  meta_barrier_manager_native_process (priv->barrier_manager,
 | 
			
		||||
  meta_barrier_manager_native_process (native->barrier_manager,
 | 
			
		||||
                                       device,
 | 
			
		||||
                                       time,
 | 
			
		||||
                                       new_x, new_y);
 | 
			
		||||
@@ -376,13 +382,10 @@ static MetaRenderer *
 | 
			
		||||
meta_backend_native_create_renderer (MetaBackend *backend,
 | 
			
		||||
                                     GError     **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  MetaMonitorManagerKms *monitor_manager_kms =
 | 
			
		||||
    META_MONITOR_MANAGER_KMS (monitor_manager);
 | 
			
		||||
  MetaBackendNative *native = META_BACKEND_NATIVE (backend);
 | 
			
		||||
  MetaRendererNative *renderer_native;
 | 
			
		||||
 | 
			
		||||
  renderer_native = meta_renderer_native_new (monitor_manager_kms, error);
 | 
			
		||||
  renderer_native = meta_renderer_native_new (native, error);
 | 
			
		||||
  if (!renderer_native)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
@@ -519,11 +522,142 @@ meta_backend_native_update_screen_size (MetaBackend *backend,
 | 
			
		||||
  clutter_actor_set_size (stage, width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaGpuKms *
 | 
			
		||||
create_gpu_from_udev_device (MetaBackendNative  *native,
 | 
			
		||||
                             GUdevDevice        *device,
 | 
			
		||||
                             GError            **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsDeviceFlag flags = META_KMS_DEVICE_FLAG_NONE;
 | 
			
		||||
  const char *device_path;
 | 
			
		||||
  MetaKmsDevice *kms_device;
 | 
			
		||||
 | 
			
		||||
  if (meta_is_udev_device_platform_device (device))
 | 
			
		||||
    flags |= META_KMS_DEVICE_FLAG_PLATFORM_DEVICE;
 | 
			
		||||
 | 
			
		||||
  if (meta_is_udev_device_boot_vga (device))
 | 
			
		||||
    flags |= META_KMS_DEVICE_FLAG_BOOT_VGA;
 | 
			
		||||
 | 
			
		||||
  device_path = g_udev_device_get_device_file (device);
 | 
			
		||||
 | 
			
		||||
  kms_device = meta_kms_create_device (native->kms, device_path, flags,
 | 
			
		||||
                                       error);
 | 
			
		||||
  if (!kms_device)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  return meta_gpu_kms_new (native, kms_device, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_udev_device_added (MetaUdev          *udev,
 | 
			
		||||
                      GUdevDevice       *device,
 | 
			
		||||
                      MetaBackendNative *native)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend *backend = META_BACKEND (native);
 | 
			
		||||
  g_autoptr (GError) error = NULL;
 | 
			
		||||
  const char *device_path;
 | 
			
		||||
  MetaGpuKms *new_gpu_kms;
 | 
			
		||||
  GList *gpus, *l;
 | 
			
		||||
 | 
			
		||||
  if (!meta_udev_is_drm_device (udev, device))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  device_path = g_udev_device_get_device_file (device);
 | 
			
		||||
 | 
			
		||||
  gpus = meta_backend_get_gpus (backend);;
 | 
			
		||||
  for (l = gpus; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpuKms *gpu_kms = l->data;
 | 
			
		||||
 | 
			
		||||
      if (!g_strcmp0 (device_path, meta_gpu_kms_get_file_path (gpu_kms)))
 | 
			
		||||
        {
 | 
			
		||||
          g_warning ("Failed to hotplug secondary gpu '%s': %s",
 | 
			
		||||
                     device_path, "device already present");
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  new_gpu_kms = create_gpu_from_udev_device (native, device, &error);
 | 
			
		||||
  if (!new_gpu_kms)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to hotplug secondary gpu '%s': %s",
 | 
			
		||||
                 device_path, error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_backend_add_gpu (backend, META_GPU (new_gpu_kms));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
connect_udev_device_added_handler (MetaBackendNative *native)
 | 
			
		||||
{
 | 
			
		||||
  native->udev_device_added_handler_id =
 | 
			
		||||
    g_signal_connect (native->udev, "device-added",
 | 
			
		||||
                      G_CALLBACK (on_udev_device_added), native);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
disconnect_udev_device_added_handler (MetaBackendNative *native)
 | 
			
		||||
{
 | 
			
		||||
  g_signal_handler_disconnect (native->udev,
 | 
			
		||||
                               native->udev_device_added_handler_id);
 | 
			
		||||
  native->udev_device_added_handler_id = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
init_gpus (MetaBackendNative  *native,
 | 
			
		||||
           GError            **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend *backend = META_BACKEND (native);
 | 
			
		||||
  MetaUdev *udev = meta_backend_native_get_udev (native);
 | 
			
		||||
  GList *devices;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  devices = meta_udev_list_drm_devices (udev, error);
 | 
			
		||||
  if (!devices)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  for (l = devices; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      GUdevDevice *device = l->data;
 | 
			
		||||
      MetaGpuKms *gpu_kms;
 | 
			
		||||
      GError *local_error = NULL;
 | 
			
		||||
 | 
			
		||||
      gpu_kms = create_gpu_from_udev_device (native, device, &local_error);
 | 
			
		||||
 | 
			
		||||
      if (!gpu_kms)
 | 
			
		||||
        {
 | 
			
		||||
          g_warning ("Failed to open gpu '%s': %s",
 | 
			
		||||
                     g_udev_device_get_device_file (device),
 | 
			
		||||
                     local_error->message);
 | 
			
		||||
          g_clear_error (&local_error);
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_backend_add_gpu (backend, META_GPU (gpu_kms));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_list_free_full (devices, g_object_unref);
 | 
			
		||||
 | 
			
		||||
  if (g_list_length (meta_backend_get_gpus (backend)) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                   "No GPUs found");
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  connect_udev_device_added_handler (native);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_backend_native_initable_init (GInitable     *initable,
 | 
			
		||||
                                   GCancellable  *cancellable,
 | 
			
		||||
                                   GError       **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendNative *native = META_BACKEND_NATIVE (initable);
 | 
			
		||||
 | 
			
		||||
  if (!meta_is_stage_views_enabled ())
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
 | 
			
		||||
@@ -531,6 +665,20 @@ meta_backend_native_initable_init (GInitable     *initable,
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  native->launcher = meta_launcher_new (error);
 | 
			
		||||
  if (!native->launcher)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  native->udev = meta_udev_new (native);
 | 
			
		||||
  native->barrier_manager = meta_barrier_manager_native_new ();
 | 
			
		||||
 | 
			
		||||
  native->kms = meta_kms_new (META_BACKEND (native), error);
 | 
			
		||||
  if (!native->kms)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (!init_gpus (native, error))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  return initable_parent_iface->init (initable, cancellable, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -575,26 +723,24 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_native_init (MetaBackendNative *native)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  priv->launcher = meta_launcher_new (&error);
 | 
			
		||||
  if (priv->launcher == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Can't initialize KMS backend: %s\n", error->message);
 | 
			
		||||
      exit (1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  priv->barrier_manager = meta_barrier_manager_native_new ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaLauncher *
 | 
			
		||||
meta_backend_native_get_launcher (MetaBackendNative *native)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendNativePrivate *priv =
 | 
			
		||||
    meta_backend_native_get_instance_private (native);
 | 
			
		||||
  return native->launcher;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  return priv->launcher;
 | 
			
		||||
MetaUdev *
 | 
			
		||||
meta_backend_native_get_udev (MetaBackendNative *native)
 | 
			
		||||
{
 | 
			
		||||
  return native->udev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKms *
 | 
			
		||||
meta_backend_native_get_kms (MetaBackendNative *native)
 | 
			
		||||
{
 | 
			
		||||
  return native->kms;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
@@ -610,10 +756,7 @@ meta_activate_vt (int vt, GError **error)
 | 
			
		||||
MetaBarrierManagerNative *
 | 
			
		||||
meta_backend_native_get_barrier_manager (MetaBackendNative *native)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendNativePrivate *priv =
 | 
			
		||||
    meta_backend_native_get_instance_private (native);
 | 
			
		||||
 | 
			
		||||
  return priv->barrier_manager;
 | 
			
		||||
  return native->barrier_manager;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -634,9 +777,8 @@ meta_activate_session (void)
 | 
			
		||||
    return TRUE;
 | 
			
		||||
 | 
			
		||||
  MetaBackendNative *native = META_BACKEND_NATIVE (backend);
 | 
			
		||||
  MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
 | 
			
		||||
 | 
			
		||||
  if (!meta_launcher_activate_session (priv->launcher, &error))
 | 
			
		||||
  if (!meta_launcher_activate_session (native->launcher, &error))
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Could not activate session: %s\n", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
@@ -659,6 +801,8 @@ meta_backend_native_pause (MetaBackendNative *native)
 | 
			
		||||
  clutter_evdev_release_devices ();
 | 
			
		||||
  clutter_stage_freeze_updates (stage);
 | 
			
		||||
 | 
			
		||||
  disconnect_udev_device_added_handler (native);
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_kms_pause (monitor_manager_kms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -674,6 +818,8 @@ void meta_backend_native_resume (MetaBackendNative *native)
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_kms_resume (monitor_manager_kms);
 | 
			
		||||
 | 
			
		||||
  connect_udev_device_added_handler (native);
 | 
			
		||||
 | 
			
		||||
  clutter_evdev_reclaim_devices ();
 | 
			
		||||
  clutter_stage_thaw_updates (stage);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,9 @@
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "backends/native/meta-clutter-backend-native.h"
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
#include "backends/native/meta-launcher.h"
 | 
			
		||||
#include "backends/native/meta-udev.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_BACKEND_NATIVE (meta_backend_native_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaBackendNative, meta_backend_native,
 | 
			
		||||
@@ -41,4 +43,8 @@ void meta_backend_native_resume (MetaBackendNative *backend_native);
 | 
			
		||||
 | 
			
		||||
MetaLauncher * meta_backend_native_get_launcher (MetaBackendNative *native);
 | 
			
		||||
 | 
			
		||||
MetaUdev * meta_backend_native_get_udev (MetaBackendNative *native);
 | 
			
		||||
 | 
			
		||||
MetaKms * meta_backend_native_get_kms (MetaBackendNative *native);
 | 
			
		||||
 | 
			
		||||
#endif /* META_BACKEND_NATIVE_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -24,68 +24,24 @@
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-crtc-kms.h"
 | 
			
		||||
 | 
			
		||||
#include <drm_fourcc.h>
 | 
			
		||||
#include <drm_mode.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "backends/meta-logical-monitor.h"
 | 
			
		||||
#include "backends/native/meta-gpu-kms.h"
 | 
			
		||||
#include "backends/native/meta-output-kms.h"
 | 
			
		||||
#include "backends/native/meta-kms-device.h"
 | 
			
		||||
#include "backends/native/meta-kms-plane.h"
 | 
			
		||||
#include "backends/native/meta-kms-update.h"
 | 
			
		||||
 | 
			
		||||
/* added in libdrm 2.4.95 */
 | 
			
		||||
#ifndef DRM_FORMAT_INVALID
 | 
			
		||||
#define DRM_FORMAT_INVALID 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define ALL_TRANSFORMS (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)
 | 
			
		||||
#define ALL_TRANSFORMS_MASK ((1 << ALL_TRANSFORMS) - 1)
 | 
			
		||||
#define ALL_TRANSFORMS_MASK ((1 << META_MONITOR_N_TRANSFORMS) - 1)
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaCrtcKms
 | 
			
		||||
{
 | 
			
		||||
  unsigned int index;
 | 
			
		||||
  uint32_t primary_plane_id;
 | 
			
		||||
  uint32_t rotation_prop_id;
 | 
			
		||||
  uint32_t rotation_map[ALL_TRANSFORMS];
 | 
			
		||||
  uint32_t all_hw_transforms;
 | 
			
		||||
  MetaKmsCrtc *kms_crtc;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * primary plane's supported formats and maybe modifiers
 | 
			
		||||
   * key: GUINT_TO_POINTER (format)
 | 
			
		||||
   * value: owned GArray* (uint64_t modifier), or NULL
 | 
			
		||||
   */
 | 
			
		||||
  GHashTable *formats_modifiers;
 | 
			
		||||
  MetaKmsPlane *primary_plane;
 | 
			
		||||
} MetaCrtcKms;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_drm_format_to_string:
 | 
			
		||||
 * @tmp: temporary buffer
 | 
			
		||||
 * @drm_format: DRM fourcc pixel format
 | 
			
		||||
 *
 | 
			
		||||
 * Returns a pointer to a string naming the given pixel format,
 | 
			
		||||
 * usually a pointer to the temporary buffer but not always.
 | 
			
		||||
 * Invalid formats may return nonsense names.
 | 
			
		||||
 *
 | 
			
		||||
 * When calling this, allocate one MetaDrmFormatBuf on the stack to
 | 
			
		||||
 * be used as the temporary buffer.
 | 
			
		||||
 */
 | 
			
		||||
const char *
 | 
			
		||||
meta_drm_format_to_string (MetaDrmFormatBuf *tmp,
 | 
			
		||||
                           uint32_t          drm_format)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  if (drm_format == DRM_FORMAT_INVALID)
 | 
			
		||||
    return "INVALID";
 | 
			
		||||
 | 
			
		||||
  G_STATIC_ASSERT (sizeof (tmp->s) == 5);
 | 
			
		||||
  for (i = 0; i < 4; i++)
 | 
			
		||||
    {
 | 
			
		||||
      char c = (drm_format >> (i * 8)) & 0xff;
 | 
			
		||||
      tmp->s[i] = g_ascii_isgraph (c) ? c : '.';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  tmp->s[i] = 0;
 | 
			
		||||
 | 
			
		||||
  return tmp->s;
 | 
			
		||||
}
 | 
			
		||||
static GQuark kms_crtc_crtc_kms_quark;
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_crtc_kms_is_transform_handled (MetaCrtc             *crtc,
 | 
			
		||||
@@ -93,77 +49,147 @@ meta_crtc_kms_is_transform_handled (MetaCrtc             *crtc,
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
 | 
			
		||||
  if ((1 << transform) & crtc_kms->all_hw_transforms)
 | 
			
		||||
    return TRUE;
 | 
			
		||||
  else
 | 
			
		||||
  if (!crtc_kms->primary_plane)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  return meta_kms_plane_is_transform_handled (crtc_kms->primary_plane,
 | 
			
		||||
                                              transform);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_crtc_kms_apply_transform (MetaCrtc *crtc)
 | 
			
		||||
meta_crtc_kms_apply_transform (MetaCrtc               *crtc,
 | 
			
		||||
                               MetaKmsPlaneAssignment *kms_plane_assignment)
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
  MetaGpu *gpu = meta_crtc_get_gpu (crtc);
 | 
			
		||||
  MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
 | 
			
		||||
  int kms_fd;
 | 
			
		||||
  MetaMonitorTransform hw_transform;
 | 
			
		||||
 | 
			
		||||
  kms_fd = meta_gpu_kms_get_fd (gpu_kms);
 | 
			
		||||
 | 
			
		||||
  if (crtc_kms->all_hw_transforms & (1 << crtc->transform))
 | 
			
		||||
  hw_transform = crtc->transform;
 | 
			
		||||
  else
 | 
			
		||||
  if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform))
 | 
			
		||||
    hw_transform = META_MONITOR_TRANSFORM_NORMAL;
 | 
			
		||||
 | 
			
		||||
  if (!meta_crtc_kms_is_transform_handled (crtc, META_MONITOR_TRANSFORM_NORMAL))
 | 
			
		||||
  if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (drmModeObjectSetProperty (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);
 | 
			
		||||
  meta_kms_plane_update_set_rotation (crtc_kms->primary_plane,
 | 
			
		||||
                                      kms_plane_assignment,
 | 
			
		||||
                                      hw_transform);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
      /*
 | 
			
		||||
       * Blacklist this HW transform, we want to fallback to our
 | 
			
		||||
       * fallbacks in this case.
 | 
			
		||||
       */
 | 
			
		||||
      crtc_kms->all_hw_transforms &= ~(1 << hw_transform);
 | 
			
		||||
void
 | 
			
		||||
meta_crtc_kms_assign_primary_plane (MetaCrtc      *crtc,
 | 
			
		||||
                                    uint32_t       fb_id,
 | 
			
		||||
                                    MetaKmsUpdate *kms_update)
 | 
			
		||||
{
 | 
			
		||||
  MetaRectangle logical_monitor_rect;
 | 
			
		||||
  int x, y;
 | 
			
		||||
  MetaFixed16Rectangle src_rect;
 | 
			
		||||
  MetaFixed16Rectangle dst_rect;
 | 
			
		||||
  MetaKmsCrtc *kms_crtc;
 | 
			
		||||
  MetaKmsDevice *kms_device;
 | 
			
		||||
  MetaKmsPlane *primary_kms_plane;
 | 
			
		||||
  MetaKmsPlaneAssignment *plane_assignment;
 | 
			
		||||
 | 
			
		||||
  logical_monitor_rect =
 | 
			
		||||
    meta_logical_monitor_get_layout (crtc->logical_monitor);
 | 
			
		||||
  x = crtc->rect.x - logical_monitor_rect.x;
 | 
			
		||||
  y = crtc->rect.y - logical_monitor_rect.y;
 | 
			
		||||
  src_rect = (MetaFixed16Rectangle) {
 | 
			
		||||
    .x = meta_fixed_16_from_int (x),
 | 
			
		||||
    .y = meta_fixed_16_from_int (y),
 | 
			
		||||
    .width = meta_fixed_16_from_int (crtc->rect.width),
 | 
			
		||||
    .height = meta_fixed_16_from_int (crtc->rect.height),
 | 
			
		||||
  };
 | 
			
		||||
  dst_rect = (MetaFixed16Rectangle) {
 | 
			
		||||
    .x = meta_fixed_16_from_int (0),
 | 
			
		||||
    .y = meta_fixed_16_from_int (0),
 | 
			
		||||
    .width = meta_fixed_16_from_int (crtc->rect.width),
 | 
			
		||||
    .height = meta_fixed_16_from_int (crtc->rect.height),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  kms_crtc = meta_crtc_kms_get_kms_crtc (crtc);
 | 
			
		||||
  kms_device = meta_kms_crtc_get_device (kms_crtc);
 | 
			
		||||
  primary_kms_plane = meta_kms_device_get_primary_plane_for (kms_device,
 | 
			
		||||
                                                             kms_crtc);
 | 
			
		||||
  plane_assignment = meta_kms_update_assign_plane (kms_update,
 | 
			
		||||
                                                   kms_crtc,
 | 
			
		||||
                                                   primary_kms_plane,
 | 
			
		||||
                                                   fb_id,
 | 
			
		||||
                                                   src_rect,
 | 
			
		||||
                                                   dst_rect);
 | 
			
		||||
  meta_crtc_kms_apply_transform (crtc, plane_assignment);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GList *
 | 
			
		||||
generate_crtc_connector_list (MetaGpu  *gpu,
 | 
			
		||||
                              MetaCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
  GList *connectors = NULL;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *output = l->data;
 | 
			
		||||
      MetaCrtc *assigned_crtc;
 | 
			
		||||
 | 
			
		||||
      assigned_crtc = meta_output_get_assigned_crtc (output);
 | 
			
		||||
      if (assigned_crtc == crtc)
 | 
			
		||||
        {
 | 
			
		||||
          MetaKmsConnector *kms_connector =
 | 
			
		||||
            meta_output_kms_get_kms_connector (output);
 | 
			
		||||
 | 
			
		||||
          connectors = g_list_prepend (connectors, kms_connector);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
find_property_index (MetaGpu                    *gpu,
 | 
			
		||||
                     drmModeObjectPropertiesPtr  props,
 | 
			
		||||
                     const char                 *prop_name,
 | 
			
		||||
                     drmModePropertyPtr         *out_prop)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
 | 
			
		||||
  int kms_fd;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  kms_fd = meta_gpu_kms_get_fd (gpu_kms);
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < props->count_props; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModePropertyPtr prop;
 | 
			
		||||
 | 
			
		||||
      prop = drmModeGetProperty (kms_fd, props->props[i]);
 | 
			
		||||
      if (!prop)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if (strcmp (prop->name, prop_name) == 0)
 | 
			
		||||
        {
 | 
			
		||||
          *out_prop = prop;
 | 
			
		||||
          return i;
 | 
			
		||||
  return connectors;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
      drmModeFreeProperty (prop);
 | 
			
		||||
void
 | 
			
		||||
meta_crtc_kms_set_mode (MetaCrtc      *crtc,
 | 
			
		||||
                        MetaKmsUpdate *kms_update)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = meta_crtc_get_gpu (crtc);
 | 
			
		||||
  GList *connectors;
 | 
			
		||||
  drmModeModeInfo *mode;
 | 
			
		||||
 | 
			
		||||
  connectors = generate_crtc_connector_list (gpu, crtc);
 | 
			
		||||
 | 
			
		||||
  if (connectors)
 | 
			
		||||
    {
 | 
			
		||||
      mode = crtc->current_mode->driver_private;
 | 
			
		||||
 | 
			
		||||
      g_debug ("Setting CRTC (%ld) mode to %s", crtc->crtc_id, mode->name);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      mode = NULL;
 | 
			
		||||
 | 
			
		||||
      g_debug ("Unsetting CRTC (%ld) mode", crtc->crtc_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return -1;
 | 
			
		||||
  meta_kms_update_mode_set (kms_update,
 | 
			
		||||
                            meta_crtc_kms_get_kms_crtc (crtc),
 | 
			
		||||
                            g_steal_pointer (&connectors),
 | 
			
		||||
                            mode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_crtc_kms_page_flip (MetaCrtc                      *crtc,
 | 
			
		||||
                         const MetaKmsPageFlipFeedback *page_flip_feedback,
 | 
			
		||||
                         gpointer                       user_data,
 | 
			
		||||
                         MetaKmsUpdate                 *kms_update)
 | 
			
		||||
{
 | 
			
		||||
  meta_kms_update_page_flip (kms_update,
 | 
			
		||||
                             meta_crtc_kms_get_kms_crtc (crtc),
 | 
			
		||||
                             page_flip_feedback,
 | 
			
		||||
                             user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsCrtc *
 | 
			
		||||
meta_crtc_kms_get_kms_crtc (MetaCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
 | 
			
		||||
  return crtc_kms->kms_crtc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -186,8 +212,8 @@ meta_crtc_kms_get_modifiers (MetaCrtc *crtc,
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
 | 
			
		||||
  return g_hash_table_lookup (crtc_kms->formats_modifiers,
 | 
			
		||||
                              GUINT_TO_POINTER (format));
 | 
			
		||||
  return meta_kms_plane_get_modifiers_for_format (crtc_kms->primary_plane,
 | 
			
		||||
                                                  format);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -202,24 +228,8 @@ GArray *
 | 
			
		||||
meta_crtc_kms_copy_drm_format_list (MetaCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
  GArray *formats;
 | 
			
		||||
  GHashTableIter it;
 | 
			
		||||
  gpointer key;
 | 
			
		||||
  unsigned int n_formats_modifiers;
 | 
			
		||||
 | 
			
		||||
  n_formats_modifiers = g_hash_table_size (crtc_kms->formats_modifiers);
 | 
			
		||||
  formats = g_array_sized_new (FALSE,
 | 
			
		||||
                               FALSE,
 | 
			
		||||
                               sizeof (uint32_t),
 | 
			
		||||
                               n_formats_modifiers);
 | 
			
		||||
  g_hash_table_iter_init (&it, crtc_kms->formats_modifiers);
 | 
			
		||||
  while (g_hash_table_iter_next (&it, &key, NULL))
 | 
			
		||||
    {
 | 
			
		||||
      uint32_t drm_format = GPOINTER_TO_UINT (key);
 | 
			
		||||
      g_array_append_val (formats, drm_format);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return formats;
 | 
			
		||||
  return meta_kms_plane_copy_drm_format_list (crtc_kms->primary_plane);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -235,284 +245,47 @@ meta_crtc_kms_supports_format (MetaCrtc *crtc,
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
 | 
			
		||||
  return g_hash_table_lookup_extended (crtc_kms->formats_modifiers,
 | 
			
		||||
                                       GUINT_TO_POINTER (drm_format),
 | 
			
		||||
                                       NULL,
 | 
			
		||||
                                       NULL);
 | 
			
		||||
  return meta_kms_plane_is_format_supported (crtc_kms->primary_plane,
 | 
			
		||||
                                             drm_format);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint32_t *
 | 
			
		||||
formats_ptr (struct drm_format_modifier_blob *blob)
 | 
			
		||||
MetaCrtc *
 | 
			
		||||
meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc)
 | 
			
		||||
{
 | 
			
		||||
  return (uint32_t *) (((char *) blob) + blob->formats_offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct drm_format_modifier *
 | 
			
		||||
modifiers_ptr (struct drm_format_modifier_blob *blob)
 | 
			
		||||
{
 | 
			
		||||
  return (struct drm_format_modifier *) (((char *) blob) +
 | 
			
		||||
                                         blob->modifiers_offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
free_modifier_array (GArray *array)
 | 
			
		||||
{
 | 
			
		||||
  if (!array)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_array_free (array, TRUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * In case the DRM driver does not expose a format list for the
 | 
			
		||||
 * primary plane (does not support universal planes nor
 | 
			
		||||
 * IN_FORMATS property), hardcode something that is probably supported.
 | 
			
		||||
 */
 | 
			
		||||
static const uint32_t drm_default_formats[] =
 | 
			
		||||
  {
 | 
			
		||||
    DRM_FORMAT_XRGB8888 /* The format everything should always support by convention */,
 | 
			
		||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
 | 
			
		||||
    DRM_FORMAT_XBGR8888 /* OpenGL GL_RGBA, GL_UNSIGNED_BYTE format, hopefully supported */
 | 
			
		||||
#endif
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_formats_from_array (MetaCrtc       *crtc,
 | 
			
		||||
                        const uint32_t *formats,
 | 
			
		||||
                        size_t          n_formats)
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
  size_t i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_formats; i++)
 | 
			
		||||
    {
 | 
			
		||||
      g_hash_table_insert (crtc_kms->formats_modifiers,
 | 
			
		||||
                           GUINT_TO_POINTER (formats[i]), NULL);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
parse_formats (MetaCrtc *crtc,
 | 
			
		||||
               int       kms_fd,
 | 
			
		||||
               uint32_t  blob_id)
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
  drmModePropertyBlobPtr blob;
 | 
			
		||||
  struct drm_format_modifier_blob *blob_fmt;
 | 
			
		||||
  uint32_t *formats;
 | 
			
		||||
  struct drm_format_modifier *modifiers;
 | 
			
		||||
  unsigned int fmt_i, mod_i;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (g_hash_table_size (crtc_kms->formats_modifiers) == 0);
 | 
			
		||||
 | 
			
		||||
  if (blob_id == 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  blob = drmModeGetPropertyBlob (kms_fd, blob_id);
 | 
			
		||||
  if (!blob)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (blob->length < sizeof (struct drm_format_modifier_blob))
 | 
			
		||||
    {
 | 
			
		||||
      drmModeFreePropertyBlob (blob);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  blob_fmt = blob->data;
 | 
			
		||||
 | 
			
		||||
  formats = formats_ptr (blob_fmt);
 | 
			
		||||
  modifiers = modifiers_ptr (blob_fmt);
 | 
			
		||||
 | 
			
		||||
  for (fmt_i = 0; fmt_i < blob_fmt->count_formats; fmt_i++)
 | 
			
		||||
    {
 | 
			
		||||
      GArray *mod_tmp = g_array_new (FALSE, FALSE, sizeof (uint64_t));
 | 
			
		||||
 | 
			
		||||
      for (mod_i = 0; mod_i < blob_fmt->count_modifiers; mod_i++)
 | 
			
		||||
        {
 | 
			
		||||
          struct drm_format_modifier *modifier = &modifiers[mod_i];
 | 
			
		||||
 | 
			
		||||
          /* The modifier advertisement blob is partitioned into groups of
 | 
			
		||||
           * 64 formats. */
 | 
			
		||||
          if (fmt_i < modifier->offset || fmt_i > modifier->offset + 63)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
          if (!(modifier->formats & (1 << (fmt_i - modifier->offset))))
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
          g_array_append_val (mod_tmp, modifier->modifier);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (mod_tmp->len == 0)
 | 
			
		||||
        {
 | 
			
		||||
          free_modifier_array (mod_tmp);
 | 
			
		||||
          mod_tmp = NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      g_hash_table_insert (crtc_kms->formats_modifiers,
 | 
			
		||||
                           GUINT_TO_POINTER (formats[fmt_i]), mod_tmp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  drmModeFreePropertyBlob (blob);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
parse_transforms (MetaCrtc          *crtc,
 | 
			
		||||
                  drmModePropertyPtr prop)
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < prop->count_enums; i++)
 | 
			
		||||
    {
 | 
			
		||||
      int transform = -1;
 | 
			
		||||
 | 
			
		||||
      if (strcmp (prop->enums[i].name, "rotate-0") == 0)
 | 
			
		||||
        transform = META_MONITOR_TRANSFORM_NORMAL;
 | 
			
		||||
      else if (strcmp (prop->enums[i].name, "rotate-90") == 0)
 | 
			
		||||
        transform = META_MONITOR_TRANSFORM_90;
 | 
			
		||||
      else if (strcmp (prop->enums[i].name, "rotate-180") == 0)
 | 
			
		||||
        transform = META_MONITOR_TRANSFORM_180;
 | 
			
		||||
      else if (strcmp (prop->enums[i].name, "rotate-270") == 0)
 | 
			
		||||
        transform = META_MONITOR_TRANSFORM_270;
 | 
			
		||||
 | 
			
		||||
      if (transform != -1)
 | 
			
		||||
        {
 | 
			
		||||
          crtc_kms->all_hw_transforms |= 1 << transform;
 | 
			
		||||
          crtc_kms->rotation_map[transform] = 1 << prop->enums[i].value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
is_primary_plane (MetaGpu                   *gpu,
 | 
			
		||||
                  drmModeObjectPropertiesPtr props)
 | 
			
		||||
{
 | 
			
		||||
  drmModePropertyPtr prop;
 | 
			
		||||
  int idx;
 | 
			
		||||
 | 
			
		||||
  idx = find_property_index (gpu, props, "type", &prop);
 | 
			
		||||
  if (idx < 0)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  drmModeFreeProperty (prop);
 | 
			
		||||
  return props->prop_values[idx] == DRM_PLANE_TYPE_PRIMARY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_crtc_rotations (MetaCrtc *crtc,
 | 
			
		||||
                     MetaGpu  *gpu)
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
  MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
 | 
			
		||||
  int kms_fd;
 | 
			
		||||
  drmModeObjectPropertiesPtr props;
 | 
			
		||||
  drmModePlaneRes *planes;
 | 
			
		||||
  drmModePlane *drm_plane;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  kms_fd = meta_gpu_kms_get_fd (gpu_kms);
 | 
			
		||||
 | 
			
		||||
  planes = drmModeGetPlaneResources (kms_fd);
 | 
			
		||||
  if (planes == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < planes->count_planes; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModePropertyPtr prop;
 | 
			
		||||
 | 
			
		||||
      drm_plane = drmModeGetPlane (kms_fd, planes->planes[i]);
 | 
			
		||||
 | 
			
		||||
      if (!drm_plane)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if ((drm_plane->possible_crtcs & (1 << crtc_kms->index)))
 | 
			
		||||
        {
 | 
			
		||||
          props = drmModeObjectGetProperties (kms_fd,
 | 
			
		||||
                                              drm_plane->plane_id,
 | 
			
		||||
                                              DRM_MODE_OBJECT_PLANE);
 | 
			
		||||
 | 
			
		||||
          if (props && is_primary_plane (gpu, props))
 | 
			
		||||
            {
 | 
			
		||||
              int rotation_idx, fmts_idx;
 | 
			
		||||
 | 
			
		||||
              crtc_kms->primary_plane_id = drm_plane->plane_id;
 | 
			
		||||
              rotation_idx = find_property_index (gpu, props,
 | 
			
		||||
                                                  "rotation", &prop);
 | 
			
		||||
              if (rotation_idx >= 0)
 | 
			
		||||
                {
 | 
			
		||||
                  crtc_kms->rotation_prop_id = props->props[rotation_idx];
 | 
			
		||||
                  parse_transforms (crtc, prop);
 | 
			
		||||
                  drmModeFreeProperty (prop);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
              fmts_idx = find_property_index (gpu, props,
 | 
			
		||||
                                              "IN_FORMATS", &prop);
 | 
			
		||||
              if (fmts_idx >= 0)
 | 
			
		||||
                {
 | 
			
		||||
                  parse_formats (crtc, kms_fd, props->prop_values[fmts_idx]);
 | 
			
		||||
                  drmModeFreeProperty (prop);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
              /* fall back to universal plane formats without modifiers */
 | 
			
		||||
              if (g_hash_table_size (crtc_kms->formats_modifiers) == 0)
 | 
			
		||||
                {
 | 
			
		||||
                  set_formats_from_array (crtc,
 | 
			
		||||
                                          drm_plane->formats,
 | 
			
		||||
                                          drm_plane->count_formats);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          if (props)
 | 
			
		||||
            drmModeFreeObjectProperties (props);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      drmModeFreePlane (drm_plane);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  crtc->all_transforms |= crtc_kms->all_hw_transforms;
 | 
			
		||||
 | 
			
		||||
  drmModeFreePlaneResources (planes);
 | 
			
		||||
 | 
			
		||||
  /* final formats fallback to something hardcoded */
 | 
			
		||||
  if (g_hash_table_size (crtc_kms->formats_modifiers) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      set_formats_from_array (crtc,
 | 
			
		||||
                              drm_default_formats,
 | 
			
		||||
                              G_N_ELEMENTS (drm_default_formats));
 | 
			
		||||
    }
 | 
			
		||||
  return g_object_get_qdata (G_OBJECT (kms_crtc), kms_crtc_crtc_kms_quark);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_crtc_destroy_notify (MetaCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
  MetaCrtcKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
 | 
			
		||||
  g_hash_table_destroy (crtc_kms->formats_modifiers);
 | 
			
		||||
  g_free (crtc->driver_private);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaCrtc *
 | 
			
		||||
meta_create_kms_crtc (MetaGpuKms  *gpu_kms,
 | 
			
		||||
                      drmModeCrtc  *drm_crtc,
 | 
			
		||||
                      unsigned int  crtc_index)
 | 
			
		||||
                      MetaKmsCrtc *kms_crtc)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = META_GPU (gpu_kms);
 | 
			
		||||
  MetaKmsDevice *kms_device;
 | 
			
		||||
  MetaCrtc *crtc;
 | 
			
		||||
  MetaCrtcKms *crtc_kms;
 | 
			
		||||
  MetaKmsPlane *primary_plane;
 | 
			
		||||
  const MetaKmsCrtcState *crtc_state;
 | 
			
		||||
 | 
			
		||||
  kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
 | 
			
		||||
  primary_plane = meta_kms_device_get_primary_plane_for (kms_device,
 | 
			
		||||
                                                         kms_crtc);
 | 
			
		||||
  crtc_state = meta_kms_crtc_get_current_state (kms_crtc);
 | 
			
		||||
 | 
			
		||||
  crtc = g_object_new (META_TYPE_CRTC, NULL);
 | 
			
		||||
 | 
			
		||||
  crtc->gpu = gpu;
 | 
			
		||||
  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->crtc_id = meta_kms_crtc_get_id (kms_crtc);
 | 
			
		||||
  crtc->rect = crtc_state->rect;
 | 
			
		||||
  crtc->is_dirty = FALSE;
 | 
			
		||||
  crtc->transform = META_MONITOR_TRANSFORM_NORMAL;
 | 
			
		||||
  crtc->all_transforms = ALL_TRANSFORMS_MASK;
 | 
			
		||||
 | 
			
		||||
  if (drm_crtc->mode_valid)
 | 
			
		||||
  if (crtc_state->is_drm_mode_valid)
 | 
			
		||||
    {
 | 
			
		||||
      GList *l;
 | 
			
		||||
 | 
			
		||||
@@ -520,7 +293,7 @@ meta_create_kms_crtc (MetaGpuKms   *gpu_kms,
 | 
			
		||||
        {
 | 
			
		||||
          MetaCrtcMode *mode = l->data;
 | 
			
		||||
 | 
			
		||||
          if (meta_drm_mode_equal (&drm_crtc->mode, mode->driver_private))
 | 
			
		||||
          if (meta_drm_mode_equal (&crtc_state->drm_mode, mode->driver_private))
 | 
			
		||||
            {
 | 
			
		||||
              crtc->current_mode = mode;
 | 
			
		||||
              break;
 | 
			
		||||
@@ -529,18 +302,19 @@ meta_create_kms_crtc (MetaGpuKms   *gpu_kms,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  crtc_kms = g_new0 (MetaCrtcKms, 1);
 | 
			
		||||
  crtc_kms->index = crtc_index;
 | 
			
		||||
 | 
			
		||||
  crtc_kms->formats_modifiers =
 | 
			
		||||
    g_hash_table_new_full (g_direct_hash,
 | 
			
		||||
                           g_direct_equal,
 | 
			
		||||
                           NULL,
 | 
			
		||||
                           (GDestroyNotify) free_modifier_array);
 | 
			
		||||
  crtc_kms->kms_crtc = kms_crtc;
 | 
			
		||||
  crtc_kms->primary_plane = primary_plane;
 | 
			
		||||
 | 
			
		||||
  crtc->driver_private = crtc_kms;
 | 
			
		||||
  crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
 | 
			
		||||
 | 
			
		||||
  init_crtc_rotations (crtc, gpu);
 | 
			
		||||
  if (!kms_crtc_crtc_kms_quark)
 | 
			
		||||
    {
 | 
			
		||||
      kms_crtc_crtc_kms_quark =
 | 
			
		||||
        g_quark_from_static_string ("meta-kms-crtc-crtc-kms-quark");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_object_set_qdata (G_OBJECT (kms_crtc), kms_crtc_crtc_kms_quark, crtc);
 | 
			
		||||
 | 
			
		||||
  return crtc;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,20 +29,30 @@
 | 
			
		||||
#include "backends/meta-backend-types.h"
 | 
			
		||||
#include "backends/meta-crtc.h"
 | 
			
		||||
#include "backends/native/meta-gpu-kms.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaDrmFormatBuf
 | 
			
		||||
{
 | 
			
		||||
  char s[5];
 | 
			
		||||
} MetaDrmFormatBuf;
 | 
			
		||||
 | 
			
		||||
const char *
 | 
			
		||||
meta_drm_format_to_string (MetaDrmFormatBuf *tmp,
 | 
			
		||||
                           uint32_t          format);
 | 
			
		||||
#include "backends/native/meta-kms-crtc.h"
 | 
			
		||||
 | 
			
		||||
gboolean meta_crtc_kms_is_transform_handled (MetaCrtc             *crtc,
 | 
			
		||||
                                             MetaMonitorTransform  transform);
 | 
			
		||||
 | 
			
		||||
void meta_crtc_kms_apply_transform (MetaCrtc *crtc);
 | 
			
		||||
void meta_crtc_kms_apply_transform (MetaCrtc               *crtc,
 | 
			
		||||
                                    MetaKmsPlaneAssignment *kms_plane_assignment);
 | 
			
		||||
 | 
			
		||||
void meta_crtc_kms_assign_primary_plane (MetaCrtc      *crtc,
 | 
			
		||||
                                         uint32_t       fb_id,
 | 
			
		||||
                                         MetaKmsUpdate *kms_update);
 | 
			
		||||
 | 
			
		||||
void meta_crtc_kms_set_mode (MetaCrtc      *crtc,
 | 
			
		||||
                             MetaKmsUpdate *kms_update);
 | 
			
		||||
 | 
			
		||||
void meta_crtc_kms_page_flip (MetaCrtc                      *crtc,
 | 
			
		||||
                              const MetaKmsPageFlipFeedback *page_flip_feedback,
 | 
			
		||||
                              gpointer                       user_data,
 | 
			
		||||
                              MetaKmsUpdate                 *kms_update);
 | 
			
		||||
 | 
			
		||||
void meta_crtc_kms_set_is_underscanning (MetaCrtc *crtc,
 | 
			
		||||
                                         gboolean  is_underscanning);
 | 
			
		||||
 | 
			
		||||
MetaKmsCrtc * meta_crtc_kms_get_kms_crtc (MetaCrtc *crtc);
 | 
			
		||||
 | 
			
		||||
GArray * meta_crtc_kms_get_modifiers (MetaCrtc *crtc,
 | 
			
		||||
                                      uint32_t  format);
 | 
			
		||||
@@ -54,8 +64,9 @@ gboolean
 | 
			
		||||
meta_crtc_kms_supports_format (MetaCrtc *crtc,
 | 
			
		||||
                               uint32_t  drm_format);
 | 
			
		||||
 | 
			
		||||
MetaCrtc * meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc);
 | 
			
		||||
 | 
			
		||||
MetaCrtc * meta_create_kms_crtc (MetaGpuKms  *gpu_kms,
 | 
			
		||||
                                 drmModeCrtc  *drm_crtc,
 | 
			
		||||
                                 unsigned int  crtc_index);
 | 
			
		||||
                                 MetaKmsCrtc *kms_crtc);
 | 
			
		||||
 | 
			
		||||
#endif /* META_CRTC_KMS_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -77,7 +77,7 @@ struct _MetaCursorRendererNative
 | 
			
		||||
 | 
			
		||||
struct _MetaCursorRendererNativePrivate
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *monitor_manager;
 | 
			
		||||
  MetaBackend *backend;
 | 
			
		||||
 | 
			
		||||
  gboolean hw_state_invalidated;
 | 
			
		||||
  gboolean has_hw_cursor;
 | 
			
		||||
@@ -387,7 +387,9 @@ update_hw_cursor (MetaCursorRendererNative *native,
 | 
			
		||||
  MetaCursorRendererNativePrivate *priv =
 | 
			
		||||
    meta_cursor_renderer_native_get_instance_private (native);
 | 
			
		||||
  MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = priv->monitor_manager;
 | 
			
		||||
  MetaBackend *backend = priv->backend;
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  GList *logical_monitors;
 | 
			
		||||
  GList *l;
 | 
			
		||||
  ClutterRect rect;
 | 
			
		||||
@@ -480,7 +482,9 @@ cursor_over_transformed_logical_monitor (MetaCursorRenderer *renderer,
 | 
			
		||||
    META_CURSOR_RENDERER_NATIVE (renderer);
 | 
			
		||||
  MetaCursorRendererNativePrivate *priv =
 | 
			
		||||
    meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = priv->monitor_manager;
 | 
			
		||||
  MetaBackend *backend = priv->backend;
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  GList *logical_monitors;
 | 
			
		||||
  GList *l;
 | 
			
		||||
  ClutterRect cursor_rect;
 | 
			
		||||
@@ -538,7 +542,9 @@ can_draw_cursor_unscaled (MetaCursorRenderer *renderer,
 | 
			
		||||
    META_CURSOR_RENDERER_NATIVE (renderer);
 | 
			
		||||
  MetaCursorRendererNativePrivate *priv =
 | 
			
		||||
    meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = priv->monitor_manager;
 | 
			
		||||
  MetaBackend *backend = priv->backend;
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  ClutterRect cursor_rect;
 | 
			
		||||
  GList *logical_monitors;
 | 
			
		||||
  GList *l;
 | 
			
		||||
@@ -680,7 +686,9 @@ calculate_cursor_sprite_gpus (MetaCursorRenderer *renderer,
 | 
			
		||||
  MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
 | 
			
		||||
  MetaCursorRendererNativePrivate *priv =
 | 
			
		||||
    meta_cursor_renderer_native_get_instance_private (native);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = priv->monitor_manager;
 | 
			
		||||
  MetaBackend *backend = priv->backend;
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  GList *gpus = NULL;
 | 
			
		||||
  GList *logical_monitors;
 | 
			
		||||
  GList *l;
 | 
			
		||||
@@ -1175,7 +1183,7 @@ init_hw_cursor_support (MetaCursorRendererNative *cursor_renderer_native)
 | 
			
		||||
  GList *gpus;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
 | 
			
		||||
  gpus = meta_backend_get_gpus (priv->backend);
 | 
			
		||||
  for (l = gpus; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpuKms *gpu_kms = l->data;
 | 
			
		||||
@@ -1223,7 +1231,7 @@ meta_cursor_renderer_native_new (MetaBackend *backend)
 | 
			
		||||
                           G_CALLBACK (on_monitors_changed),
 | 
			
		||||
                           cursor_renderer_native, 0);
 | 
			
		||||
 | 
			
		||||
  priv->monitor_manager = monitor_manager;
 | 
			
		||||
  priv->backend = backend;
 | 
			
		||||
  priv->hw_state_invalidated = TRUE;
 | 
			
		||||
 | 
			
		||||
  init_hw_cursor_support (cursor_renderer_native);
 | 
			
		||||
 
 | 
			
		||||
@@ -37,174 +37,40 @@
 | 
			
		||||
#include "backends/meta-output.h"
 | 
			
		||||
#include "backends/native/meta-backend-native.h"
 | 
			
		||||
#include "backends/native/meta-crtc-kms.h"
 | 
			
		||||
#include "backends/native/meta-kms-connector.h"
 | 
			
		||||
#include "backends/native/meta-kms-device.h"
 | 
			
		||||
#include "backends/native/meta-kms-update.h"
 | 
			
		||||
#include "backends/native/meta-kms-utils.h"
 | 
			
		||||
#include "backends/native/meta-kms.h"
 | 
			
		||||
#include "backends/native/meta-launcher.h"
 | 
			
		||||
#include "backends/native/meta-output-kms.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-default-modes.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsSource
 | 
			
		||||
{
 | 
			
		||||
  GSource source;
 | 
			
		||||
 | 
			
		||||
  gpointer fd_tag;
 | 
			
		||||
  MetaGpuKms *gpu_kms;
 | 
			
		||||
} MetaKmsSource;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaGpuKmsFlipClosureContainer
 | 
			
		||||
{
 | 
			
		||||
  GClosure *flip_closure;
 | 
			
		||||
  MetaGpuKms *gpu_kms;
 | 
			
		||||
  MetaCrtc *crtc;
 | 
			
		||||
} MetaGpuKmsFlipClosureContainer;
 | 
			
		||||
 | 
			
		||||
struct _MetaGpuKms
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu parent;
 | 
			
		||||
 | 
			
		||||
  MetaKmsDevice *kms_device;
 | 
			
		||||
 | 
			
		||||
  uint32_t id;
 | 
			
		||||
  int fd;
 | 
			
		||||
  char *file_path;
 | 
			
		||||
  GSource *source;
 | 
			
		||||
 | 
			
		||||
  clockid_t clock_id;
 | 
			
		||||
 | 
			
		||||
  drmModeConnector **connectors;
 | 
			
		||||
  unsigned int n_connectors;
 | 
			
		||||
 | 
			
		||||
  int max_buffer_width;
 | 
			
		||||
  int max_buffer_height;
 | 
			
		||||
 | 
			
		||||
  gboolean resources_init_failed_before;
 | 
			
		||||
 | 
			
		||||
  MetaGpuKmsFlag flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaGpuKms, meta_gpu_kms, META_TYPE_GPU)
 | 
			
		||||
 | 
			
		||||
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_gpu_kms_wait_for_flip (kms_source->gpu_kms, NULL);
 | 
			
		||||
 | 
			
		||||
  return G_SOURCE_CONTINUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GSourceFuncs kms_event_funcs = {
 | 
			
		||||
  NULL,
 | 
			
		||||
  kms_event_check,
 | 
			
		||||
  kms_event_dispatch
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
get_crtc_drm_connectors (MetaGpu       *gpu,
 | 
			
		||||
                         MetaCrtc      *crtc,
 | 
			
		||||
                         uint32_t     **connectors,
 | 
			
		||||
                         unsigned int  *n_connectors)
 | 
			
		||||
{
 | 
			
		||||
  GArray *connectors_array = g_array_new (FALSE, FALSE, sizeof (uint32_t));
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *output = l->data;
 | 
			
		||||
      MetaCrtc *assigned_crtc;
 | 
			
		||||
 | 
			
		||||
      assigned_crtc = meta_output_get_assigned_crtc (output);
 | 
			
		||||
      if (assigned_crtc == crtc)
 | 
			
		||||
        {
 | 
			
		||||
          uint32_t connector_id;
 | 
			
		||||
 | 
			
		||||
          connector_id = meta_output_kms_get_connector_id (output);
 | 
			
		||||
          g_array_append_val (connectors_array, connector_id);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  *n_connectors = connectors_array->len;
 | 
			
		||||
  *connectors = (uint32_t *) g_array_free (connectors_array, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms,
 | 
			
		||||
                              MetaCrtc   *crtc,
 | 
			
		||||
                              int         x,
 | 
			
		||||
                              int         y,
 | 
			
		||||
                              uint32_t    fb_id)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = meta_crtc_get_gpu (crtc);
 | 
			
		||||
  int kms_fd = meta_gpu_kms_get_fd (gpu_kms);
 | 
			
		||||
  uint32_t *connectors;
 | 
			
		||||
  unsigned int n_connectors;
 | 
			
		||||
  drmModeModeInfo *mode;
 | 
			
		||||
 | 
			
		||||
  get_crtc_drm_connectors (gpu, crtc, &connectors, &n_connectors);
 | 
			
		||||
 | 
			
		||||
  if (connectors)
 | 
			
		||||
    mode = crtc->current_mode->driver_private;
 | 
			
		||||
  else
 | 
			
		||||
    mode = NULL;
 | 
			
		||||
 | 
			
		||||
  if (drmModeSetCrtc (kms_fd,
 | 
			
		||||
                      crtc->crtc_id,
 | 
			
		||||
                      fb_id,
 | 
			
		||||
                      x, y,
 | 
			
		||||
                      connectors, n_connectors,
 | 
			
		||||
                      mode) != 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (mode)
 | 
			
		||||
        g_warning ("Failed to set CRTC mode %s: %m", crtc->current_mode->name);
 | 
			
		||||
      else
 | 
			
		||||
        g_warning ("Failed to disable CRTC");
 | 
			
		||||
      g_free (connectors);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_free (connectors);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
invoke_flip_closure (GClosure   *flip_closure,
 | 
			
		||||
                     MetaGpuKms *gpu_kms,
 | 
			
		||||
                     MetaCrtc   *crtc,
 | 
			
		||||
                     int64_t     page_flip_time_ns)
 | 
			
		||||
{
 | 
			
		||||
  GValue params[] = {
 | 
			
		||||
    G_VALUE_INIT,
 | 
			
		||||
    G_VALUE_INIT,
 | 
			
		||||
    G_VALUE_INIT,
 | 
			
		||||
    G_VALUE_INIT,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  g_value_init (¶ms[0], G_TYPE_POINTER);
 | 
			
		||||
  g_value_set_pointer (¶ms[0], flip_closure);
 | 
			
		||||
  g_value_init (¶ms[1], G_TYPE_OBJECT);
 | 
			
		||||
  g_value_set_object (¶ms[1], gpu_kms);
 | 
			
		||||
  g_value_init (¶ms[2], G_TYPE_OBJECT);
 | 
			
		||||
  g_value_set_object (¶ms[2], crtc);
 | 
			
		||||
  g_value_init (¶ms[3], G_TYPE_INT64);
 | 
			
		||||
  g_value_set_int64 (¶ms[3], page_flip_time_ns);
 | 
			
		||||
  g_closure_invoke (flip_closure, NULL, 4, params, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
 | 
			
		||||
                             MetaCrtc   *crtc)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = META_GPU (gpu_kms);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
 | 
			
		||||
  MetaBackend *backend = meta_gpu_get_backend (gpu);
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  GList *l;
 | 
			
		||||
  gboolean connected_crtc_found;
 | 
			
		||||
 | 
			
		||||
@@ -233,76 +99,6 @@ meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaGpuKmsFlipClosureContainer *
 | 
			
		||||
meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms,
 | 
			
		||||
                                MetaCrtc   *crtc,
 | 
			
		||||
                                GClosure   *flip_closure)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpuKmsFlipClosureContainer *closure_container;
 | 
			
		||||
 | 
			
		||||
  closure_container = g_new0 (MetaGpuKmsFlipClosureContainer, 1);
 | 
			
		||||
  *closure_container = (MetaGpuKmsFlipClosureContainer) {
 | 
			
		||||
    .flip_closure = g_closure_ref (flip_closure),
 | 
			
		||||
    .gpu_kms = gpu_kms,
 | 
			
		||||
    .crtc = crtc
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return closure_container;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_gpu_kms_flip_closure_container_free (MetaGpuKmsFlipClosureContainer *closure_container)
 | 
			
		||||
{
 | 
			
		||||
  g_closure_unref (closure_container->flip_closure);
 | 
			
		||||
  g_free (closure_container);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_gpu_kms_flip_crtc (MetaGpuKms  *gpu_kms,
 | 
			
		||||
                        MetaCrtc    *crtc,
 | 
			
		||||
                        uint32_t     fb_id,
 | 
			
		||||
                        GClosure    *flip_closure,
 | 
			
		||||
                        GError     **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = META_GPU (gpu_kms);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
 | 
			
		||||
  MetaGpuKmsFlipClosureContainer *closure_container;
 | 
			
		||||
  int kms_fd = meta_gpu_kms_get_fd (gpu_kms);
 | 
			
		||||
  uint32_t *connectors;
 | 
			
		||||
  unsigned int n_connectors;
 | 
			
		||||
  int ret = -1;
 | 
			
		||||
 | 
			
		||||
  g_assert (meta_crtc_get_gpu (crtc) == gpu);
 | 
			
		||||
  g_assert (meta_monitor_manager_get_power_save_mode (monitor_manager) ==
 | 
			
		||||
            META_POWER_SAVE_ON);
 | 
			
		||||
 | 
			
		||||
  get_crtc_drm_connectors (gpu, crtc, &connectors, &n_connectors);
 | 
			
		||||
  g_assert (n_connectors > 0);
 | 
			
		||||
  g_free (connectors);
 | 
			
		||||
 | 
			
		||||
  g_assert (fb_id != 0);
 | 
			
		||||
 | 
			
		||||
  closure_container = meta_gpu_kms_wrap_flip_closure (gpu_kms,
 | 
			
		||||
                                                      crtc,
 | 
			
		||||
                                                      flip_closure);
 | 
			
		||||
 | 
			
		||||
  ret = drmModePageFlip (kms_fd,
 | 
			
		||||
                         crtc->crtc_id,
 | 
			
		||||
                         fb_id,
 | 
			
		||||
                         DRM_MODE_PAGE_FLIP_EVENT,
 | 
			
		||||
                         closure_container);
 | 
			
		||||
  if (ret != 0)
 | 
			
		||||
    {
 | 
			
		||||
      meta_gpu_kms_flip_closure_container_free (closure_container);
 | 
			
		||||
      g_set_error (error, G_IO_ERROR,
 | 
			
		||||
                   g_io_error_from_errno (-ret),
 | 
			
		||||
                   "drmModePageFlip failed: %s", g_strerror (-ret));
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t
 | 
			
		||||
timespec_to_nanoseconds (const struct timespec *ts)
 | 
			
		||||
{
 | 
			
		||||
@@ -311,82 +107,20 @@ timespec_to_nanoseconds (const struct timespec *ts)
 | 
			
		||||
  return ((int64_t) ts->tv_sec) * one_billion + ts->tv_nsec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t
 | 
			
		||||
timeval_to_nanoseconds (const struct timeval *tv)
 | 
			
		||||
{
 | 
			
		||||
  int64_t usec = ((int64_t) tv->tv_sec) * G_USEC_PER_SEC + tv->tv_usec;
 | 
			
		||||
  int64_t nsec = usec * 1000;
 | 
			
		||||
 | 
			
		||||
  return nsec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
page_flip_handler (int           fd,
 | 
			
		||||
                   unsigned int  frame,
 | 
			
		||||
                   unsigned int  sec,
 | 
			
		||||
                   unsigned int  usec,
 | 
			
		||||
                   void         *user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpuKmsFlipClosureContainer *closure_container = user_data;
 | 
			
		||||
  GClosure *flip_closure = closure_container->flip_closure;
 | 
			
		||||
  MetaGpuKms *gpu_kms = closure_container->gpu_kms;
 | 
			
		||||
  struct timeval page_flip_time = {sec, usec};
 | 
			
		||||
 | 
			
		||||
  invoke_flip_closure (flip_closure,
 | 
			
		||||
                       gpu_kms,
 | 
			
		||||
                       closure_container->crtc,
 | 
			
		||||
                       timeval_to_nanoseconds (&page_flip_time));
 | 
			
		||||
  meta_gpu_kms_flip_closure_container_free (closure_container);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms,
 | 
			
		||||
                            GError    **error)
 | 
			
		||||
{
 | 
			
		||||
  drmEventContext evctx;
 | 
			
		||||
 | 
			
		||||
  memset (&evctx, 0, sizeof evctx);
 | 
			
		||||
  evctx.version = 2;
 | 
			
		||||
  evctx.page_flip_handler = page_flip_handler;
 | 
			
		||||
 | 
			
		||||
  while (TRUE)
 | 
			
		||||
    {
 | 
			
		||||
      if (drmHandleEvent (gpu_kms->fd, &evctx) != 0)
 | 
			
		||||
        {
 | 
			
		||||
          struct pollfd pfd;
 | 
			
		||||
          int ret;
 | 
			
		||||
 | 
			
		||||
          if (errno != EAGAIN)
 | 
			
		||||
            {
 | 
			
		||||
              g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
 | 
			
		||||
                                   strerror (errno));
 | 
			
		||||
  if (meta_kms_device_dispatch_sync (gpu_kms->kms_device, error) < 0)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          pfd.fd = gpu_kms->fd;
 | 
			
		||||
          pfd.events = POLL_IN | POLL_ERR;
 | 
			
		||||
          do
 | 
			
		||||
            {
 | 
			
		||||
              ret = poll (&pfd, 1, -1);
 | 
			
		||||
            }
 | 
			
		||||
          while (ret == -1 && errno == EINTR);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_gpu_kms_get_max_buffer_size (MetaGpuKms *gpu_kms,
 | 
			
		||||
                                  int        *max_width,
 | 
			
		||||
                                  int        *max_height)
 | 
			
		||||
MetaKmsDevice *
 | 
			
		||||
meta_gpu_kms_get_kms_device (MetaGpuKms *gpu_kms)
 | 
			
		||||
{
 | 
			
		||||
  *max_width = gpu_kms->max_buffer_width;
 | 
			
		||||
  *max_height = gpu_kms->max_buffer_height;
 | 
			
		||||
  return gpu_kms->kms_device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
@@ -404,7 +138,7 @@ meta_gpu_kms_get_id (MetaGpuKms *gpu_kms)
 | 
			
		||||
const char *
 | 
			
		||||
meta_gpu_kms_get_file_path (MetaGpuKms *gpu_kms)
 | 
			
		||||
{
 | 
			
		||||
  return gpu_kms->file_path;
 | 
			
		||||
  return meta_kms_device_get_path (gpu_kms->kms_device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t
 | 
			
		||||
@@ -420,7 +154,8 @@ meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_gpu_kms_set_power_save_mode (MetaGpuKms    *gpu_kms,
 | 
			
		||||
                                  uint64_t    state)
 | 
			
		||||
                                  uint64_t       state,
 | 
			
		||||
                                  MetaKmsUpdate *kms_update)
 | 
			
		||||
{
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
@@ -428,31 +163,26 @@ meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *output = l->data;
 | 
			
		||||
 | 
			
		||||
      meta_output_kms_set_power_save_mode (output, state);
 | 
			
		||||
      meta_output_kms_set_power_save_mode (output, state, kms_update);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_gpu_kms_is_boot_vga (MetaGpuKms *gpu_kms)
 | 
			
		||||
{
 | 
			
		||||
  return !!(gpu_kms->flags & META_GPU_KMS_FLAG_BOOT_VGA);
 | 
			
		||||
  MetaKmsDeviceFlag flags;
 | 
			
		||||
 | 
			
		||||
  flags = meta_kms_device_get_flags (gpu_kms->kms_device);
 | 
			
		||||
  return !!(flags & META_KMS_DEVICE_FLAG_BOOT_VGA);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_gpu_kms_is_platform_device (MetaGpuKms *gpu_kms)
 | 
			
		||||
{
 | 
			
		||||
  return !!(gpu_kms->flags & META_GPU_KMS_FLAG_PLATFORM_DEVICE);
 | 
			
		||||
}
 | 
			
		||||
  MetaKmsDeviceFlag flags;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
free_resources (MetaGpuKms *gpu_kms)
 | 
			
		||||
{
 | 
			
		||||
  unsigned i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < gpu_kms->n_connectors; i++)
 | 
			
		||||
    drmModeFreeConnector (gpu_kms->connectors[i]);
 | 
			
		||||
 | 
			
		||||
  g_free (gpu_kms->connectors);
 | 
			
		||||
  flags = meta_kms_device_get_flags (gpu_kms->kms_device);
 | 
			
		||||
  return !!(flags & META_KMS_DEVICE_FLAG_PLATFORM_DEVICE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
@@ -530,24 +260,6 @@ meta_gpu_kms_get_mode_from_drm_mode (MetaGpuKms            *gpu_kms,
 | 
			
		||||
  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)
 | 
			
		||||
@@ -569,7 +281,7 @@ create_mode (const drmModeModeInfo *drm_mode,
 | 
			
		||||
 | 
			
		||||
static MetaOutput *
 | 
			
		||||
find_output_by_connector_id (GList    *outputs,
 | 
			
		||||
                             glong  id)
 | 
			
		||||
                             uint32_t  connector_id)
 | 
			
		||||
{
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
@@ -577,7 +289,7 @@ find_output_by_connector_id (GList *outputs,
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *output = l->data;
 | 
			
		||||
 | 
			
		||||
      if (meta_output_kms_get_connector_id (output) == id)
 | 
			
		||||
      if (meta_output_kms_get_connector_id (output) == connector_id)
 | 
			
		||||
        return output;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -615,51 +327,32 @@ setup_output_clones (MetaGpu *gpu)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_connectors (MetaGpuKms *gpu_kms,
 | 
			
		||||
                 drmModeRes *resources)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  gpu_kms->n_connectors = resources->count_connectors;
 | 
			
		||||
  gpu_kms->connectors = g_new (drmModeConnector *, gpu_kms->n_connectors);
 | 
			
		||||
  for (i = 0; i < gpu_kms->n_connectors; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModeConnector *drm_connector;
 | 
			
		||||
 | 
			
		||||
      drm_connector = drmModeGetConnector (gpu_kms->fd,
 | 
			
		||||
                                           resources->connectors[i]);
 | 
			
		||||
      gpu_kms->connectors[i] = drm_connector;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_modes (MetaGpuKms *gpu_kms,
 | 
			
		||||
            drmModeRes *resources)
 | 
			
		||||
init_modes (MetaGpuKms *gpu_kms)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = META_GPU (gpu_kms);
 | 
			
		||||
  GHashTable *modes_table;
 | 
			
		||||
  GList *l;
 | 
			
		||||
  GList *modes;
 | 
			
		||||
  GHashTableIter iter;
 | 
			
		||||
  drmModeModeInfo *drm_mode;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
  int i;
 | 
			
		||||
  long mode_id;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Gather all modes on all connected connectors.
 | 
			
		||||
   */
 | 
			
		||||
  modes_table = g_hash_table_new (drm_mode_hash, (GEqualFunc) meta_drm_mode_equal);
 | 
			
		||||
  for (i = 0; i < gpu_kms->n_connectors; i++)
 | 
			
		||||
  for (l = meta_kms_device_get_connectors (gpu_kms->kms_device); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      drmModeConnector *drm_connector;
 | 
			
		||||
      MetaKmsConnector *kms_connector = l->data;
 | 
			
		||||
      const MetaKmsConnectorState *state;
 | 
			
		||||
 | 
			
		||||
      drm_connector = gpu_kms->connectors[i];
 | 
			
		||||
      if (drm_connector && drm_connector->connection == DRM_MODE_CONNECTED)
 | 
			
		||||
        {
 | 
			
		||||
          unsigned int j;
 | 
			
		||||
      state = meta_kms_connector_get_current_state (kms_connector);
 | 
			
		||||
      if (!state)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
          for (j = 0; j < (unsigned int) drm_connector->count_modes; j++)
 | 
			
		||||
            g_hash_table_add (modes_table, &drm_connector->modes[j]);
 | 
			
		||||
        }
 | 
			
		||||
      for (i = 0; i < state->n_modes; i++)
 | 
			
		||||
        g_hash_table_add (modes_table, &state->modes[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  modes = NULL;
 | 
			
		||||
@@ -702,26 +395,21 @@ init_modes (MetaGpuKms *gpu_kms,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_crtcs (MetaGpuKms       *gpu_kms,
 | 
			
		||||
            MetaKmsResources *resources)
 | 
			
		||||
init_crtcs (MetaGpuKms *gpu_kms)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = META_GPU (gpu_kms);
 | 
			
		||||
  MetaKmsDevice *kms_device = gpu_kms->kms_device;
 | 
			
		||||
  GList *l;
 | 
			
		||||
  GList *crtcs;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  crtcs = NULL;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < (unsigned int) resources->resources->count_crtcs; i++)
 | 
			
		||||
  for (l = meta_kms_device_get_crtcs (kms_device); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      drmModeCrtc *drm_crtc;
 | 
			
		||||
      MetaKmsCrtc *kms_crtc = l->data;
 | 
			
		||||
      MetaCrtc *crtc;
 | 
			
		||||
 | 
			
		||||
      drm_crtc = drmModeGetCrtc (gpu_kms->fd,
 | 
			
		||||
                                 resources->resources->crtcs[i]);
 | 
			
		||||
 | 
			
		||||
      crtc = meta_create_kms_crtc (gpu_kms, drm_crtc, i);
 | 
			
		||||
 | 
			
		||||
      drmModeFreeCrtc (drm_crtc);
 | 
			
		||||
      crtc = meta_create_kms_crtc (gpu_kms, kms_crtc);
 | 
			
		||||
 | 
			
		||||
      crtcs = g_list_append (crtcs, crtc);
 | 
			
		||||
    }
 | 
			
		||||
@@ -741,33 +429,34 @@ 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;
 | 
			
		||||
  GList *outputs;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  old_outputs = meta_gpu_get_outputs (gpu);
 | 
			
		||||
 | 
			
		||||
  outputs = NULL;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < gpu_kms->n_connectors; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModeConnector *connector;
 | 
			
		||||
 | 
			
		||||
      connector = gpu_kms->connectors[i];
 | 
			
		||||
 | 
			
		||||
      if (connector && connector->connection == DRM_MODE_CONNECTED)
 | 
			
		||||
  for (l = meta_kms_device_get_connectors (gpu_kms->kms_device); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsConnector *kms_connector = l->data;
 | 
			
		||||
      const MetaKmsConnectorState *connector_state;
 | 
			
		||||
      MetaOutput *output;
 | 
			
		||||
      MetaOutput *old_output;
 | 
			
		||||
      GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
          old_output = find_output_by_connector_id (old_outputs,
 | 
			
		||||
                                                    connector->connector_id);
 | 
			
		||||
          output = meta_create_kms_output (gpu_kms, connector, resources,
 | 
			
		||||
      connector_state = meta_kms_connector_get_current_state (kms_connector);
 | 
			
		||||
      if (!connector_state)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      old_output =
 | 
			
		||||
        find_output_by_connector_id (old_outputs,
 | 
			
		||||
                                     meta_kms_connector_get_id (kms_connector));
 | 
			
		||||
      output = meta_create_kms_output (gpu_kms,
 | 
			
		||||
                                       kms_connector,
 | 
			
		||||
                                       old_output,
 | 
			
		||||
                                       &error);
 | 
			
		||||
      if (!output)
 | 
			
		||||
@@ -780,7 +469,6 @@ init_outputs (MetaGpuKms       *gpu_kms,
 | 
			
		||||
          outputs = g_list_prepend (outputs, output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /* Sort the outputs for easier handling in MetaMonitorConfig */
 | 
			
		||||
@@ -790,159 +478,64 @@ init_outputs (MetaGpuKms       *gpu_kms,
 | 
			
		||||
  setup_output_clones (gpu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_kms_resources_init (MetaKmsResources  *resources,
 | 
			
		||||
                         int                fd,
 | 
			
		||||
                         GError           **error)
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
  drmModeRes *drm_resources;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  drm_resources = drmModeGetResources (fd);
 | 
			
		||||
 | 
			
		||||
  if (!drm_resources)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error,
 | 
			
		||||
                   G_IO_ERROR,
 | 
			
		||||
                   G_IO_ERROR_FAILED,
 | 
			
		||||
                   "Calling drmModeGetResources() failed");
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  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]);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&resources->resources, drmModeFreeResources);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_gpu_kms_read_current (MetaGpu  *gpu,
 | 
			
		||||
                           GError  **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
 | 
			
		||||
  MetaKmsResources resources;
 | 
			
		||||
  g_autoptr (GError) local_error = NULL;
 | 
			
		||||
 | 
			
		||||
  if (!meta_kms_resources_init (&resources, gpu_kms->fd, &local_error))
 | 
			
		||||
    {
 | 
			
		||||
      if (!gpu_kms->resources_init_failed_before)
 | 
			
		||||
        {
 | 
			
		||||
          g_warning ("meta_kms_resources_init failed: %s, assuming we have no outputs",
 | 
			
		||||
                     local_error->message);
 | 
			
		||||
          gpu_kms->resources_init_failed_before = TRUE;
 | 
			
		||||
        }
 | 
			
		||||
      return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  gpu_kms->max_buffer_width = resources.resources->max_width;
 | 
			
		||||
  gpu_kms->max_buffer_height = resources.resources->max_height;
 | 
			
		||||
 | 
			
		||||
  /* 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 (gpu_kms);
 | 
			
		||||
 | 
			
		||||
  init_connectors (gpu_kms, resources.resources);
 | 
			
		||||
  init_modes (gpu_kms, resources.resources);
 | 
			
		||||
  init_crtcs (gpu_kms, &resources);
 | 
			
		||||
  init_outputs (gpu_kms, &resources);
 | 
			
		||||
  init_modes (gpu_kms);
 | 
			
		||||
  init_crtcs (gpu_kms);
 | 
			
		||||
  init_outputs (gpu_kms);
 | 
			
		||||
  init_frame_clock (gpu_kms);
 | 
			
		||||
 | 
			
		||||
  meta_kms_resources_release (&resources);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_gpu_kms_can_have_outputs (MetaGpuKms *gpu_kms)
 | 
			
		||||
{
 | 
			
		||||
  return gpu_kms->n_connectors > 0;
 | 
			
		||||
  GList *l;
 | 
			
		||||
  int n_connected_connectors = 0;
 | 
			
		||||
 | 
			
		||||
  for (l = meta_kms_device_get_connectors (gpu_kms->kms_device); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsConnector *kms_connector = l->data;
 | 
			
		||||
 | 
			
		||||
      if (meta_kms_connector_get_current_state (kms_connector))
 | 
			
		||||
        n_connected_connectors++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return n_connected_connectors > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaGpuKms *
 | 
			
		||||
meta_gpu_kms_new (MetaMonitorManagerKms  *monitor_manager_kms,
 | 
			
		||||
                  const char             *kms_file_path,
 | 
			
		||||
                  MetaGpuKmsFlag          flags,
 | 
			
		||||
meta_gpu_kms_new (MetaBackendNative  *backend_native,
 | 
			
		||||
                  MetaKmsDevice      *kms_device,
 | 
			
		||||
                  GError            **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    META_MONITOR_MANAGER (monitor_manager_kms);
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (monitor_manager);
 | 
			
		||||
  MetaLauncher *launcher =
 | 
			
		||||
    meta_backend_native_get_launcher (META_BACKEND_NATIVE (backend));
 | 
			
		||||
  GSource *source;
 | 
			
		||||
  MetaKmsSource *kms_source;
 | 
			
		||||
  MetaGpuKms *gpu_kms;
 | 
			
		||||
  int kms_fd;
 | 
			
		||||
 | 
			
		||||
  kms_fd = meta_launcher_open_restricted (launcher, kms_file_path, error);
 | 
			
		||||
  if (kms_fd == -1)
 | 
			
		||||
    return NULL;
 | 
			
		||||
  kms_fd = meta_kms_device_leak_fd (kms_device);
 | 
			
		||||
 | 
			
		||||
  gpu_kms = g_object_new (META_TYPE_GPU_KMS,
 | 
			
		||||
                          "monitor-manager", monitor_manager_kms,
 | 
			
		||||
                          "backend", backend_native,
 | 
			
		||||
                          NULL);
 | 
			
		||||
 | 
			
		||||
  gpu_kms->flags = flags;
 | 
			
		||||
  gpu_kms->kms_device = kms_device;
 | 
			
		||||
  gpu_kms->fd = kms_fd;
 | 
			
		||||
  gpu_kms->file_path = g_strdup (kms_file_path);
 | 
			
		||||
 | 
			
		||||
  drmSetClientCap (gpu_kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
 | 
			
		||||
 | 
			
		||||
  meta_gpu_kms_read_current (META_GPU (gpu_kms), NULL);
 | 
			
		||||
 | 
			
		||||
  source = g_source_new (&kms_event_funcs, sizeof (MetaKmsSource));
 | 
			
		||||
  kms_source = (MetaKmsSource *) source;
 | 
			
		||||
  kms_source->fd_tag = g_source_add_unix_fd (source,
 | 
			
		||||
                                             gpu_kms->fd,
 | 
			
		||||
                                             G_IO_IN | G_IO_ERR);
 | 
			
		||||
  kms_source->gpu_kms = gpu_kms;
 | 
			
		||||
 | 
			
		||||
  gpu_kms->source = source;
 | 
			
		||||
  g_source_attach (gpu_kms->source, NULL);
 | 
			
		||||
 | 
			
		||||
  return gpu_kms;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_gpu_kms_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpuKms *gpu_kms = META_GPU_KMS (object);
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_gpu_get_monitor_manager (META_GPU (gpu_kms));
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (monitor_manager);
 | 
			
		||||
  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
 | 
			
		||||
  MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
 | 
			
		||||
 | 
			
		||||
  if (gpu_kms->fd != -1)
 | 
			
		||||
    meta_launcher_close_restricted (launcher, gpu_kms->fd);
 | 
			
		||||
  g_clear_pointer (&gpu_kms->file_path, g_free);
 | 
			
		||||
 | 
			
		||||
  g_source_destroy (gpu_kms->source);
 | 
			
		||||
 | 
			
		||||
  free_resources (gpu_kms);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_gpu_kms_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_gpu_kms_init (MetaGpuKms *gpu_kms)
 | 
			
		||||
{
 | 
			
		||||
@@ -955,10 +548,7 @@ meta_gpu_kms_init (MetaGpuKms *gpu_kms)
 | 
			
		||||
static void
 | 
			
		||||
meta_gpu_kms_class_init (MetaGpuKmsClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
  MetaGpuClass *gpu_class = META_GPU_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_gpu_kms_finalize;
 | 
			
		||||
 | 
			
		||||
  gpu_class->read_current = meta_gpu_kms_read_current;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,40 +28,18 @@
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-gpu.h"
 | 
			
		||||
#include "backends/native/meta-monitor-manager-kms.h"
 | 
			
		||||
#include "backends/native/meta-backend-native.h"
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_GPU_KMS (meta_gpu_kms_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaGpuKms, meta_gpu_kms, META, GPU_KMS, MetaGpu)
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaGpuKmsFlipClosureContainer MetaGpuKmsFlipClosureContainer;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsResources
 | 
			
		||||
{
 | 
			
		||||
  drmModeRes *resources;
 | 
			
		||||
  drmModeEncoder **encoders;
 | 
			
		||||
  unsigned int n_encoders;
 | 
			
		||||
} MetaKmsResources;
 | 
			
		||||
 | 
			
		||||
typedef void (*MetaKmsFlipCallback) (void *user_data);
 | 
			
		||||
 | 
			
		||||
typedef enum _MetaGpuKmsFlag
 | 
			
		||||
{
 | 
			
		||||
  META_GPU_KMS_FLAG_NONE =                  0,
 | 
			
		||||
  META_GPU_KMS_FLAG_BOOT_VGA =        (1 << 0),
 | 
			
		||||
  META_GPU_KMS_FLAG_PLATFORM_DEVICE = (1 << 1),
 | 
			
		||||
} MetaGpuKmsFlag;
 | 
			
		||||
 | 
			
		||||
MetaGpuKms * meta_gpu_kms_new (MetaMonitorManagerKms  *monitor_manager_kms,
 | 
			
		||||
                               const char             *kms_file_path,
 | 
			
		||||
                               MetaGpuKmsFlag          flags,
 | 
			
		||||
MetaGpuKms * meta_gpu_kms_new (MetaBackendNative  *backend_native,
 | 
			
		||||
                               MetaKmsDevice      *kms_device,
 | 
			
		||||
                               GError            **error);
 | 
			
		||||
 | 
			
		||||
gboolean meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms,
 | 
			
		||||
                                       MetaCrtc   *crtc,
 | 
			
		||||
                                       int         x,
 | 
			
		||||
                                       int         y,
 | 
			
		||||
                                       uint32_t    fb_id);
 | 
			
		||||
 | 
			
		||||
gboolean meta_gpu_kms_can_have_outputs (MetaGpuKms *gpu_kms);
 | 
			
		||||
 | 
			
		||||
gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
 | 
			
		||||
@@ -70,15 +48,11 @@ gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
 | 
			
		||||
gboolean meta_gpu_kms_is_boot_vga (MetaGpuKms *gpu_kms);
 | 
			
		||||
gboolean meta_gpu_kms_is_platform_device (MetaGpuKms *gpu_kms);
 | 
			
		||||
 | 
			
		||||
gboolean meta_gpu_kms_flip_crtc (MetaGpuKms  *gpu_kms,
 | 
			
		||||
                                 MetaCrtc    *crtc,
 | 
			
		||||
                                 uint32_t     fb_id,
 | 
			
		||||
                                 GClosure    *flip_closure,
 | 
			
		||||
                                 GError     **error);
 | 
			
		||||
 | 
			
		||||
gboolean meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms,
 | 
			
		||||
                                     GError    **error);
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice * meta_gpu_kms_get_kms_device (MetaGpuKms *gpu_kms);
 | 
			
		||||
 | 
			
		||||
int meta_gpu_kms_get_fd (MetaGpuKms *gpu_kms);
 | 
			
		||||
 | 
			
		||||
uint32_t meta_gpu_kms_get_id (MetaGpuKms *gpu_kms);
 | 
			
		||||
@@ -87,12 +61,9 @@ const char * meta_gpu_kms_get_file_path (MetaGpuKms *gpu_kms);
 | 
			
		||||
 | 
			
		||||
int64_t meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms);
 | 
			
		||||
 | 
			
		||||
void meta_gpu_kms_get_max_buffer_size (MetaGpuKms *gpu_kms,
 | 
			
		||||
                                       int        *max_width,
 | 
			
		||||
                                       int        *max_height);
 | 
			
		||||
 | 
			
		||||
void meta_gpu_kms_set_power_save_mode (MetaGpuKms    *gpu_kms,
 | 
			
		||||
                                       uint64_t    state);
 | 
			
		||||
                                       uint64_t       state,
 | 
			
		||||
                                       MetaKmsUpdate *kms_update);
 | 
			
		||||
 | 
			
		||||
MetaCrtcMode * meta_gpu_kms_get_mode_from_drm_mode (MetaGpuKms            *gpu_kms,
 | 
			
		||||
                                                    const drmModeModeInfo *drm_mode);
 | 
			
		||||
@@ -100,8 +71,6 @@ MetaCrtcMode * meta_gpu_kms_get_mode_from_drm_mode (MetaGpuKms            *gpu_k
 | 
			
		||||
gboolean meta_drm_mode_equal (const drmModeModeInfo *one,
 | 
			
		||||
                              const drmModeModeInfo *two);
 | 
			
		||||
 | 
			
		||||
float meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *mode);
 | 
			
		||||
 | 
			
		||||
MetaGpuKmsFlipClosureContainer * meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms,
 | 
			
		||||
                                                                 MetaCrtc   *crtc,
 | 
			
		||||
                                                                 GClosure   *flip_closure);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								src/backends/native/meta-kms-connector-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/backends/native/meta-kms-connector-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_CONNECTOR_PRIVATE_H
 | 
			
		||||
#define META_KMS_CONNECTOR_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#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);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_CONNECTOR_PRIVATE_H */
 | 
			
		||||
							
								
								
									
										607
									
								
								src/backends/native/meta-kms-connector.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										607
									
								
								src/backends/native/meta-kms-connector.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,607 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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-kms-connector.h"
 | 
			
		||||
#include "backends/native/meta-kms-connector-private.h"
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-device-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-impl-device.h"
 | 
			
		||||
#include "backends/native/meta-kms-update-private.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaKmsConnector
 | 
			
		||||
{
 | 
			
		||||
  GObject parent;
 | 
			
		||||
 | 
			
		||||
  MetaKmsDevice *device;
 | 
			
		||||
 | 
			
		||||
  uint32_t id;
 | 
			
		||||
  MetaConnectorType type;
 | 
			
		||||
  char *name;
 | 
			
		||||
 | 
			
		||||
  MetaKmsConnectorState *current_state;
 | 
			
		||||
 | 
			
		||||
  uint32_t dpms_prop_id;
 | 
			
		||||
  uint32_t underscan_prop_id;
 | 
			
		||||
  uint32_t underscan_hborder_prop_id;
 | 
			
		||||
  uint32_t underscan_vborder_prop_id;
 | 
			
		||||
  uint32_t edid_blob_id;
 | 
			
		||||
  uint32_t tile_blob_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice *
 | 
			
		||||
meta_kms_connector_get_device (MetaKmsConnector *connector)
 | 
			
		||||
{
 | 
			
		||||
  return connector->device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_connector_update_set_dpms_state (MetaKmsConnector *connector,
 | 
			
		||||
                                          MetaKmsUpdate    *update,
 | 
			
		||||
                                          uint64_t          state)
 | 
			
		||||
{
 | 
			
		||||
  meta_kms_update_set_connector_property (update,
 | 
			
		||||
                                          connector,
 | 
			
		||||
                                          connector->dpms_prop_id,
 | 
			
		||||
                                          state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_connector_set_underscanning (MetaKmsConnector *connector,
 | 
			
		||||
                                      MetaKmsUpdate    *update,
 | 
			
		||||
                                      uint64_t          hborder,
 | 
			
		||||
                                      uint64_t          vborder)
 | 
			
		||||
{
 | 
			
		||||
  meta_kms_update_set_connector_property (update,
 | 
			
		||||
                                          connector,
 | 
			
		||||
                                          connector->underscan_prop_id,
 | 
			
		||||
                                          1);
 | 
			
		||||
  meta_kms_update_set_connector_property (update,
 | 
			
		||||
                                          connector,
 | 
			
		||||
                                          connector->underscan_hborder_prop_id,
 | 
			
		||||
                                          hborder);
 | 
			
		||||
  meta_kms_update_set_connector_property (update,
 | 
			
		||||
                                          connector,
 | 
			
		||||
                                          connector->underscan_vborder_prop_id,
 | 
			
		||||
                                          vborder);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_connector_unset_underscanning (MetaKmsConnector *connector,
 | 
			
		||||
                                        MetaKmsUpdate    *update)
 | 
			
		||||
{
 | 
			
		||||
  meta_kms_update_set_connector_property (update,
 | 
			
		||||
                                          connector,
 | 
			
		||||
                                          connector->underscan_prop_id,
 | 
			
		||||
                                          0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaConnectorType
 | 
			
		||||
meta_kms_connector_get_connector_type (MetaKmsConnector *connector)
 | 
			
		||||
{
 | 
			
		||||
  return connector->type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t
 | 
			
		||||
meta_kms_connector_get_id (MetaKmsConnector *connector)
 | 
			
		||||
{
 | 
			
		||||
  return connector->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector)
 | 
			
		||||
{
 | 
			
		||||
  return connector->underscan_prop_id != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 void
 | 
			
		||||
find_property_ids (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_ENUM) &&
 | 
			
		||||
          strcmp (prop->name, "DPMS") == 0)
 | 
			
		||||
        connector->dpms_prop_id = prop->prop_id;
 | 
			
		||||
      else if ((prop->flags & DRM_MODE_PROP_ENUM) &&
 | 
			
		||||
               strcmp (prop->name, "underscan") == 0)
 | 
			
		||||
        connector->underscan_prop_id = prop->prop_id;
 | 
			
		||||
      else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
 | 
			
		||||
               strcmp (prop->name, "underscan hborder") == 0)
 | 
			
		||||
        connector->underscan_hborder_prop_id = prop->prop_id;
 | 
			
		||||
      else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
 | 
			
		||||
               strcmp (prop->name, "underscan vborder") == 0)
 | 
			
		||||
        connector->underscan_vborder_prop_id = prop->prop_id;
 | 
			
		||||
 | 
			
		||||
      drmModeFreeProperty (prop);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
make_connector_name (drmModeConnector *drm_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 (drm_connector->connector_type < G_N_ELEMENTS (connector_type_names))
 | 
			
		||||
    return g_strdup_printf ("%s-%d",
 | 
			
		||||
                            connector_type_names[drm_connector->connector_type],
 | 
			
		||||
                            drm_connector->connector_type_id);
 | 
			
		||||
  else
 | 
			
		||||
    return g_strdup_printf ("Unknown%d-%d",
 | 
			
		||||
                            drm_connector->connector_type,
 | 
			
		||||
                            drm_connector->connector_type_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsConnector *
 | 
			
		||||
meta_kms_connector_new (MetaKmsImplDevice *impl_device,
 | 
			
		||||
                        drmModeConnector  *drm_connector,
 | 
			
		||||
                        drmModeRes        *drm_resources)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsConnector *connector;
 | 
			
		||||
 | 
			
		||||
  connector = g_object_new (META_TYPE_KMS_CONNECTOR, NULL);
 | 
			
		||||
  connector->device = meta_kms_impl_device_get_device (impl_device);
 | 
			
		||||
  connector->id = drm_connector->connector_id;
 | 
			
		||||
  connector->type = (MetaConnectorType) drm_connector->connector_type;
 | 
			
		||||
  connector->name = make_connector_name (drm_connector);
 | 
			
		||||
 | 
			
		||||
  find_property_ids (connector, impl_device, drm_connector);
 | 
			
		||||
 | 
			
		||||
  meta_kms_connector_read_state (connector, impl_device,
 | 
			
		||||
                                 drm_connector,
 | 
			
		||||
                                 drm_resources);
 | 
			
		||||
 | 
			
		||||
  return connector;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_connector_init (MetaKmsConnector *connector)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_connector_class_init (MetaKmsConnectorClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_kms_connector_finalize;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										89
									
								
								src/backends/native/meta-kms-connector.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/backends/native/meta-kms-connector.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_CONNECTOR_H
 | 
			
		||||
#define META_KMS_CONNECTOR_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <xf86drmMode.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);
 | 
			
		||||
 | 
			
		||||
void meta_kms_connector_update_set_dpms_state (MetaKmsConnector *connector,
 | 
			
		||||
                                               MetaKmsUpdate    *update,
 | 
			
		||||
                                               uint64_t          state);
 | 
			
		||||
 | 
			
		||||
void meta_kms_connector_set_underscanning (MetaKmsConnector *connector,
 | 
			
		||||
                                           MetaKmsUpdate    *update,
 | 
			
		||||
                                           uint64_t          hborder,
 | 
			
		||||
                                           uint64_t          vborder);
 | 
			
		||||
 | 
			
		||||
void meta_kms_connector_unset_underscanning (MetaKmsConnector *connector,
 | 
			
		||||
                                             MetaKmsUpdate    *update);
 | 
			
		||||
 | 
			
		||||
MetaConnectorType meta_kms_connector_get_connector_type (MetaKmsConnector *connector);
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
gboolean meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_CONNECTOR_H */
 | 
			
		||||
							
								
								
									
										33
									
								
								src/backends/native/meta-kms-crtc-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/backends/native/meta-kms-crtc-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_CRTC_PRIVATE_H
 | 
			
		||||
#define META_KMS_CRTC_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
 | 
			
		||||
MetaKmsCrtc * meta_kms_crtc_new (MetaKmsImplDevice *impl_device,
 | 
			
		||||
                                 drmModeCrtc       *drm_crtc,
 | 
			
		||||
                                 int                idx);
 | 
			
		||||
 | 
			
		||||
void meta_kms_crtc_update_state (MetaKmsCrtc *crtc);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_CRTC_PRIVATE_H */
 | 
			
		||||
							
								
								
									
										160
									
								
								src/backends/native/meta-kms-crtc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								src/backends/native/meta-kms-crtc.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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-kms-crtc.h"
 | 
			
		||||
#include "backends/native/meta-kms-crtc-private.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-device-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-impl-device.h"
 | 
			
		||||
#include "backends/native/meta-kms-update-private.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaKmsCrtc
 | 
			
		||||
{
 | 
			
		||||
  GObject parent;
 | 
			
		||||
 | 
			
		||||
  MetaKmsDevice *device;
 | 
			
		||||
 | 
			
		||||
  uint32_t id;
 | 
			
		||||
  int idx;
 | 
			
		||||
 | 
			
		||||
  MetaKmsCrtcState current_state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice *
 | 
			
		||||
meta_kms_crtc_get_device (MetaKmsCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
  return crtc->device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MetaKmsCrtcState *
 | 
			
		||||
meta_kms_crtc_get_current_state (MetaKmsCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
  return &crtc->current_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t
 | 
			
		||||
meta_kms_crtc_get_id (MetaKmsCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
  return crtc->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_kms_crtc_get_idx (MetaKmsCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
  return crtc->idx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_crtc_read_state (MetaKmsCrtc       *crtc,
 | 
			
		||||
                          MetaKmsImplDevice *impl_device,
 | 
			
		||||
                          drmModeCrtc       *drm_crtc)
 | 
			
		||||
{
 | 
			
		||||
  g_clear_pointer (&crtc->current_state.gamma.red, g_free);
 | 
			
		||||
  g_clear_pointer (&crtc->current_state.gamma.green, g_free);
 | 
			
		||||
  g_clear_pointer (&crtc->current_state.gamma.blue, g_free);
 | 
			
		||||
 | 
			
		||||
  crtc->current_state = (MetaKmsCrtcState) {
 | 
			
		||||
    .rect = {
 | 
			
		||||
      .x = drm_crtc->x,
 | 
			
		||||
      .y = drm_crtc->y,
 | 
			
		||||
      .width = drm_crtc->width,
 | 
			
		||||
      .height = drm_crtc->height,
 | 
			
		||||
    },
 | 
			
		||||
    .is_drm_mode_valid = drm_crtc->mode_valid,
 | 
			
		||||
    .drm_mode = drm_crtc->mode,
 | 
			
		||||
    .gamma = {
 | 
			
		||||
      .size = drm_crtc->gamma_size,
 | 
			
		||||
      .red = g_new0 (unsigned short, drm_crtc->gamma_size),
 | 
			
		||||
      .green = g_new0 (unsigned short, drm_crtc->gamma_size),
 | 
			
		||||
      .blue = g_new0 (unsigned short, drm_crtc->gamma_size),
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  drmModeCrtcGetGamma (meta_kms_impl_device_get_fd (impl_device),
 | 
			
		||||
                       crtc->id,
 | 
			
		||||
                       drm_crtc->gamma_size,
 | 
			
		||||
                       crtc->current_state.gamma.red,
 | 
			
		||||
                       crtc->current_state.gamma.green,
 | 
			
		||||
                       crtc->current_state.gamma.blue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_crtc_update_state (MetaKmsCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplDevice *impl_device;
 | 
			
		||||
  drmModeCrtc *drm_crtc;
 | 
			
		||||
 | 
			
		||||
  impl_device = meta_kms_device_get_impl_device (crtc->device);
 | 
			
		||||
  drm_crtc = drmModeGetCrtc (meta_kms_impl_device_get_fd (impl_device),
 | 
			
		||||
                             crtc->id);
 | 
			
		||||
  meta_kms_crtc_read_state (crtc, impl_device, drm_crtc);
 | 
			
		||||
  drmModeFreeCrtc (drm_crtc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsCrtc *
 | 
			
		||||
meta_kms_crtc_new (MetaKmsImplDevice *impl_device,
 | 
			
		||||
                   drmModeCrtc       *drm_crtc,
 | 
			
		||||
                   int                idx)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCrtc *crtc;
 | 
			
		||||
 | 
			
		||||
  crtc = g_object_new (META_TYPE_KMS_CRTC, NULL);
 | 
			
		||||
  crtc->device = meta_kms_impl_device_get_device (impl_device);
 | 
			
		||||
  crtc->id = drm_crtc->crtc_id;
 | 
			
		||||
  crtc->idx = idx;
 | 
			
		||||
 | 
			
		||||
  return crtc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_crtc_init (MetaKmsCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_crtc_class_init (MetaKmsCrtcClass *klass)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_crtc_get_gamma (MetaKmsCrtc     *crtc,
 | 
			
		||||
                         gsize           *size,
 | 
			
		||||
                         unsigned short **red,
 | 
			
		||||
                         unsigned short **green,
 | 
			
		||||
                         unsigned short **blue)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int n_gamma_values = crtc->current_state.gamma.size;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  *size = n_gamma_values;
 | 
			
		||||
  *red = g_new0 (unsigned short, n_gamma_values);
 | 
			
		||||
  *green = g_new0 (unsigned short, n_gamma_values);
 | 
			
		||||
  *blue = g_new0 (unsigned short, n_gamma_values);
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_gamma_values; i++)
 | 
			
		||||
    {
 | 
			
		||||
      *red[i] = crtc->current_state.gamma.red[i];
 | 
			
		||||
      *green[i] = crtc->current_state.gamma.green[i];
 | 
			
		||||
      *blue[i] = crtc->current_state.gamma.blue[i];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								src/backends/native/meta-kms-crtc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/backends/native/meta-kms-crtc.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_CRTC_H
 | 
			
		||||
#define META_KMS_CRTC_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
#include "meta/boxes.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsCrtcState
 | 
			
		||||
{
 | 
			
		||||
  MetaRectangle rect;
 | 
			
		||||
  gboolean is_drm_mode_valid;
 | 
			
		||||
  drmModeModeInfo drm_mode;
 | 
			
		||||
 | 
			
		||||
  uint32_t common_possible_crtcs;
 | 
			
		||||
  uint32_t common_possible_clones;
 | 
			
		||||
  uint32_t encoder_device_idxs;
 | 
			
		||||
 | 
			
		||||
  struct {
 | 
			
		||||
    unsigned int size;
 | 
			
		||||
    unsigned short *red;
 | 
			
		||||
    unsigned short *green;
 | 
			
		||||
    unsigned short *blue;
 | 
			
		||||
  } gamma;
 | 
			
		||||
} MetaKmsCrtcState;
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_KMS_CRTC (meta_kms_crtc_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaKmsCrtc, meta_kms_crtc,
 | 
			
		||||
                      META, KMS_CRTC,
 | 
			
		||||
                      GObject)
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice * meta_kms_crtc_get_device (MetaKmsCrtc *crtc);
 | 
			
		||||
 | 
			
		||||
const MetaKmsCrtcState * meta_kms_crtc_get_current_state (MetaKmsCrtc *crtc);
 | 
			
		||||
 | 
			
		||||
uint32_t meta_kms_crtc_get_id (MetaKmsCrtc *crtc);
 | 
			
		||||
 | 
			
		||||
int meta_kms_crtc_get_idx (MetaKmsCrtc *crtc);
 | 
			
		||||
 | 
			
		||||
void meta_kms_crtc_get_gamma (MetaKmsCrtc     *crtc,
 | 
			
		||||
                              gsize           *size,
 | 
			
		||||
                              unsigned short **red,
 | 
			
		||||
                              unsigned short **green,
 | 
			
		||||
                              unsigned short **blue);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_CRTC_H */
 | 
			
		||||
							
								
								
									
										27
									
								
								src/backends/native/meta-kms-device-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/backends/native/meta-kms-device-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_DEVICE_PRIVATE_H
 | 
			
		||||
#define META_KMS_DEVICE_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
 | 
			
		||||
MetaKmsImplDevice * meta_kms_device_get_impl_device (MetaKmsDevice *device);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_DEVICE_PRIVATE_H */
 | 
			
		||||
							
								
								
									
										277
									
								
								src/backends/native/meta-kms-device.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								src/backends/native/meta-kms-device.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,277 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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-kms-device-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-device.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-backend-native.h"
 | 
			
		||||
#include "backends/native/meta-kms-impl-device.h"
 | 
			
		||||
#include "backends/native/meta-kms-impl.h"
 | 
			
		||||
#include "backends/native/meta-kms-plane.h"
 | 
			
		||||
#include "backends/native/meta-kms-private.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaKmsDevice
 | 
			
		||||
{
 | 
			
		||||
  GObject parent;
 | 
			
		||||
 | 
			
		||||
  MetaKms *kms;
 | 
			
		||||
 | 
			
		||||
  MetaKmsImplDevice *impl_device;
 | 
			
		||||
 | 
			
		||||
  MetaKmsDeviceFlag flags;
 | 
			
		||||
  char *path;
 | 
			
		||||
 | 
			
		||||
  GList *crtcs;
 | 
			
		||||
  GList *connectors;
 | 
			
		||||
  GList *planes;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaKmsDevice, meta_kms_device, G_TYPE_OBJECT);
 | 
			
		||||
 | 
			
		||||
MetaKmsImplDevice *
 | 
			
		||||
meta_kms_device_get_impl_device (MetaKmsDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  return device->impl_device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_kms_device_leak_fd (MetaKmsDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  return meta_kms_impl_device_leak_fd (device->impl_device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *
 | 
			
		||||
meta_kms_device_get_path (MetaKmsDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  return device->path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsDeviceFlag
 | 
			
		||||
meta_kms_device_get_flags (MetaKmsDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  return device->flags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_kms_device_get_connectors (MetaKmsDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  return device->connectors;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_kms_device_get_crtcs (MetaKmsDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  return device->crtcs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GList *
 | 
			
		||||
meta_kms_device_get_planes (MetaKmsDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  return device->planes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsPlane *
 | 
			
		||||
meta_kms_device_get_primary_plane_for (MetaKmsDevice *device,
 | 
			
		||||
                                       MetaKmsCrtc   *crtc)
 | 
			
		||||
{
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = meta_kms_device_get_planes (device); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsPlane *plane = l->data;
 | 
			
		||||
 | 
			
		||||
      if (meta_kms_plane_get_plane_type (plane) != META_KMS_PLANE_TYPE_PRIMARY)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if (meta_kms_plane_is_usable_with (plane, crtc))
 | 
			
		||||
        return plane;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
dispatch_in_impl (MetaKmsImpl  *impl,
 | 
			
		||||
                  gpointer      user_data,
 | 
			
		||||
                  GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (user_data);
 | 
			
		||||
 | 
			
		||||
  return meta_kms_impl_device_dispatch (impl_device, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_kms_device_dispatch_sync (MetaKmsDevice  *device,
 | 
			
		||||
                               GError        **error)
 | 
			
		||||
{
 | 
			
		||||
  int callback_count;
 | 
			
		||||
 | 
			
		||||
  callback_count = meta_kms_flush_callbacks (device->kms);
 | 
			
		||||
  if (callback_count > 0)
 | 
			
		||||
    return TRUE;
 | 
			
		||||
 | 
			
		||||
  if (!meta_kms_run_impl_task_sync (device->kms,
 | 
			
		||||
                                    dispatch_in_impl,
 | 
			
		||||
                                    device->impl_device,
 | 
			
		||||
                                    error))
 | 
			
		||||
    return -1;
 | 
			
		||||
 | 
			
		||||
  return meta_kms_flush_callbacks (device->kms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct _CreateImplDeviceData
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsDevice *device;
 | 
			
		||||
  int fd;
 | 
			
		||||
 | 
			
		||||
  MetaKmsImplDevice *out_impl_device;
 | 
			
		||||
  GList *out_crtcs;
 | 
			
		||||
  GList *out_connectors;
 | 
			
		||||
  GList *out_planes;
 | 
			
		||||
} CreateImplDeviceData;
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
create_impl_device_in_impl (MetaKmsImpl  *impl,
 | 
			
		||||
                            gpointer      user_data,
 | 
			
		||||
                            GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  CreateImplDeviceData *data = user_data;
 | 
			
		||||
  MetaKmsImplDevice *impl_device;
 | 
			
		||||
 | 
			
		||||
  impl_device = meta_kms_impl_device_new (data->device, impl, data->fd);
 | 
			
		||||
 | 
			
		||||
  data->out_impl_device = impl_device;
 | 
			
		||||
  data->out_crtcs = meta_kms_impl_device_copy_crtcs (impl_device);
 | 
			
		||||
  data->out_connectors = meta_kms_impl_device_copy_connectors (impl_device);
 | 
			
		||||
  data->out_planes = meta_kms_impl_device_copy_planes (impl_device);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice *
 | 
			
		||||
meta_kms_device_new (MetaKms            *kms,
 | 
			
		||||
                     const char         *path,
 | 
			
		||||
                     MetaKmsDeviceFlag   flags,
 | 
			
		||||
                     GError            **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend *backend = meta_kms_get_backend (kms);
 | 
			
		||||
  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
 | 
			
		||||
  MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
 | 
			
		||||
  MetaKmsDevice *device;
 | 
			
		||||
  CreateImplDeviceData data;
 | 
			
		||||
  int fd;
 | 
			
		||||
 | 
			
		||||
  fd = meta_launcher_open_restricted (launcher, path, error);
 | 
			
		||||
  if (fd == -1)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  device = g_object_new (META_TYPE_KMS_DEVICE, NULL);
 | 
			
		||||
 | 
			
		||||
  data = (CreateImplDeviceData) {
 | 
			
		||||
    .device = device,
 | 
			
		||||
    .fd = fd,
 | 
			
		||||
  };
 | 
			
		||||
  if (!meta_kms_run_impl_task_sync (kms, create_impl_device_in_impl, &data,
 | 
			
		||||
                                    error))
 | 
			
		||||
    {
 | 
			
		||||
      meta_launcher_close_restricted (launcher, fd);
 | 
			
		||||
      g_object_unref (device);
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  device->kms = kms;
 | 
			
		||||
  device->impl_device = data.out_impl_device;
 | 
			
		||||
  device->flags = flags;
 | 
			
		||||
  device->path = g_strdup (path);
 | 
			
		||||
  device->crtcs = data.out_crtcs;
 | 
			
		||||
  device->connectors = data.out_connectors;
 | 
			
		||||
  device->planes = data.out_planes;
 | 
			
		||||
 | 
			
		||||
  return device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct _FreeImplDeviceData
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplDevice *impl_device;
 | 
			
		||||
 | 
			
		||||
  int out_fd;
 | 
			
		||||
} FreeImplDeviceData;
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
free_impl_device_in_impl (MetaKmsImpl  *impl,
 | 
			
		||||
                          gpointer      user_data,
 | 
			
		||||
                          GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  FreeImplDeviceData *data = user_data;
 | 
			
		||||
  MetaKmsImplDevice *impl_device = data->impl_device;
 | 
			
		||||
  int fd;
 | 
			
		||||
 | 
			
		||||
  fd = meta_kms_impl_device_close (impl_device);
 | 
			
		||||
  g_object_unref (impl_device);
 | 
			
		||||
 | 
			
		||||
  data->out_fd = fd;
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_device_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsDevice *device = META_KMS_DEVICE (object);
 | 
			
		||||
  MetaBackend *backend = meta_kms_get_backend (device->kms);
 | 
			
		||||
  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
 | 
			
		||||
  MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
 | 
			
		||||
  FreeImplDeviceData data;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  g_list_free (device->crtcs);
 | 
			
		||||
  g_list_free (device->connectors);
 | 
			
		||||
  g_list_free (device->planes);
 | 
			
		||||
 | 
			
		||||
  data = (FreeImplDeviceData) {
 | 
			
		||||
    .impl_device = device->impl_device,
 | 
			
		||||
  };
 | 
			
		||||
  if (!meta_kms_run_impl_task_sync (device->kms, free_impl_device_in_impl, &data,
 | 
			
		||||
                                   &error))
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to close KMS impl device: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      meta_launcher_close_restricted (launcher, data.out_fd);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_kms_device_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_device_init (MetaKmsDevice *device)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_device_class_init (MetaKmsDeviceClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_kms_device_finalize;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								src/backends/native/meta-kms-device.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/backends/native/meta-kms-device.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_DEVICE_H
 | 
			
		||||
#define META_KMS_DEVICE_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_KMS_DEVICE (meta_kms_device_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaKmsDevice, meta_kms_device,
 | 
			
		||||
                      META, KMS_DEVICE,
 | 
			
		||||
                      GObject)
 | 
			
		||||
 | 
			
		||||
int meta_kms_device_leak_fd (MetaKmsDevice *device);
 | 
			
		||||
 | 
			
		||||
const char * meta_kms_device_get_path (MetaKmsDevice *device);
 | 
			
		||||
 | 
			
		||||
MetaKmsDeviceFlag meta_kms_device_get_flags (MetaKmsDevice *device);
 | 
			
		||||
 | 
			
		||||
GList * meta_kms_device_get_connectors (MetaKmsDevice *device);
 | 
			
		||||
 | 
			
		||||
GList * meta_kms_device_get_crtcs (MetaKmsDevice *device);
 | 
			
		||||
 | 
			
		||||
MetaKmsPlane * meta_kms_device_get_primary_plane_for (MetaKmsDevice *device,
 | 
			
		||||
                                                      MetaKmsCrtc   *crtc);
 | 
			
		||||
 | 
			
		||||
int meta_kms_device_dispatch_sync (MetaKmsDevice  *device,
 | 
			
		||||
                                   GError        **error);
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice * meta_kms_device_new (MetaKms            *kms,
 | 
			
		||||
                                     const char         *path,
 | 
			
		||||
                                     MetaKmsDeviceFlag   flags,
 | 
			
		||||
                                     GError            **error);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_DEVICE_H */
 | 
			
		||||
							
								
								
									
										395
									
								
								src/backends/native/meta-kms-impl-device.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										395
									
								
								src/backends/native/meta-kms-impl-device.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,395 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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-kms-impl-device.h"
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <xf86drm.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-connector-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-connector.h"
 | 
			
		||||
#include "backends/native/meta-kms-crtc-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-crtc.h"
 | 
			
		||||
#include "backends/native/meta-kms-impl.h"
 | 
			
		||||
#include "backends/native/meta-kms-page-flip-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-plane.h"
 | 
			
		||||
#include "backends/native/meta-kms-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-update.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaKmsImplDevice
 | 
			
		||||
{
 | 
			
		||||
  GObject parent;
 | 
			
		||||
 | 
			
		||||
  MetaKmsDevice *device;
 | 
			
		||||
  MetaKmsImpl *impl;
 | 
			
		||||
 | 
			
		||||
  int fd;
 | 
			
		||||
  GSource *fd_source;
 | 
			
		||||
 | 
			
		||||
  GList *crtcs;
 | 
			
		||||
  GList *connectors;
 | 
			
		||||
  GList *planes;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaKmsImplDevice, meta_kms_impl_device, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice *
 | 
			
		||||
meta_kms_impl_device_get_device (MetaKmsImplDevice *impl_device)
 | 
			
		||||
{
 | 
			
		||||
  return impl_device->device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_kms_impl_device_copy_connectors (MetaKmsImplDevice *impl_device)
 | 
			
		||||
{
 | 
			
		||||
  return g_list_copy (impl_device->connectors);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_kms_impl_device_copy_crtcs (MetaKmsImplDevice *impl_device)
 | 
			
		||||
{
 | 
			
		||||
  return g_list_copy (impl_device->crtcs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device)
 | 
			
		||||
{
 | 
			
		||||
  return g_list_copy (impl_device->planes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
page_flip_handler (int           fd,
 | 
			
		||||
                   unsigned int  sequence,
 | 
			
		||||
                   unsigned int  sec,
 | 
			
		||||
                   unsigned int  usec,
 | 
			
		||||
                   void         *user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsPageFlipData *page_flip_data = user_data;
 | 
			
		||||
  MetaKmsImpl *impl;
 | 
			
		||||
 | 
			
		||||
  meta_kms_page_flip_data_set_timings_in_impl (page_flip_data,
 | 
			
		||||
                                               sequence, sec, usec);
 | 
			
		||||
 | 
			
		||||
  impl = meta_kms_page_flip_data_get_kms_impl (page_flip_data);
 | 
			
		||||
  meta_kms_impl_handle_page_flip_callback (impl, page_flip_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_kms_impl_device_dispatch (MetaKmsImplDevice  *impl_device,
 | 
			
		||||
                               GError            **error)
 | 
			
		||||
{
 | 
			
		||||
  drmEventContext drm_event_context;
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
 | 
			
		||||
 | 
			
		||||
  drm_event_context = (drmEventContext) { 0 };
 | 
			
		||||
  drm_event_context.version = 2;
 | 
			
		||||
  drm_event_context.page_flip_handler = page_flip_handler;
 | 
			
		||||
 | 
			
		||||
  while (TRUE)
 | 
			
		||||
    {
 | 
			
		||||
      if (drmHandleEvent (impl_device->fd, &drm_event_context) != 0)
 | 
			
		||||
        {
 | 
			
		||||
          struct pollfd pfd;
 | 
			
		||||
          int ret;
 | 
			
		||||
 | 
			
		||||
          if (errno != EAGAIN)
 | 
			
		||||
            {
 | 
			
		||||
              g_set_error_literal (error, G_IO_ERROR,
 | 
			
		||||
                                   g_io_error_from_errno (errno),
 | 
			
		||||
                                   strerror (errno));
 | 
			
		||||
              return FALSE;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          pfd.fd = impl_device->fd;
 | 
			
		||||
          pfd.events = POLL_IN | POLL_ERR;
 | 
			
		||||
          do
 | 
			
		||||
            {
 | 
			
		||||
              ret = poll (&pfd, 1, -1);
 | 
			
		||||
            }
 | 
			
		||||
          while (ret == -1 && errno == EINTR);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
kms_event_dispatch_in_impl (MetaKmsImpl  *impl,
 | 
			
		||||
                            gpointer      user_data,
 | 
			
		||||
                            GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplDevice *impl_device = user_data;
 | 
			
		||||
 | 
			
		||||
  return meta_kms_impl_device_dispatch (impl_device, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
drmModePropertyPtr
 | 
			
		||||
meta_kms_impl_device_find_property (MetaKmsImplDevice       *impl_device,
 | 
			
		||||
                                    drmModeObjectProperties *props,
 | 
			
		||||
                                    const char              *prop_name,
 | 
			
		||||
                                    int                     *out_idx)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < props->count_props; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModePropertyPtr prop;
 | 
			
		||||
 | 
			
		||||
      prop = drmModeGetProperty (impl_device->fd, props->props[i]);
 | 
			
		||||
      if (!prop)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if (strcmp (prop->name, prop_name) == 0)
 | 
			
		||||
        {
 | 
			
		||||
          *out_idx = i;
 | 
			
		||||
          return prop;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      drmModeFreeProperty (prop);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_crtcs (MetaKmsImplDevice *impl_device,
 | 
			
		||||
            drmModeRes        *drm_resources)
 | 
			
		||||
{
 | 
			
		||||
  int idx;
 | 
			
		||||
 | 
			
		||||
  for (idx = 0; idx < drm_resources->count_crtcs; idx++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModeCrtc *drm_crtc;
 | 
			
		||||
      MetaKmsCrtc *crtc;
 | 
			
		||||
 | 
			
		||||
      drm_crtc = drmModeGetCrtc (impl_device->fd, drm_resources->crtcs[idx]);
 | 
			
		||||
      crtc = meta_kms_crtc_new (impl_device, drm_crtc, idx);
 | 
			
		||||
      drmModeFreeCrtc (drm_crtc);
 | 
			
		||||
 | 
			
		||||
      impl_device->crtcs = g_list_prepend (impl_device->crtcs, crtc);
 | 
			
		||||
    }
 | 
			
		||||
  impl_device->crtcs = g_list_reverse (impl_device->crtcs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_connectors (MetaKmsImplDevice *impl_device,
 | 
			
		||||
                 drmModeRes        *drm_resources)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < drm_resources->count_connectors; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModeConnector *drm_connector;
 | 
			
		||||
      MetaKmsConnector *connector;
 | 
			
		||||
 | 
			
		||||
      drm_connector = drmModeGetConnector (impl_device->fd,
 | 
			
		||||
                                           drm_resources->connectors[i]);
 | 
			
		||||
      connector = meta_kms_connector_new (impl_device, drm_connector,
 | 
			
		||||
                                          drm_resources);
 | 
			
		||||
      drmModeFreeConnector (drm_connector);
 | 
			
		||||
 | 
			
		||||
      impl_device->connectors = g_list_prepend (impl_device->connectors,
 | 
			
		||||
                                                connector);
 | 
			
		||||
    }
 | 
			
		||||
  impl_device->connectors = g_list_reverse (impl_device->connectors);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaKmsPlaneType
 | 
			
		||||
get_plane_type (MetaKmsImplDevice       *impl_device,
 | 
			
		||||
                drmModeObjectProperties *props)
 | 
			
		||||
{
 | 
			
		||||
  drmModePropertyPtr prop;
 | 
			
		||||
  int idx;
 | 
			
		||||
 | 
			
		||||
  prop = meta_kms_impl_device_find_property (impl_device, props, "type", &idx);
 | 
			
		||||
  if (!prop)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
  drmModeFreeProperty (prop);
 | 
			
		||||
 | 
			
		||||
  switch (props->prop_values[idx])
 | 
			
		||||
    {
 | 
			
		||||
    case DRM_PLANE_TYPE_PRIMARY:
 | 
			
		||||
      return META_KMS_PLANE_TYPE_PRIMARY;
 | 
			
		||||
    case DRM_PLANE_TYPE_CURSOR:
 | 
			
		||||
      return META_KMS_PLANE_TYPE_CURSOR;
 | 
			
		||||
    case DRM_PLANE_TYPE_OVERLAY:
 | 
			
		||||
      return META_KMS_PLANE_TYPE_OVERLAY;
 | 
			
		||||
    default:
 | 
			
		||||
      g_warning ("Unhandled plane type %lu", props->prop_values[idx]);
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_planes (MetaKmsImplDevice *impl_device)
 | 
			
		||||
{
 | 
			
		||||
  int fd = impl_device->fd;
 | 
			
		||||
  drmModePlaneRes *drm_planes;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  drm_planes = drmModeGetPlaneResources (fd);
 | 
			
		||||
  if (!drm_planes)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < drm_planes->count_planes; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModePlane *drm_plane;
 | 
			
		||||
      drmModeObjectProperties *props;
 | 
			
		||||
 | 
			
		||||
      drm_plane = drmModeGetPlane (fd, drm_planes->planes[i]);
 | 
			
		||||
      if (!drm_plane)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      props = drmModeObjectGetProperties (fd,
 | 
			
		||||
                                          drm_plane->plane_id,
 | 
			
		||||
                                          DRM_MODE_OBJECT_PLANE);
 | 
			
		||||
      if (props)
 | 
			
		||||
        {
 | 
			
		||||
          MetaKmsPlaneType plane_type;
 | 
			
		||||
 | 
			
		||||
          plane_type = get_plane_type (impl_device, props);
 | 
			
		||||
          if (plane_type != -1)
 | 
			
		||||
            {
 | 
			
		||||
              MetaKmsPlane *plane;
 | 
			
		||||
 | 
			
		||||
              plane = meta_kms_plane_new (plane_type,
 | 
			
		||||
                                          impl_device,
 | 
			
		||||
                                          drm_plane, props);
 | 
			
		||||
 | 
			
		||||
              impl_device->planes = g_list_prepend (impl_device->planes, plane);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      g_clear_pointer (&props, drmModeFreeObjectProperties);
 | 
			
		||||
      drmModeFreePlane (drm_plane);
 | 
			
		||||
    }
 | 
			
		||||
  impl_device->planes = g_list_reverse (impl_device->planes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 *
 | 
			
		||||
meta_kms_impl_device_new (MetaKmsDevice *device,
 | 
			
		||||
                          MetaKmsImpl   *impl,
 | 
			
		||||
                          int            fd)
 | 
			
		||||
{
 | 
			
		||||
  MetaKms *kms = meta_kms_impl_get_kms (impl);
 | 
			
		||||
  MetaKmsImplDevice *impl_device;
 | 
			
		||||
  drmModeRes *drm_resources;
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  impl_device = g_object_new (META_TYPE_KMS_IMPL_DEVICE, NULL);
 | 
			
		||||
  impl_device->device = device;
 | 
			
		||||
  impl_device->impl = impl;
 | 
			
		||||
  impl_device->fd = fd;
 | 
			
		||||
 | 
			
		||||
  drmSetClientCap (fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
 | 
			
		||||
 | 
			
		||||
  drm_resources = drmModeGetResources (fd);
 | 
			
		||||
 | 
			
		||||
  init_crtcs (impl_device, drm_resources);
 | 
			
		||||
  init_connectors (impl_device, drm_resources);
 | 
			
		||||
  init_planes (impl_device);
 | 
			
		||||
 | 
			
		||||
  drmModeFreeResources (drm_resources);
 | 
			
		||||
 | 
			
		||||
  impl_device->fd_source =
 | 
			
		||||
    meta_kms_register_fd_in_impl (kms, fd,
 | 
			
		||||
                                  kms_event_dispatch_in_impl,
 | 
			
		||||
                                  impl_device);
 | 
			
		||||
 | 
			
		||||
  return impl_device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device)
 | 
			
		||||
{
 | 
			
		||||
  meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
 | 
			
		||||
 | 
			
		||||
  return impl_device->fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_kms_impl_device_leak_fd (MetaKmsImplDevice *impl_device)
 | 
			
		||||
{
 | 
			
		||||
  return impl_device->fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_kms_impl_device_close (MetaKmsImplDevice *impl_device)
 | 
			
		||||
{
 | 
			
		||||
  int fd;
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&impl_device->fd_source, g_source_destroy);
 | 
			
		||||
  fd = impl_device->fd;
 | 
			
		||||
  impl_device->fd = -1;
 | 
			
		||||
 | 
			
		||||
  return fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_device_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (object);
 | 
			
		||||
 | 
			
		||||
  g_list_free_full (impl_device->planes, g_object_unref);
 | 
			
		||||
  g_list_free_full (impl_device->crtcs, g_object_unref);
 | 
			
		||||
  g_list_free_full (impl_device->connectors, g_object_unref);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_kms_impl_device_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_device_init (MetaKmsImplDevice *device)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_device_class_init (MetaKmsImplDeviceClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_kms_impl_device_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										64
									
								
								src/backends/native/meta-kms-impl-device.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/backends/native/meta-kms-impl-device.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_IMPL_DEVICE_H
 | 
			
		||||
#define META_KMS_IMPL_DEVICE_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-device.h"
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
#include "backends/native/meta-kms-update.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_KMS_IMPL_DEVICE (meta_kms_impl_device_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaKmsImplDevice, meta_kms_impl_device,
 | 
			
		||||
                      META, KMS_IMPL_DEVICE,
 | 
			
		||||
                      GObject)
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice * meta_kms_impl_device_get_device (MetaKmsImplDevice *impl_device);
 | 
			
		||||
 | 
			
		||||
GList * meta_kms_impl_device_copy_connectors (MetaKmsImplDevice *impl_device);
 | 
			
		||||
 | 
			
		||||
GList * meta_kms_impl_device_copy_crtcs (MetaKmsImplDevice *impl_device);
 | 
			
		||||
 | 
			
		||||
GList * meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device);
 | 
			
		||||
 | 
			
		||||
gboolean meta_kms_impl_device_dispatch (MetaKmsImplDevice  *impl_device,
 | 
			
		||||
                                        GError            **error);
 | 
			
		||||
 | 
			
		||||
drmModePropertyPtr meta_kms_impl_device_find_property (MetaKmsImplDevice       *impl_device,
 | 
			
		||||
                                                       drmModeObjectProperties *props,
 | 
			
		||||
                                                       const char              *prop_name,
 | 
			
		||||
                                                       int                     *idx);
 | 
			
		||||
 | 
			
		||||
int meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device);
 | 
			
		||||
 | 
			
		||||
int meta_kms_impl_device_leak_fd (MetaKmsImplDevice *impl_device);
 | 
			
		||||
 | 
			
		||||
void meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device);
 | 
			
		||||
 | 
			
		||||
int meta_kms_impl_device_close (MetaKmsImplDevice *impl_device);
 | 
			
		||||
 | 
			
		||||
MetaKmsImplDevice * meta_kms_impl_device_new (MetaKmsDevice *device,
 | 
			
		||||
                                              MetaKmsImpl   *kms_impl,
 | 
			
		||||
                                              int            fd);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_IMPL_DEVICE_H */
 | 
			
		||||
							
								
								
									
										935
									
								
								src/backends/native/meta-kms-impl-simple.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										935
									
								
								src/backends/native/meta-kms-impl-simple.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,935 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2019 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-kms-impl-simple.h"
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <gbm.h>
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-connector.h"
 | 
			
		||||
#include "backends/native/meta-kms-crtc.h"
 | 
			
		||||
#include "backends/native/meta-kms-device-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-page-flip-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-plane.h"
 | 
			
		||||
#include "backends/native/meta-kms-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-update-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-utils.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _CachedModeSet
 | 
			
		||||
{
 | 
			
		||||
  GList *connectors;
 | 
			
		||||
  drmModeModeInfo *drm_mode;
 | 
			
		||||
} CachedModeSet;
 | 
			
		||||
 | 
			
		||||
struct _MetaKmsImplSimple
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImpl parent;
 | 
			
		||||
 | 
			
		||||
  GSource *mode_set_fallback_feedback_source;
 | 
			
		||||
  GList *mode_set_fallback_page_flip_datas;
 | 
			
		||||
 | 
			
		||||
  GList *pending_page_flip_retries;
 | 
			
		||||
  GSource *retry_page_flips_source;
 | 
			
		||||
 | 
			
		||||
  GList *postponed_page_flip_datas;
 | 
			
		||||
  GList *postponed_mode_set_fallback_datas;
 | 
			
		||||
 | 
			
		||||
  GHashTable *cached_mode_sets;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaKmsImplSimple, meta_kms_impl_simple,
 | 
			
		||||
               META_TYPE_KMS_IMPL)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
flush_postponed_page_flip_datas (MetaKmsImplSimple *impl_simple);
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
generate_gamma_ramp_string (size_t          size,
 | 
			
		||||
                            unsigned short *red,
 | 
			
		||||
                            unsigned short *green,
 | 
			
		||||
                            unsigned short *blue)
 | 
			
		||||
{
 | 
			
		||||
  GString *string;
 | 
			
		||||
  int color;
 | 
			
		||||
 | 
			
		||||
  string = g_string_new ("[");
 | 
			
		||||
  for (color = 0; color < 3; color++)
 | 
			
		||||
    {
 | 
			
		||||
      unsigned short **color_ptr;
 | 
			
		||||
      char color_char;
 | 
			
		||||
      size_t i;
 | 
			
		||||
 | 
			
		||||
      switch (color)
 | 
			
		||||
        {
 | 
			
		||||
        case 0:
 | 
			
		||||
          color_ptr = &red;
 | 
			
		||||
          color_char = 'r';
 | 
			
		||||
          break;
 | 
			
		||||
        case 1:
 | 
			
		||||
          color_ptr = &green;
 | 
			
		||||
          color_char = 'g';
 | 
			
		||||
          break;
 | 
			
		||||
        case 2:
 | 
			
		||||
          color_ptr = &blue;
 | 
			
		||||
          color_char = 'b';
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      g_string_append_printf (string, " %c: ", color_char);
 | 
			
		||||
      for (i = 0; i < MIN (4, size); i++)
 | 
			
		||||
        {
 | 
			
		||||
          int j;
 | 
			
		||||
 | 
			
		||||
          if (size > 4)
 | 
			
		||||
            {
 | 
			
		||||
              if (i == 2)
 | 
			
		||||
                g_string_append (string, ",...");
 | 
			
		||||
 | 
			
		||||
              if (i >= 2)
 | 
			
		||||
                j = i + (size - 4);
 | 
			
		||||
              else
 | 
			
		||||
                j = i;
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              j = i;
 | 
			
		||||
            }
 | 
			
		||||
          g_string_append_printf (string, "%s%hu",
 | 
			
		||||
                                  j == 0 ? "" : ",",
 | 
			
		||||
                                  (*color_ptr)[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_string_append (string, " ]");
 | 
			
		||||
 | 
			
		||||
  return g_string_free (string, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsImplSimple *
 | 
			
		||||
meta_kms_impl_simple_new (MetaKms  *kms,
 | 
			
		||||
                          GError  **error)
 | 
			
		||||
{
 | 
			
		||||
  return g_object_new (META_TYPE_KMS_IMPL_SIMPLE,
 | 
			
		||||
                       "kms", kms,
 | 
			
		||||
                       NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
process_connector_property (MetaKmsImpl               *impl,
 | 
			
		||||
                            MetaKmsUpdate             *update,
 | 
			
		||||
                            MetaKmsConnectorProperty  *connector_property,
 | 
			
		||||
                            GError                   **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsConnector *connector = connector_property->connector;
 | 
			
		||||
  MetaKmsDevice *device = meta_kms_connector_get_device (connector);
 | 
			
		||||
  MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
 | 
			
		||||
  int fd;
 | 
			
		||||
  int ret;
 | 
			
		||||
 | 
			
		||||
  fd = meta_kms_impl_device_get_fd (impl_device);
 | 
			
		||||
 | 
			
		||||
  ret = drmModeObjectSetProperty (fd,
 | 
			
		||||
                                  meta_kms_connector_get_id (connector),
 | 
			
		||||
                                  DRM_MODE_OBJECT_CONNECTOR,
 | 
			
		||||
                                  connector_property->prop_id,
 | 
			
		||||
                                  connector_property->value);
 | 
			
		||||
  if (ret != 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
 | 
			
		||||
                   "Failed to set connector %u property %u: %s",
 | 
			
		||||
                   meta_kms_connector_get_id (connector),
 | 
			
		||||
                   connector_property->prop_id,
 | 
			
		||||
                   g_strerror (-ret));
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
process_crtc_gamma (MetaKmsImpl       *impl,
 | 
			
		||||
                    MetaKmsUpdate     *update,
 | 
			
		||||
                    MetaKmsCrtcGamma  *crtc_gamma,
 | 
			
		||||
                    GError           **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCrtc *crtc = crtc_gamma->crtc;
 | 
			
		||||
  MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
 | 
			
		||||
  MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
 | 
			
		||||
  g_autofree char *gamma_ramp_string = NULL;
 | 
			
		||||
  uint32_t crtc_id;
 | 
			
		||||
  int fd;
 | 
			
		||||
  int ret;
 | 
			
		||||
 | 
			
		||||
  fd = meta_kms_impl_device_get_fd (impl_device);
 | 
			
		||||
  crtc_id = meta_kms_crtc_get_id (crtc);
 | 
			
		||||
 | 
			
		||||
  gamma_ramp_string = generate_gamma_ramp_string (crtc_gamma->size,
 | 
			
		||||
                                                  crtc_gamma->red,
 | 
			
		||||
                                                  crtc_gamma->green,
 | 
			
		||||
                                                  crtc_gamma->blue);
 | 
			
		||||
  g_debug ("Setting CRTC (%u) gamma to %s", crtc_id, gamma_ramp_string);
 | 
			
		||||
 | 
			
		||||
  ret = drmModeCrtcSetGamma (fd,
 | 
			
		||||
                             crtc_id,
 | 
			
		||||
                             crtc_gamma->size,
 | 
			
		||||
                             crtc_gamma->red,
 | 
			
		||||
                             crtc_gamma->green,
 | 
			
		||||
                             crtc_gamma->blue);
 | 
			
		||||
  if (ret != 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to set CRTC (%u) Gamma: %s",
 | 
			
		||||
                 meta_kms_crtc_get_id (crtc),
 | 
			
		||||
                 g_strerror (-ret));
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
process_plane_property (MetaKmsImpl      *impl,
 | 
			
		||||
                        MetaKmsPlane     *plane,
 | 
			
		||||
                        MetaKmsProperty  *prop,
 | 
			
		||||
                        GError          **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsDevice *device = meta_kms_plane_get_device (plane);
 | 
			
		||||
  MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
 | 
			
		||||
  int fd;
 | 
			
		||||
  int ret;
 | 
			
		||||
 | 
			
		||||
  fd = meta_kms_impl_device_get_fd (impl_device);
 | 
			
		||||
 | 
			
		||||
  ret = drmModeObjectSetProperty (fd,
 | 
			
		||||
                                  meta_kms_plane_get_id (plane),
 | 
			
		||||
                                  DRM_MODE_OBJECT_PLANE,
 | 
			
		||||
                                  prop->prop_id,
 | 
			
		||||
                                  prop->value);
 | 
			
		||||
  if (ret != 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
 | 
			
		||||
                   "Failed to set plane %u property %u: %s",
 | 
			
		||||
                   meta_kms_plane_get_id (plane),
 | 
			
		||||
                   prop->prop_id,
 | 
			
		||||
                   g_strerror (-ret));
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaKmsPlaneAssignment *
 | 
			
		||||
get_primary_plane_assignment (MetaKmsImpl   *impl,
 | 
			
		||||
                              MetaKmsUpdate *update,
 | 
			
		||||
                              MetaKmsCrtc   *crtc)
 | 
			
		||||
{
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = meta_kms_update_get_plane_assignments (update); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsPlaneAssignment *plane_assignment = l->data;
 | 
			
		||||
 | 
			
		||||
      if (plane_assignment->crtc == crtc)
 | 
			
		||||
        return plane_assignment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static CachedModeSet *
 | 
			
		||||
cached_mode_set_new (GList                 *connectors,
 | 
			
		||||
                     const drmModeModeInfo *drm_mode)
 | 
			
		||||
{
 | 
			
		||||
  CachedModeSet *cached_mode_set;
 | 
			
		||||
 | 
			
		||||
  cached_mode_set = g_new0 (CachedModeSet, 1);
 | 
			
		||||
  *cached_mode_set = (CachedModeSet) {
 | 
			
		||||
    .connectors = g_list_copy (connectors),
 | 
			
		||||
    .drm_mode = g_memdup (drm_mode, sizeof *drm_mode),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return cached_mode_set;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
cached_mode_set_free (CachedModeSet *cached_mode_set)
 | 
			
		||||
{
 | 
			
		||||
  g_list_free (cached_mode_set->connectors);
 | 
			
		||||
  g_free (cached_mode_set->drm_mode);
 | 
			
		||||
  g_free (cached_mode_set);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
fill_connector_ids_array (GList     *connectors,
 | 
			
		||||
                          uint32_t **out_connectors,
 | 
			
		||||
                          int       *out_n_connectors)
 | 
			
		||||
{
 | 
			
		||||
  GList *l;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  *out_n_connectors = g_list_length (connectors);
 | 
			
		||||
  *out_connectors = g_new0 (uint32_t, *out_n_connectors);
 | 
			
		||||
  i = 0;
 | 
			
		||||
  for (l = connectors; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsConnector *connector = l->data;
 | 
			
		||||
 | 
			
		||||
      (*out_connectors)[i++] = meta_kms_connector_get_id (connector);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
process_mode_set (MetaKmsImpl     *impl,
 | 
			
		||||
                  MetaKmsUpdate   *update,
 | 
			
		||||
                  MetaKmsModeSet  *mode_set,
 | 
			
		||||
                  GError         **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl);
 | 
			
		||||
  MetaKmsCrtc *crtc = mode_set->crtc;;
 | 
			
		||||
  MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
 | 
			
		||||
  MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
 | 
			
		||||
  g_autofree uint32_t *connectors = NULL;
 | 
			
		||||
  int n_connectors;
 | 
			
		||||
  MetaKmsPlaneAssignment *plane_assignment;
 | 
			
		||||
  uint32_t x, y;
 | 
			
		||||
  uint32_t fb_id;
 | 
			
		||||
  int fd;
 | 
			
		||||
  int ret;
 | 
			
		||||
 | 
			
		||||
  crtc = mode_set->crtc;
 | 
			
		||||
 | 
			
		||||
  if (mode_set->drm_mode)
 | 
			
		||||
    {
 | 
			
		||||
      GList *l;
 | 
			
		||||
 | 
			
		||||
      fill_connector_ids_array (mode_set->connectors,
 | 
			
		||||
                                &connectors,
 | 
			
		||||
                                &n_connectors);
 | 
			
		||||
 | 
			
		||||
      plane_assignment = get_primary_plane_assignment (impl, update, crtc);
 | 
			
		||||
      if (!plane_assignment)
 | 
			
		||||
        {
 | 
			
		||||
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
 | 
			
		||||
                       "Missing primary plane assignment for legacy mode set on CRTC %u",
 | 
			
		||||
                       meta_kms_crtc_get_id (crtc));
 | 
			
		||||
          return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      x = meta_fixed_16_to_int (plane_assignment->src_rect.x);
 | 
			
		||||
      y = meta_fixed_16_to_int (plane_assignment->src_rect.y);
 | 
			
		||||
 | 
			
		||||
      for (l = plane_assignment->plane_properties; l; l = l->next)
 | 
			
		||||
        {
 | 
			
		||||
          MetaKmsProperty *prop = l->data;
 | 
			
		||||
 | 
			
		||||
          if (!process_plane_property (impl, plane_assignment->plane,
 | 
			
		||||
                                       prop, error))
 | 
			
		||||
            return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      fb_id = plane_assignment->fb_id;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      x = y = 0;
 | 
			
		||||
      n_connectors = 0;
 | 
			
		||||
      connectors = NULL;
 | 
			
		||||
      fb_id = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  fd = meta_kms_impl_device_get_fd (impl_device);
 | 
			
		||||
  ret = drmModeSetCrtc (fd,
 | 
			
		||||
                        meta_kms_crtc_get_id (crtc),
 | 
			
		||||
                        fb_id,
 | 
			
		||||
                        x, y,
 | 
			
		||||
                        connectors, n_connectors,
 | 
			
		||||
                        mode_set->drm_mode);
 | 
			
		||||
  if (ret != 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
 | 
			
		||||
                   "Failed to set mode on CRTC %u: %s",
 | 
			
		||||
                   meta_kms_crtc_get_id (crtc),
 | 
			
		||||
                   g_strerror (-ret));
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (mode_set->drm_mode)
 | 
			
		||||
    {
 | 
			
		||||
      g_hash_table_replace (impl_simple->cached_mode_sets,
 | 
			
		||||
                            crtc,
 | 
			
		||||
                            cached_mode_set_new (mode_set->connectors,
 | 
			
		||||
                                                 mode_set->drm_mode));
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      g_hash_table_remove (impl_simple->cached_mode_sets, crtc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
is_timestamp_earlier_than (uint64_t ts1,
 | 
			
		||||
                           uint64_t ts2)
 | 
			
		||||
{
 | 
			
		||||
  if (ts1 == ts2)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
  else
 | 
			
		||||
    return ts2 - ts1 < UINT64_MAX / 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct _RetryPageFlipData
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCrtc *crtc;
 | 
			
		||||
  uint32_t fb_id;
 | 
			
		||||
  MetaKmsPageFlipData *page_flip_data;
 | 
			
		||||
  float refresh_rate;
 | 
			
		||||
  uint64_t retry_time_us;
 | 
			
		||||
} RetryPageFlipData;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
retry_page_flip_data_free (RetryPageFlipData *retry_page_flip_data)
 | 
			
		||||
{
 | 
			
		||||
  g_assert (!retry_page_flip_data->page_flip_data);
 | 
			
		||||
  g_free (retry_page_flip_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float
 | 
			
		||||
get_cached_crtc_refresh_rate (MetaKmsImplSimple *impl_simple,
 | 
			
		||||
                              MetaKmsCrtc       *crtc)
 | 
			
		||||
{
 | 
			
		||||
  CachedModeSet *cached_mode_set;
 | 
			
		||||
 | 
			
		||||
  cached_mode_set = g_hash_table_lookup (impl_simple->cached_mode_sets,
 | 
			
		||||
                                         crtc);
 | 
			
		||||
  g_assert (cached_mode_set);
 | 
			
		||||
 | 
			
		||||
  return meta_calculate_drm_mode_refresh_rate (cached_mode_set->drm_mode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
retry_page_flips (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (user_data);
 | 
			
		||||
  uint64_t now_us;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (meta_kms_impl_get_kms (META_KMS_IMPL (impl_simple)));
 | 
			
		||||
 | 
			
		||||
  now_us = g_source_get_time (impl_simple->retry_page_flips_source);
 | 
			
		||||
 | 
			
		||||
  l = impl_simple->pending_page_flip_retries;
 | 
			
		||||
  while (l)
 | 
			
		||||
    {
 | 
			
		||||
      RetryPageFlipData *retry_page_flip_data = l->data;
 | 
			
		||||
      MetaKmsCrtc *crtc = retry_page_flip_data->crtc;
 | 
			
		||||
      MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
 | 
			
		||||
      MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
 | 
			
		||||
      GList *l_next = l->next;
 | 
			
		||||
      int fd;
 | 
			
		||||
      int ret;
 | 
			
		||||
      MetaKmsPageFlipData *page_flip_data;
 | 
			
		||||
 | 
			
		||||
      if (is_timestamp_earlier_than (now_us,
 | 
			
		||||
                                     retry_page_flip_data->retry_time_us))
 | 
			
		||||
        {
 | 
			
		||||
          l = l_next;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      fd = meta_kms_impl_device_get_fd (impl_device);
 | 
			
		||||
      ret = drmModePageFlip (fd,
 | 
			
		||||
                             meta_kms_crtc_get_id (crtc),
 | 
			
		||||
                             retry_page_flip_data->fb_id,
 | 
			
		||||
                             DRM_MODE_PAGE_FLIP_EVENT,
 | 
			
		||||
                             retry_page_flip_data->page_flip_data);
 | 
			
		||||
      if (ret == -EBUSY)
 | 
			
		||||
        {
 | 
			
		||||
          float refresh_rate;
 | 
			
		||||
 | 
			
		||||
          refresh_rate = get_cached_crtc_refresh_rate (impl_simple, crtc);
 | 
			
		||||
          retry_page_flip_data->retry_time_us +=
 | 
			
		||||
            (uint64_t) (G_USEC_PER_SEC / refresh_rate);
 | 
			
		||||
          l = l_next;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      impl_simple->pending_page_flip_retries =
 | 
			
		||||
        g_list_remove_link (impl_simple->pending_page_flip_retries, l);
 | 
			
		||||
 | 
			
		||||
      page_flip_data = g_steal_pointer (&retry_page_flip_data->page_flip_data);
 | 
			
		||||
      if (ret != 0)
 | 
			
		||||
        {
 | 
			
		||||
          g_autoptr (GError) error = NULL;
 | 
			
		||||
 | 
			
		||||
          g_set_error (&error, G_IO_ERROR, g_io_error_from_errno (-ret),
 | 
			
		||||
                       "drmModePageFlip on CRTC %u failed: %s",
 | 
			
		||||
                       meta_kms_crtc_get_id (crtc),
 | 
			
		||||
                       g_strerror (-ret));
 | 
			
		||||
          if (!g_error_matches (error,
 | 
			
		||||
                                G_IO_ERROR,
 | 
			
		||||
                                G_IO_ERROR_PERMISSION_DENIED))
 | 
			
		||||
            g_critical ("Failed to page flip: %s", error->message);
 | 
			
		||||
 | 
			
		||||
          meta_kms_page_flip_data_discard_in_impl (page_flip_data, error);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      retry_page_flip_data_free (retry_page_flip_data);
 | 
			
		||||
 | 
			
		||||
      l = l_next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (impl_simple->pending_page_flip_retries)
 | 
			
		||||
    {
 | 
			
		||||
      GList *l;
 | 
			
		||||
      uint64_t earliest_retry_time_us = 0;
 | 
			
		||||
 | 
			
		||||
      for (l = impl_simple->pending_page_flip_retries; l; l = l->next)
 | 
			
		||||
        {
 | 
			
		||||
          RetryPageFlipData *retry_page_flip_data = l->data;
 | 
			
		||||
 | 
			
		||||
          if (l == impl_simple->pending_page_flip_retries ||
 | 
			
		||||
              is_timestamp_earlier_than (retry_page_flip_data->retry_time_us,
 | 
			
		||||
                                         earliest_retry_time_us))
 | 
			
		||||
            earliest_retry_time_us = retry_page_flip_data->retry_time_us;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      g_source_set_ready_time (impl_simple->retry_page_flips_source,
 | 
			
		||||
                               earliest_retry_time_us);
 | 
			
		||||
      return G_SOURCE_CONTINUE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      g_clear_pointer (&impl_simple->retry_page_flips_source,
 | 
			
		||||
                       g_source_unref);
 | 
			
		||||
 | 
			
		||||
      flush_postponed_page_flip_datas (impl_simple);
 | 
			
		||||
 | 
			
		||||
      return G_SOURCE_REMOVE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
schedule_retry_page_flip (MetaKmsImplSimple   *impl_simple,
 | 
			
		||||
                          MetaKmsCrtc         *crtc,
 | 
			
		||||
                          uint32_t             fb_id,
 | 
			
		||||
                          float                refresh_rate,
 | 
			
		||||
                          MetaKmsPageFlipData *page_flip_data)
 | 
			
		||||
{
 | 
			
		||||
  RetryPageFlipData *retry_page_flip_data;
 | 
			
		||||
  uint64_t now_us;
 | 
			
		||||
  uint64_t retry_time_us;
 | 
			
		||||
 | 
			
		||||
  now_us = g_get_monotonic_time ();
 | 
			
		||||
  retry_time_us = now_us + (uint64_t) (G_USEC_PER_SEC / refresh_rate);
 | 
			
		||||
 | 
			
		||||
  retry_page_flip_data = g_new0 (RetryPageFlipData, 1);
 | 
			
		||||
  *retry_page_flip_data = (RetryPageFlipData) {
 | 
			
		||||
    .crtc = crtc,
 | 
			
		||||
    .fb_id = fb_id,
 | 
			
		||||
    .page_flip_data = meta_kms_page_flip_data_ref (page_flip_data),
 | 
			
		||||
    .refresh_rate = refresh_rate,
 | 
			
		||||
    .retry_time_us = retry_time_us,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (!impl_simple->retry_page_flips_source)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKms *kms = meta_kms_impl_get_kms (META_KMS_IMPL (impl_simple));
 | 
			
		||||
      GSource *source;
 | 
			
		||||
 | 
			
		||||
      source = meta_kms_add_source_in_impl (kms, retry_page_flips,
 | 
			
		||||
                                            impl_simple, NULL);
 | 
			
		||||
      g_source_set_ready_time (source, retry_time_us);
 | 
			
		||||
 | 
			
		||||
      impl_simple->retry_page_flips_source = source;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      GList *l;
 | 
			
		||||
 | 
			
		||||
      for (l = impl_simple->pending_page_flip_retries; l; l = l->next)
 | 
			
		||||
        {
 | 
			
		||||
          RetryPageFlipData *pending_retry_page_flip_data = l->data;
 | 
			
		||||
          uint64_t pending_retry_time_us =
 | 
			
		||||
            pending_retry_page_flip_data->retry_time_us;
 | 
			
		||||
 | 
			
		||||
          if (is_timestamp_earlier_than (retry_time_us, pending_retry_time_us))
 | 
			
		||||
            {
 | 
			
		||||
              g_source_set_ready_time (impl_simple->retry_page_flips_source,
 | 
			
		||||
                                       retry_time_us);
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  impl_simple->pending_page_flip_retries =
 | 
			
		||||
    g_list_append (impl_simple->pending_page_flip_retries,
 | 
			
		||||
                   retry_page_flip_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
invoke_page_flip_datas (GList                        *page_flip_datas,
 | 
			
		||||
                        MetaPageFlipDataFeedbackFunc  func)
 | 
			
		||||
{
 | 
			
		||||
  g_list_foreach (page_flip_datas, (GFunc) func, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
clear_page_flip_datas (GList **page_flip_datas)
 | 
			
		||||
{
 | 
			
		||||
  g_list_free_full (*page_flip_datas,
 | 
			
		||||
                    (GDestroyNotify) meta_kms_page_flip_data_unref);
 | 
			
		||||
  *page_flip_datas = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
mode_set_fallback_feedback_idle (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplSimple *impl_simple = user_data;
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&impl_simple->mode_set_fallback_feedback_source,
 | 
			
		||||
                   g_source_unref);
 | 
			
		||||
 | 
			
		||||
  if (!impl_simple->pending_page_flip_retries)
 | 
			
		||||
    {
 | 
			
		||||
      impl_simple->postponed_mode_set_fallback_datas =
 | 
			
		||||
        g_steal_pointer (&impl_simple->mode_set_fallback_page_flip_datas);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      invoke_page_flip_datas (impl_simple->mode_set_fallback_page_flip_datas,
 | 
			
		||||
                              meta_kms_page_flip_data_mode_set_fallback_in_impl);
 | 
			
		||||
      clear_page_flip_datas (&impl_simple->mode_set_fallback_page_flip_datas);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
mode_set_fallback (MetaKmsImplSimple       *impl_simple,
 | 
			
		||||
                   MetaKmsUpdate           *update,
 | 
			
		||||
                   MetaKmsPageFlip         *page_flip,
 | 
			
		||||
                   MetaKmsPlaneAssignment  *plane_assignment,
 | 
			
		||||
                   MetaKmsPageFlipData     *page_flip_data,
 | 
			
		||||
                   GError                 **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKms *kms = meta_kms_impl_get_kms (META_KMS_IMPL (impl_simple));
 | 
			
		||||
  MetaKmsCrtc *crtc = page_flip->crtc;
 | 
			
		||||
  MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
 | 
			
		||||
  MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
 | 
			
		||||
  CachedModeSet *cached_mode_set;
 | 
			
		||||
  g_autofree uint32_t *connectors = NULL;
 | 
			
		||||
  int n_connectors;
 | 
			
		||||
  uint32_t x, y;
 | 
			
		||||
  int fd;
 | 
			
		||||
  int ret;
 | 
			
		||||
 | 
			
		||||
  cached_mode_set = g_hash_table_lookup (impl_simple->cached_mode_sets,
 | 
			
		||||
                                         crtc);
 | 
			
		||||
  g_assert (cached_mode_set);
 | 
			
		||||
 | 
			
		||||
  fill_connector_ids_array (cached_mode_set->connectors,
 | 
			
		||||
                            &connectors,
 | 
			
		||||
                            &n_connectors);
 | 
			
		||||
 | 
			
		||||
  x = meta_fixed_16_to_int (plane_assignment->src_rect.x);
 | 
			
		||||
  y = meta_fixed_16_to_int (plane_assignment->src_rect.y);
 | 
			
		||||
 | 
			
		||||
  fd = meta_kms_impl_device_get_fd (impl_device);
 | 
			
		||||
  ret = drmModeSetCrtc (fd,
 | 
			
		||||
                        meta_kms_crtc_get_id (crtc),
 | 
			
		||||
                        plane_assignment->fb_id,
 | 
			
		||||
                        x, y,
 | 
			
		||||
                        connectors, n_connectors,
 | 
			
		||||
                        cached_mode_set->drm_mode);
 | 
			
		||||
  if (ret != 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
 | 
			
		||||
                   "drmModeSetCrtc mode '%s' on CRTC %u failed: %s",
 | 
			
		||||
                   cached_mode_set->drm_mode->name,
 | 
			
		||||
                   meta_kms_crtc_get_id (crtc),
 | 
			
		||||
                   g_strerror (-ret));
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!impl_simple->mode_set_fallback_feedback_source)
 | 
			
		||||
    {
 | 
			
		||||
      GSource *source;
 | 
			
		||||
 | 
			
		||||
      source = meta_kms_add_source_in_impl (kms,
 | 
			
		||||
                                            mode_set_fallback_feedback_idle,
 | 
			
		||||
                                            impl_simple,
 | 
			
		||||
                                            NULL);
 | 
			
		||||
      impl_simple->mode_set_fallback_feedback_source = source;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  impl_simple->mode_set_fallback_page_flip_datas =
 | 
			
		||||
    g_list_prepend (impl_simple->mode_set_fallback_page_flip_datas,
 | 
			
		||||
                    meta_kms_page_flip_data_ref (page_flip_data));
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
process_page_flip (MetaKmsImpl      *impl,
 | 
			
		||||
                   MetaKmsUpdate    *update,
 | 
			
		||||
                   MetaKmsPageFlip  *page_flip,
 | 
			
		||||
                   GError          **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl);
 | 
			
		||||
  MetaKmsCrtc *crtc;
 | 
			
		||||
  MetaKmsDevice *device;
 | 
			
		||||
  MetaKmsImplDevice *impl_device;
 | 
			
		||||
  MetaKmsPlaneAssignment *plane_assignment;
 | 
			
		||||
  MetaKmsPageFlipData *page_flip_data;
 | 
			
		||||
  MetaKmsCustomPageFlipFunc custom_page_flip_func;
 | 
			
		||||
  int fd;
 | 
			
		||||
  int ret;
 | 
			
		||||
 | 
			
		||||
  crtc = page_flip->crtc;
 | 
			
		||||
  plane_assignment = get_primary_plane_assignment (impl, update, crtc);
 | 
			
		||||
 | 
			
		||||
  page_flip_data = meta_kms_page_flip_data_new (impl,
 | 
			
		||||
                                                crtc,
 | 
			
		||||
                                                page_flip->feedback,
 | 
			
		||||
                                                page_flip->user_data);
 | 
			
		||||
 | 
			
		||||
  device = meta_kms_crtc_get_device (crtc);
 | 
			
		||||
  impl_device = meta_kms_device_get_impl_device (device);
 | 
			
		||||
  fd = meta_kms_impl_device_get_fd (impl_device);
 | 
			
		||||
  custom_page_flip_func = page_flip->custom_page_flip_func;
 | 
			
		||||
  if (custom_page_flip_func)
 | 
			
		||||
    {
 | 
			
		||||
      ret = custom_page_flip_func (page_flip->custom_page_flip_user_data,
 | 
			
		||||
                                   meta_kms_page_flip_data_ref (page_flip_data));
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      ret = drmModePageFlip (fd,
 | 
			
		||||
                             meta_kms_crtc_get_id (crtc),
 | 
			
		||||
                             plane_assignment->fb_id,
 | 
			
		||||
                             DRM_MODE_PAGE_FLIP_EVENT,
 | 
			
		||||
                             meta_kms_page_flip_data_ref (page_flip_data));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (ret == -EBUSY)
 | 
			
		||||
    {
 | 
			
		||||
      float refresh_rate;
 | 
			
		||||
 | 
			
		||||
      refresh_rate = get_cached_crtc_refresh_rate (impl_simple, crtc);
 | 
			
		||||
      schedule_retry_page_flip (impl_simple,
 | 
			
		||||
                                crtc,
 | 
			
		||||
                                plane_assignment->fb_id,
 | 
			
		||||
                                refresh_rate,
 | 
			
		||||
                                page_flip_data);
 | 
			
		||||
    }
 | 
			
		||||
  else if (ret == -EINVAL)
 | 
			
		||||
    {
 | 
			
		||||
      if (!mode_set_fallback (impl_simple,
 | 
			
		||||
                              update,
 | 
			
		||||
                              page_flip,
 | 
			
		||||
                              plane_assignment,
 | 
			
		||||
                              page_flip_data,
 | 
			
		||||
                              error))
 | 
			
		||||
        {
 | 
			
		||||
          meta_kms_page_flip_data_unref (page_flip_data);
 | 
			
		||||
          return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else if (ret != 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
 | 
			
		||||
                   "drmModePageFlip on CRTC %u failed: %s",
 | 
			
		||||
                   meta_kms_crtc_get_id (crtc),
 | 
			
		||||
                   g_strerror (-ret));
 | 
			
		||||
      meta_kms_page_flip_data_unref (page_flip_data);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_kms_page_flip_data_unref (page_flip_data);
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
discard_page_flip (MetaKmsImpl     *impl,
 | 
			
		||||
                   MetaKmsUpdate   *update,
 | 
			
		||||
                   MetaKmsPageFlip *page_flip)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCrtc *crtc;
 | 
			
		||||
  MetaKmsPageFlipData *page_flip_data;
 | 
			
		||||
 | 
			
		||||
  crtc = page_flip->crtc;
 | 
			
		||||
  page_flip_data = meta_kms_page_flip_data_new (impl,
 | 
			
		||||
                                                crtc,
 | 
			
		||||
                                                page_flip->feedback,
 | 
			
		||||
                                                page_flip->user_data);
 | 
			
		||||
  meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL);
 | 
			
		||||
  meta_kms_page_flip_data_unref (page_flip_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_kms_impl_simple_process_update (MetaKmsImpl    *impl,
 | 
			
		||||
                                     MetaKmsUpdate  *update,
 | 
			
		||||
                                     GError        **error)
 | 
			
		||||
{
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl));
 | 
			
		||||
 | 
			
		||||
  for (l = meta_kms_update_get_connector_properties (update); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsConnectorProperty *connector_property = l->data;
 | 
			
		||||
 | 
			
		||||
      if (!process_connector_property (impl, update, connector_property, error))
 | 
			
		||||
        goto discard_page_flips;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (l = meta_kms_update_get_crtc_gammas (update); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsCrtcGamma *crtc_gamma = l->data;
 | 
			
		||||
 | 
			
		||||
      if (!process_crtc_gamma (impl, update, crtc_gamma, error))
 | 
			
		||||
        goto discard_page_flips;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (l = meta_kms_update_get_mode_sets (update); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsModeSet *mode_set = l->data;
 | 
			
		||||
 | 
			
		||||
      if (!process_mode_set (impl, update, mode_set, error))
 | 
			
		||||
        goto discard_page_flips;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (l = meta_kms_update_get_page_flips (update); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsPageFlip *page_flip = l->data;
 | 
			
		||||
 | 
			
		||||
      if (!process_page_flip (impl, update, page_flip, error))
 | 
			
		||||
        goto discard_page_flips;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
 | 
			
		||||
discard_page_flips:
 | 
			
		||||
  for (l = meta_kms_update_get_page_flips (update); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsPageFlip *page_flip = l->data;
 | 
			
		||||
 | 
			
		||||
      discard_page_flip (impl, update, page_flip);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
flush_postponed_page_flip_datas (MetaKmsImplSimple *impl_simple)
 | 
			
		||||
{
 | 
			
		||||
  invoke_page_flip_datas (impl_simple->postponed_page_flip_datas,
 | 
			
		||||
                          meta_kms_page_flip_data_flipped_in_impl);
 | 
			
		||||
  clear_page_flip_datas (&impl_simple->postponed_page_flip_datas);
 | 
			
		||||
 | 
			
		||||
  invoke_page_flip_datas (impl_simple->postponed_mode_set_fallback_datas,
 | 
			
		||||
                          meta_kms_page_flip_data_mode_set_fallback_in_impl);
 | 
			
		||||
  clear_page_flip_datas (&impl_simple->postponed_mode_set_fallback_datas);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_simple_handle_page_flip_callback (MetaKmsImpl         *impl,
 | 
			
		||||
                                                MetaKmsPageFlipData *page_flip_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl);
 | 
			
		||||
 | 
			
		||||
  if (impl_simple->pending_page_flip_retries)
 | 
			
		||||
    {
 | 
			
		||||
      impl_simple->postponed_page_flip_datas =
 | 
			
		||||
        g_list_append (impl_simple->postponed_page_flip_datas,
 | 
			
		||||
                       page_flip_data);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      meta_kms_page_flip_data_flipped_in_impl (page_flip_data);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_simple_discard_pending_page_flips (MetaKmsImpl *impl)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl);
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  if (!impl_simple->pending_page_flip_retries)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  for (l = impl_simple->pending_page_flip_retries; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      RetryPageFlipData *retry_page_flip_data = l->data;
 | 
			
		||||
      MetaKmsPageFlipData *page_flip_data;
 | 
			
		||||
 | 
			
		||||
      page_flip_data = g_steal_pointer (&retry_page_flip_data->page_flip_data);
 | 
			
		||||
      meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL);
 | 
			
		||||
      retry_page_flip_data_free (retry_page_flip_data);
 | 
			
		||||
    }
 | 
			
		||||
  g_clear_pointer (&impl_simple->pending_page_flip_retries, g_list_free);
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&impl_simple->retry_page_flips_source,
 | 
			
		||||
                   g_source_destroy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_simple_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (object);
 | 
			
		||||
 | 
			
		||||
  g_list_free_full (impl_simple->pending_page_flip_retries,
 | 
			
		||||
                    (GDestroyNotify) retry_page_flip_data_free);
 | 
			
		||||
  g_list_free_full (impl_simple->postponed_page_flip_datas,
 | 
			
		||||
                    (GDestroyNotify) meta_kms_page_flip_data_unref);
 | 
			
		||||
  g_list_free_full (impl_simple->postponed_mode_set_fallback_datas,
 | 
			
		||||
                    (GDestroyNotify) meta_kms_page_flip_data_unref);
 | 
			
		||||
  g_clear_pointer (&impl_simple->mode_set_fallback_feedback_source,
 | 
			
		||||
                   g_source_destroy);
 | 
			
		||||
  g_hash_table_destroy (impl_simple->cached_mode_sets);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_kms_impl_simple_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_simple_init (MetaKmsImplSimple *impl_simple)
 | 
			
		||||
{
 | 
			
		||||
  impl_simple->cached_mode_sets =
 | 
			
		||||
    g_hash_table_new_full (NULL,
 | 
			
		||||
                           NULL,
 | 
			
		||||
                           NULL,
 | 
			
		||||
                           (GDestroyNotify) cached_mode_set_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_simple_class_init (MetaKmsImplSimpleClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
  MetaKmsImplClass *impl_class = META_KMS_IMPL_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_kms_impl_simple_finalize;
 | 
			
		||||
 | 
			
		||||
  impl_class->process_update = meta_kms_impl_simple_process_update;
 | 
			
		||||
  impl_class->handle_page_flip_callback = meta_kms_impl_simple_handle_page_flip_callback;
 | 
			
		||||
  impl_class->discard_pending_page_flips = meta_kms_impl_simple_discard_pending_page_flips;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								src/backends/native/meta-kms-impl-simple.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/backends/native/meta-kms-impl-simple.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 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_KMS_IMPL_SIMPLE_H
 | 
			
		||||
#define META_KMS_IMPL_SIMPLE_H
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-impl.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_KMS_IMPL_SIMPLE meta_kms_impl_simple_get_type ()
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaKmsImplSimple, meta_kms_impl_simple,
 | 
			
		||||
                      META, KMS_IMPL_SIMPLE, MetaKmsImpl)
 | 
			
		||||
 | 
			
		||||
MetaKmsImplSimple * meta_kms_impl_simple_new (MetaKms  *kms,
 | 
			
		||||
                                              GError  **error);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_IMPL_SIMPLE_H */
 | 
			
		||||
							
								
								
									
										132
									
								
								src/backends/native/meta-kms-impl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								src/backends/native/meta-kms-impl.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 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-kms-impl.h"
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  PROP_0,
 | 
			
		||||
 | 
			
		||||
  PROP_KMS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsImplPrivate
 | 
			
		||||
{
 | 
			
		||||
  MetaKms *kms;
 | 
			
		||||
} MetaKmsImplPrivate;
 | 
			
		||||
 | 
			
		||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaKmsImpl, meta_kms_impl, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
MetaKms *
 | 
			
		||||
meta_kms_impl_get_kms (MetaKmsImpl *impl)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImplPrivate *priv = meta_kms_impl_get_instance_private (impl);
 | 
			
		||||
 | 
			
		||||
  return priv->kms;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_kms_impl_process_update (MetaKmsImpl    *impl,
 | 
			
		||||
                              MetaKmsUpdate  *update,
 | 
			
		||||
                              GError        **error)
 | 
			
		||||
{
 | 
			
		||||
  return META_KMS_IMPL_GET_CLASS (impl)->process_update (impl, update, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_impl_handle_page_flip_callback (MetaKmsImpl         *impl,
 | 
			
		||||
                                         MetaKmsPageFlipData *page_flip_data)
 | 
			
		||||
{
 | 
			
		||||
  META_KMS_IMPL_GET_CLASS (impl)->handle_page_flip_callback (impl,
 | 
			
		||||
                                                             page_flip_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl)
 | 
			
		||||
{
 | 
			
		||||
  META_KMS_IMPL_GET_CLASS (impl)->discard_pending_page_flips (impl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_set_property (GObject      *object,
 | 
			
		||||
                            guint         prop_id,
 | 
			
		||||
                            const GValue *value,
 | 
			
		||||
                            GParamSpec   *pspec)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImpl *impl = META_KMS_IMPL (object);
 | 
			
		||||
  MetaKmsImplPrivate *priv = meta_kms_impl_get_instance_private (impl);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_KMS:
 | 
			
		||||
      priv->kms = g_value_get_object (value);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_get_property (GObject    *object,
 | 
			
		||||
                            guint       prop_id,
 | 
			
		||||
                            GValue     *value,
 | 
			
		||||
                            GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsImpl *impl = META_KMS_IMPL (object);
 | 
			
		||||
  MetaKmsImplPrivate *priv = meta_kms_impl_get_instance_private (impl);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_KMS:
 | 
			
		||||
      g_value_set_object (value, priv->kms);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_init (MetaKmsImpl *kms_impl)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_impl_class_init (MetaKmsImplClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
  GParamSpec *pspec;
 | 
			
		||||
 | 
			
		||||
  object_class->set_property = meta_kms_impl_set_property;
 | 
			
		||||
  object_class->get_property = meta_kms_impl_get_property;
 | 
			
		||||
 | 
			
		||||
  pspec = g_param_spec_object ("kms",
 | 
			
		||||
                               "kms",
 | 
			
		||||
                               "MetaKms",
 | 
			
		||||
                               META_TYPE_KMS,
 | 
			
		||||
                               G_PARAM_READWRITE |
 | 
			
		||||
                               G_PARAM_STATIC_STRINGS |
 | 
			
		||||
                               G_PARAM_CONSTRUCT_ONLY);
 | 
			
		||||
  g_object_class_install_property (object_class,
 | 
			
		||||
                                   PROP_KMS,
 | 
			
		||||
                                   pspec);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								src/backends/native/meta-kms-impl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/backends/native/meta-kms-impl.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 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_KMS_IMPL_H
 | 
			
		||||
#define META_KMS_IMPL_H
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-impl-device.h"
 | 
			
		||||
#include "backends/native/meta-kms-page-flip-private.h"
 | 
			
		||||
#include "backends/native/meta-kms.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_KMS_IMPL (meta_kms_impl_get_type ())
 | 
			
		||||
G_DECLARE_DERIVABLE_TYPE (MetaKmsImpl, meta_kms_impl,
 | 
			
		||||
                          META, KMS_IMPL, GObject)
 | 
			
		||||
 | 
			
		||||
struct _MetaKmsImplClass
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass parent_class;
 | 
			
		||||
 | 
			
		||||
  gboolean (* process_update) (MetaKmsImpl    *impl,
 | 
			
		||||
                               MetaKmsUpdate  *update,
 | 
			
		||||
                               GError        **error);
 | 
			
		||||
  void (* handle_page_flip_callback) (MetaKmsImpl         *impl,
 | 
			
		||||
                                      MetaKmsPageFlipData *page_flip_data);
 | 
			
		||||
  void (* discard_pending_page_flips) (MetaKmsImpl *impl);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MetaKms * meta_kms_impl_get_kms (MetaKmsImpl *impl);
 | 
			
		||||
 | 
			
		||||
gboolean meta_kms_impl_process_update (MetaKmsImpl    *impl,
 | 
			
		||||
                                       MetaKmsUpdate  *update,
 | 
			
		||||
                                       GError        **error);
 | 
			
		||||
 | 
			
		||||
void meta_kms_impl_handle_page_flip_callback (MetaKmsImpl         *impl,
 | 
			
		||||
                                              MetaKmsPageFlipData *page_flip_data);
 | 
			
		||||
 | 
			
		||||
void meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_IMPL_H */
 | 
			
		||||
							
								
								
									
										57
									
								
								src/backends/native/meta-kms-page-flip-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/backends/native/meta-kms-page-flip-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_PAGE_FLIP_H
 | 
			
		||||
#define META_KMS_PAGE_FLIP_H
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsPageFlipData MetaKmsPageFlipData;
 | 
			
		||||
 | 
			
		||||
typedef void (* MetaPageFlipDataFeedbackFunc) (MetaKmsPageFlipData *page_flip_data);
 | 
			
		||||
 | 
			
		||||
MetaKmsPageFlipData * meta_kms_page_flip_data_new (MetaKmsImpl                   *impl,
 | 
			
		||||
                                                   MetaKmsCrtc                   *crtc,
 | 
			
		||||
                                                   const MetaKmsPageFlipFeedback *feedback,
 | 
			
		||||
                                                   gpointer                       user_data);
 | 
			
		||||
 | 
			
		||||
MetaKmsPageFlipData * meta_kms_page_flip_data_ref (MetaKmsPageFlipData *page_flip_data);
 | 
			
		||||
 | 
			
		||||
void meta_kms_page_flip_data_unref (MetaKmsPageFlipData *page_flip_data);
 | 
			
		||||
 | 
			
		||||
MetaKmsImpl * meta_kms_page_flip_data_get_kms_impl (MetaKmsPageFlipData *page_flip_data);
 | 
			
		||||
 | 
			
		||||
void meta_kms_page_flip_data_set_timings_in_impl (MetaKmsPageFlipData *page_flip_data,
 | 
			
		||||
                                                  unsigned int         sequence,
 | 
			
		||||
                                                  unsigned int         sec,
 | 
			
		||||
                                                  unsigned int         usec);
 | 
			
		||||
 | 
			
		||||
void meta_kms_page_flip_data_flipped_in_impl (MetaKmsPageFlipData *page_flip_data);
 | 
			
		||||
 | 
			
		||||
void meta_kms_page_flip_data_mode_set_fallback_in_impl (MetaKmsPageFlipData *page_flip_data);
 | 
			
		||||
 | 
			
		||||
void meta_kms_page_flip_data_discard_in_impl (MetaKmsPageFlipData *page_flip_data,
 | 
			
		||||
                                              const GError        *error);
 | 
			
		||||
 | 
			
		||||
void meta_kms_page_flip_data_take_error (MetaKmsPageFlipData *page_flip_data,
 | 
			
		||||
                                         GError              *error);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_PAGE_FLIP_H */
 | 
			
		||||
							
								
								
									
										196
									
								
								src/backends/native/meta-kms-page-flip.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								src/backends/native/meta-kms-page-flip.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,196 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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-kms-page-flip-private.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-impl.h"
 | 
			
		||||
#include "backends/native/meta-kms-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-update.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaKmsPageFlipData
 | 
			
		||||
{
 | 
			
		||||
  int ref_count;
 | 
			
		||||
 | 
			
		||||
  MetaKmsImpl *impl;
 | 
			
		||||
  MetaKmsCrtc *crtc;
 | 
			
		||||
 | 
			
		||||
  const MetaKmsPageFlipFeedback *feedback;
 | 
			
		||||
  gpointer user_data;
 | 
			
		||||
 | 
			
		||||
  unsigned int sequence;
 | 
			
		||||
  unsigned int sec;
 | 
			
		||||
  unsigned int usec;
 | 
			
		||||
 | 
			
		||||
  GError *error;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MetaKmsPageFlipData *
 | 
			
		||||
meta_kms_page_flip_data_new (MetaKmsImpl                   *impl,
 | 
			
		||||
                             MetaKmsCrtc                   *crtc,
 | 
			
		||||
                             const MetaKmsPageFlipFeedback *feedback,
 | 
			
		||||
                             gpointer                       user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsPageFlipData *page_flip_data;
 | 
			
		||||
 | 
			
		||||
  page_flip_data = g_new0 (MetaKmsPageFlipData , 1);
 | 
			
		||||
  *page_flip_data = (MetaKmsPageFlipData) {
 | 
			
		||||
    .ref_count = 1,
 | 
			
		||||
    .impl = impl,
 | 
			
		||||
    .crtc = crtc,
 | 
			
		||||
    .feedback = feedback,
 | 
			
		||||
    .user_data = user_data,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return page_flip_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsPageFlipData *
 | 
			
		||||
meta_kms_page_flip_data_ref (MetaKmsPageFlipData *page_flip_data)
 | 
			
		||||
{
 | 
			
		||||
  page_flip_data->ref_count++;
 | 
			
		||||
 | 
			
		||||
  return page_flip_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_page_flip_data_unref (MetaKmsPageFlipData *page_flip_data)
 | 
			
		||||
{
 | 
			
		||||
  page_flip_data->ref_count--;
 | 
			
		||||
 | 
			
		||||
  if (page_flip_data->ref_count == 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_clear_error (&page_flip_data->error);
 | 
			
		||||
      g_free (page_flip_data);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsImpl *
 | 
			
		||||
meta_kms_page_flip_data_get_kms_impl (MetaKmsPageFlipData *page_flip_data)
 | 
			
		||||
{
 | 
			
		||||
  return page_flip_data->impl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_page_flip_data_flipped (MetaKms  *kms,
 | 
			
		||||
                                 gpointer  user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsPageFlipData *page_flip_data = user_data;
 | 
			
		||||
 | 
			
		||||
  meta_assert_not_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  page_flip_data->feedback->flipped (page_flip_data->crtc,
 | 
			
		||||
                                     page_flip_data->sequence,
 | 
			
		||||
                                     page_flip_data->sec,
 | 
			
		||||
                                     page_flip_data->usec,
 | 
			
		||||
                                     page_flip_data->user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_page_flip_data_set_timings_in_impl (MetaKmsPageFlipData *page_flip_data,
 | 
			
		||||
                                             unsigned int         sequence,
 | 
			
		||||
                                             unsigned int         sec,
 | 
			
		||||
                                             unsigned int         usec)
 | 
			
		||||
{
 | 
			
		||||
  MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  page_flip_data->sequence = sequence;
 | 
			
		||||
  page_flip_data->sec = sec;
 | 
			
		||||
  page_flip_data->usec = usec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_page_flip_data_flipped_in_impl (MetaKmsPageFlipData *page_flip_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  meta_kms_queue_callback (kms,
 | 
			
		||||
                           meta_kms_page_flip_data_flipped,
 | 
			
		||||
                           meta_kms_page_flip_data_ref (page_flip_data),
 | 
			
		||||
                           (GDestroyNotify) meta_kms_page_flip_data_unref);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_page_flip_data_mode_set_fallback (MetaKms  *kms,
 | 
			
		||||
                                           gpointer  user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsPageFlipData *page_flip_data = user_data;
 | 
			
		||||
 | 
			
		||||
  meta_assert_not_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  page_flip_data->feedback->mode_set_fallback (page_flip_data->crtc,
 | 
			
		||||
                                               page_flip_data->user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_page_flip_data_mode_set_fallback_in_impl (MetaKmsPageFlipData *page_flip_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  meta_kms_queue_callback (kms,
 | 
			
		||||
                           meta_kms_page_flip_data_mode_set_fallback,
 | 
			
		||||
                           meta_kms_page_flip_data_ref (page_flip_data),
 | 
			
		||||
                           (GDestroyNotify) meta_kms_page_flip_data_unref);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_page_flip_data_discard (MetaKms  *kms,
 | 
			
		||||
                                 gpointer  user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsPageFlipData *page_flip_data = user_data;
 | 
			
		||||
 | 
			
		||||
  meta_assert_not_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  page_flip_data->feedback->discarded (page_flip_data->crtc,
 | 
			
		||||
                                       page_flip_data->user_data,
 | 
			
		||||
                                       page_flip_data->error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_page_flip_data_take_error (MetaKmsPageFlipData *page_flip_data,
 | 
			
		||||
                                    GError              *error)
 | 
			
		||||
{
 | 
			
		||||
  g_assert (!page_flip_data->error);
 | 
			
		||||
 | 
			
		||||
  page_flip_data->error = error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_page_flip_data_discard_in_impl (MetaKmsPageFlipData *page_flip_data,
 | 
			
		||||
                                         const GError        *error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  if (error)
 | 
			
		||||
    meta_kms_page_flip_data_take_error (page_flip_data, g_error_copy (error));
 | 
			
		||||
 | 
			
		||||
  meta_kms_queue_callback (kms,
 | 
			
		||||
                           meta_kms_page_flip_data_discard,
 | 
			
		||||
                           meta_kms_page_flip_data_ref (page_flip_data),
 | 
			
		||||
                           (GDestroyNotify) meta_kms_page_flip_data_unref);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										363
									
								
								src/backends/native/meta-kms-plane.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								src/backends/native/meta-kms-plane.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,363 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2013-2019 Red Hat
 | 
			
		||||
 * Copyright (C) 2018 DisplayLink (UK) Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * 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-kms-plane.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-monitor-transform.h"
 | 
			
		||||
#include "backends/native/meta-kms-crtc.h"
 | 
			
		||||
#include "backends/native/meta-kms-impl-device.h"
 | 
			
		||||
#include "backends/native/meta-kms-update-private.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaKmsPlane
 | 
			
		||||
{
 | 
			
		||||
  GObject parent;
 | 
			
		||||
 | 
			
		||||
  MetaKmsPlaneType type;
 | 
			
		||||
  uint32_t id;
 | 
			
		||||
 | 
			
		||||
  uint32_t possible_crtcs;
 | 
			
		||||
 | 
			
		||||
  uint32_t rotation_prop_id;
 | 
			
		||||
  uint32_t rotation_map[META_MONITOR_N_TRANSFORMS];
 | 
			
		||||
  uint32_t all_hw_transforms;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * primary plane's supported formats and maybe modifiers
 | 
			
		||||
   * key: GUINT_TO_POINTER (format)
 | 
			
		||||
   * value: owned GArray* (uint64_t modifier), or NULL
 | 
			
		||||
   */
 | 
			
		||||
  GHashTable *formats_modifiers;
 | 
			
		||||
 | 
			
		||||
  MetaKmsDevice *device;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaKmsPlane, meta_kms_plane, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice *
 | 
			
		||||
meta_kms_plane_get_device (MetaKmsPlane *plane)
 | 
			
		||||
{
 | 
			
		||||
  return plane->device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t
 | 
			
		||||
meta_kms_plane_get_id (MetaKmsPlane *plane)
 | 
			
		||||
{
 | 
			
		||||
  return plane->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsPlaneType
 | 
			
		||||
meta_kms_plane_get_plane_type (MetaKmsPlane *plane)
 | 
			
		||||
{
 | 
			
		||||
  return plane->type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_plane_update_set_rotation (MetaKmsPlane           *plane,
 | 
			
		||||
                                    MetaKmsPlaneAssignment *plane_assignment,
 | 
			
		||||
                                    MetaMonitorTransform    transform)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (meta_kms_plane_is_transform_handled (plane, transform));
 | 
			
		||||
 | 
			
		||||
  meta_kms_plane_assignment_set_plane_property (plane_assignment,
 | 
			
		||||
                                                plane->rotation_prop_id,
 | 
			
		||||
                                                plane->rotation_map[transform]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_kms_plane_is_transform_handled (MetaKmsPlane         *plane,
 | 
			
		||||
                                     MetaMonitorTransform  transform)
 | 
			
		||||
{
 | 
			
		||||
  switch (transform)
 | 
			
		||||
    {
 | 
			
		||||
    case META_MONITOR_TRANSFORM_NORMAL:
 | 
			
		||||
    case META_MONITOR_TRANSFORM_180:
 | 
			
		||||
    case META_MONITOR_TRANSFORM_FLIPPED:
 | 
			
		||||
    case META_MONITOR_TRANSFORM_FLIPPED_180:
 | 
			
		||||
      break;
 | 
			
		||||
    case META_MONITOR_TRANSFORM_90:
 | 
			
		||||
    case META_MONITOR_TRANSFORM_270:
 | 
			
		||||
    case META_MONITOR_TRANSFORM_FLIPPED_90:
 | 
			
		||||
    case META_MONITOR_TRANSFORM_FLIPPED_270:
 | 
			
		||||
      /*
 | 
			
		||||
       * Blacklist these transforms as testing shows that they don't work
 | 
			
		||||
       * anyway, e.g. due to the wrong buffer modifiers. They might as well be
 | 
			
		||||
       * less optimal due to the complexity dealing with rotation at scan-out,
 | 
			
		||||
       * potentially resulting in higher power consumption.
 | 
			
		||||
       */
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
  return plane->all_hw_transforms & (1 << transform);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GArray *
 | 
			
		||||
meta_kms_plane_get_modifiers_for_format (MetaKmsPlane *plane,
 | 
			
		||||
                                         uint32_t      format)
 | 
			
		||||
{
 | 
			
		||||
  return g_hash_table_lookup (plane->formats_modifiers,
 | 
			
		||||
                              GUINT_TO_POINTER (format));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GArray *
 | 
			
		||||
meta_kms_plane_copy_drm_format_list (MetaKmsPlane *plane)
 | 
			
		||||
{
 | 
			
		||||
  GArray *formats;
 | 
			
		||||
  GHashTableIter it;
 | 
			
		||||
  gpointer key;
 | 
			
		||||
  unsigned int n_formats_modifiers;
 | 
			
		||||
 | 
			
		||||
  n_formats_modifiers = g_hash_table_size (plane->formats_modifiers);
 | 
			
		||||
  formats = g_array_sized_new (FALSE, FALSE,
 | 
			
		||||
                               sizeof (uint32_t),
 | 
			
		||||
                               n_formats_modifiers);
 | 
			
		||||
  g_hash_table_iter_init (&it, plane->formats_modifiers);
 | 
			
		||||
  while (g_hash_table_iter_next (&it, &key, NULL))
 | 
			
		||||
    {
 | 
			
		||||
      uint32_t drm_format = GPOINTER_TO_UINT (key);
 | 
			
		||||
 | 
			
		||||
      g_array_append_val (formats, drm_format);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return formats;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_kms_plane_is_format_supported (MetaKmsPlane *plane,
 | 
			
		||||
                                    uint32_t      drm_format)
 | 
			
		||||
{
 | 
			
		||||
  return g_hash_table_lookup_extended (plane->formats_modifiers,
 | 
			
		||||
                                       GUINT_TO_POINTER (drm_format),
 | 
			
		||||
                                       NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_kms_plane_is_usable_with (MetaKmsPlane *plane,
 | 
			
		||||
                               MetaKmsCrtc  *crtc)
 | 
			
		||||
{
 | 
			
		||||
  return !!(plane->possible_crtcs & (1 << meta_kms_crtc_get_idx (crtc)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
parse_rotations (MetaKmsPlane       *plane,
 | 
			
		||||
                 MetaKmsImplDevice  *impl_device,
 | 
			
		||||
                 drmModePropertyPtr  prop)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < prop->count_enums; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaMonitorTransform transform = -1;
 | 
			
		||||
 | 
			
		||||
      if (strcmp (prop->enums[i].name, "rotate-0") == 0)
 | 
			
		||||
        transform = META_MONITOR_TRANSFORM_NORMAL;
 | 
			
		||||
      else if (strcmp (prop->enums[i].name, "rotate-90") == 0)
 | 
			
		||||
        transform = META_MONITOR_TRANSFORM_90;
 | 
			
		||||
      else if (strcmp (prop->enums[i].name, "rotate-180") == 0)
 | 
			
		||||
        transform = META_MONITOR_TRANSFORM_180;
 | 
			
		||||
      else if (strcmp (prop->enums[i].name, "rotate-270") == 0)
 | 
			
		||||
        transform = META_MONITOR_TRANSFORM_270;
 | 
			
		||||
 | 
			
		||||
      if (transform != -1)
 | 
			
		||||
        {
 | 
			
		||||
          plane->all_hw_transforms |= 1 << transform;
 | 
			
		||||
          plane->rotation_map[transform] = 1 << prop->enums[i].value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_rotations (MetaKmsPlane            *plane,
 | 
			
		||||
                MetaKmsImplDevice       *impl_device,
 | 
			
		||||
                drmModeObjectProperties *drm_plane_props)
 | 
			
		||||
{
 | 
			
		||||
  drmModePropertyPtr prop;
 | 
			
		||||
  int idx;
 | 
			
		||||
 | 
			
		||||
  prop = meta_kms_impl_device_find_property (impl_device, drm_plane_props,
 | 
			
		||||
                                             "rotation", &idx);
 | 
			
		||||
  if (prop)
 | 
			
		||||
    {
 | 
			
		||||
      plane->rotation_prop_id = drm_plane_props->props[idx];
 | 
			
		||||
      parse_rotations (plane, impl_device, prop);
 | 
			
		||||
      drmModeFreeProperty (prop);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint32_t *
 | 
			
		||||
drm_formats_ptr (struct drm_format_modifier_blob *blob)
 | 
			
		||||
{
 | 
			
		||||
  return (uint32_t *) (((char *) blob) + blob->formats_offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct drm_format_modifier *
 | 
			
		||||
drm_modifiers_ptr (struct drm_format_modifier_blob *blob)
 | 
			
		||||
{
 | 
			
		||||
  return (struct drm_format_modifier *) (((char *) blob) +
 | 
			
		||||
                                         blob->modifiers_offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
free_modifier_array (GArray *array)
 | 
			
		||||
{
 | 
			
		||||
  if (!array)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_array_free (array, TRUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
parse_formats (MetaKmsPlane      *plane,
 | 
			
		||||
               MetaKmsImplDevice *impl_device,
 | 
			
		||||
               uint32_t           blob_id)
 | 
			
		||||
{
 | 
			
		||||
  int fd;
 | 
			
		||||
  drmModePropertyBlobPtr blob;
 | 
			
		||||
  struct drm_format_modifier_blob *blob_fmt;
 | 
			
		||||
  uint32_t *formats;
 | 
			
		||||
  struct drm_format_modifier *drm_modifiers;
 | 
			
		||||
  unsigned int fmt_i, mod_i;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (g_hash_table_size (plane->formats_modifiers) == 0);
 | 
			
		||||
 | 
			
		||||
  if (blob_id == 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  fd = meta_kms_impl_device_get_fd (impl_device);
 | 
			
		||||
  blob = drmModeGetPropertyBlob (fd, blob_id);
 | 
			
		||||
  if (!blob)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (blob->length < sizeof (struct drm_format_modifier_blob))
 | 
			
		||||
    {
 | 
			
		||||
      drmModeFreePropertyBlob (blob);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  blob_fmt = blob->data;
 | 
			
		||||
 | 
			
		||||
  formats = drm_formats_ptr (blob_fmt);
 | 
			
		||||
  drm_modifiers = drm_modifiers_ptr (blob_fmt);
 | 
			
		||||
 | 
			
		||||
  for (fmt_i = 0; fmt_i < blob_fmt->count_formats; fmt_i++)
 | 
			
		||||
    {
 | 
			
		||||
      GArray *modifiers = g_array_new (FALSE, FALSE, sizeof (uint64_t));
 | 
			
		||||
 | 
			
		||||
      for (mod_i = 0; mod_i < blob_fmt->count_modifiers; mod_i++)
 | 
			
		||||
        {
 | 
			
		||||
          struct drm_format_modifier *drm_modifier = &drm_modifiers[mod_i];
 | 
			
		||||
 | 
			
		||||
          /*
 | 
			
		||||
           * The modifier advertisement blob is partitioned into groups of
 | 
			
		||||
           * 64 formats.
 | 
			
		||||
           */
 | 
			
		||||
          if (fmt_i < drm_modifier->offset || fmt_i > drm_modifier->offset + 63)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
          if (!(drm_modifier->formats & (1 << (fmt_i - drm_modifier->offset))))
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
          g_array_append_val (modifiers, drm_modifier->modifier);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (modifiers->len == 0)
 | 
			
		||||
        {
 | 
			
		||||
          free_modifier_array (modifiers);
 | 
			
		||||
          modifiers = NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      g_hash_table_insert (plane->formats_modifiers,
 | 
			
		||||
                           GUINT_TO_POINTER (formats[fmt_i]),
 | 
			
		||||
                           modifiers);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  drmModeFreePropertyBlob (blob);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_formats (MetaKmsPlane            *plane,
 | 
			
		||||
              MetaKmsImplDevice       *impl_device,
 | 
			
		||||
              drmModeObjectProperties *drm_plane_props)
 | 
			
		||||
{
 | 
			
		||||
  drmModePropertyPtr prop;
 | 
			
		||||
  int idx;
 | 
			
		||||
 | 
			
		||||
  plane->formats_modifiers =
 | 
			
		||||
    g_hash_table_new_full (g_direct_hash,
 | 
			
		||||
                           g_direct_equal,
 | 
			
		||||
                           NULL,
 | 
			
		||||
                           (GDestroyNotify) free_modifier_array);
 | 
			
		||||
 | 
			
		||||
  prop = meta_kms_impl_device_find_property (impl_device, drm_plane_props,
 | 
			
		||||
                                             "IN_FORMATS", &idx);
 | 
			
		||||
  if (prop)
 | 
			
		||||
    {
 | 
			
		||||
      uint32_t blob_id;
 | 
			
		||||
 | 
			
		||||
      blob_id = drm_plane_props->prop_values[idx];
 | 
			
		||||
      parse_formats (plane, impl_device, blob_id);
 | 
			
		||||
      drmModeFreeProperty (prop);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsPlane *
 | 
			
		||||
meta_kms_plane_new (MetaKmsPlaneType         type,
 | 
			
		||||
                    MetaKmsImplDevice       *impl_device,
 | 
			
		||||
                    drmModePlane            *drm_plane,
 | 
			
		||||
                    drmModeObjectProperties *drm_plane_props)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsPlane *plane;
 | 
			
		||||
 | 
			
		||||
  plane = g_object_new (META_TYPE_KMS_PLANE, NULL);
 | 
			
		||||
  plane->type = type;
 | 
			
		||||
  plane->id = drm_plane->plane_id;
 | 
			
		||||
  plane->possible_crtcs = drm_plane->possible_crtcs;
 | 
			
		||||
  plane->device = meta_kms_impl_device_get_device (impl_device);
 | 
			
		||||
 | 
			
		||||
  init_rotations (plane, impl_device, drm_plane_props);
 | 
			
		||||
  init_formats (plane, impl_device, drm_plane_props);
 | 
			
		||||
 | 
			
		||||
  return plane;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_plane_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsPlane *plane = META_KMS_PLANE (object);
 | 
			
		||||
 | 
			
		||||
  g_hash_table_destroy (plane->formats_modifiers);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_kms_plane_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_plane_init (MetaKmsPlane *plane)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_plane_class_init (MetaKmsPlaneClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_kms_plane_finalize;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								src/backends/native/meta-kms-plane.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/backends/native/meta-kms-plane.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 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_KMS_PLANE_H
 | 
			
		||||
#define META_KMS_PLANE_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
#include "backends/meta-monitor-transform.h"
 | 
			
		||||
 | 
			
		||||
typedef enum _MetaKmsPlaneType
 | 
			
		||||
{
 | 
			
		||||
  META_KMS_PLANE_TYPE_PRIMARY,
 | 
			
		||||
  META_KMS_PLANE_TYPE_CURSOR,
 | 
			
		||||
  META_KMS_PLANE_TYPE_OVERLAY,
 | 
			
		||||
} MetaKmsPlaneType;
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_KMS_PLANE meta_kms_plane_get_type ()
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaKmsPlane, meta_kms_plane,
 | 
			
		||||
                      META, KMS_PLANE, GObject)
 | 
			
		||||
 | 
			
		||||
MetaKmsPlane * meta_kms_plane_new (MetaKmsPlaneType         type,
 | 
			
		||||
                                   MetaKmsImplDevice       *impl_device,
 | 
			
		||||
                                   drmModePlane            *drm_plane,
 | 
			
		||||
                                   drmModeObjectProperties *drm_plane_props);
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice * meta_kms_plane_get_device (MetaKmsPlane *plane);
 | 
			
		||||
 | 
			
		||||
uint32_t meta_kms_plane_get_id (MetaKmsPlane *plane);
 | 
			
		||||
 | 
			
		||||
MetaKmsPlaneType meta_kms_plane_get_plane_type (MetaKmsPlane *plane);
 | 
			
		||||
 | 
			
		||||
gboolean meta_kms_plane_is_transform_handled (MetaKmsPlane         *plane,
 | 
			
		||||
                                              MetaMonitorTransform  transform);
 | 
			
		||||
 | 
			
		||||
GArray * meta_kms_plane_get_modifiers_for_format (MetaKmsPlane *plane,
 | 
			
		||||
                                                  uint32_t      format);
 | 
			
		||||
 | 
			
		||||
GArray * meta_kms_plane_copy_drm_format_list (MetaKmsPlane *plane);
 | 
			
		||||
 | 
			
		||||
gboolean meta_kms_plane_is_format_supported (MetaKmsPlane *plane,
 | 
			
		||||
                                             uint32_t      format);
 | 
			
		||||
 | 
			
		||||
gboolean meta_kms_plane_is_usable_with (MetaKmsPlane *plane,
 | 
			
		||||
                                        MetaKmsCrtc  *crtc);
 | 
			
		||||
 | 
			
		||||
void meta_kms_plane_update_set_rotation (MetaKmsPlane           *plane,
 | 
			
		||||
                                         MetaKmsPlaneAssignment *plane_assignment,
 | 
			
		||||
                                         MetaMonitorTransform    transform);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_PLANE_H */
 | 
			
		||||
							
								
								
									
										63
									
								
								src/backends/native/meta-kms-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/backends/native/meta-kms-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_PRIVATE_H
 | 
			
		||||
#define META_KMS_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
 | 
			
		||||
typedef void (* MetaKmsCallback) (MetaKms  *kms,
 | 
			
		||||
                                  gpointer  user_data);
 | 
			
		||||
 | 
			
		||||
typedef gboolean (* MetaKmsImplTaskFunc) (MetaKmsImpl  *impl,
 | 
			
		||||
                                          gpointer      user_data,
 | 
			
		||||
                                          GError      **error);
 | 
			
		||||
 | 
			
		||||
void meta_kms_queue_callback (MetaKms         *kms,
 | 
			
		||||
                              MetaKmsCallback  callback,
 | 
			
		||||
                              gpointer         user_data,
 | 
			
		||||
                              GDestroyNotify   user_data_destroy);
 | 
			
		||||
 | 
			
		||||
int meta_kms_flush_callbacks (MetaKms *kms);
 | 
			
		||||
 | 
			
		||||
gboolean meta_kms_run_impl_task_sync (MetaKms              *kms,
 | 
			
		||||
                                      MetaKmsImplTaskFunc   func,
 | 
			
		||||
                                      gpointer              user_data,
 | 
			
		||||
                                      GError              **error);
 | 
			
		||||
 | 
			
		||||
GSource * meta_kms_add_source_in_impl (MetaKms        *kms,
 | 
			
		||||
                                       GSourceFunc     func,
 | 
			
		||||
                                       gpointer        user_data,
 | 
			
		||||
                                       GDestroyNotify  user_data_destroy);
 | 
			
		||||
 | 
			
		||||
GSource * meta_kms_register_fd_in_impl (MetaKms             *kms,
 | 
			
		||||
                                        int                  fd,
 | 
			
		||||
                                        MetaKmsImplTaskFunc  dispatch,
 | 
			
		||||
                                        gpointer             user_data);
 | 
			
		||||
 | 
			
		||||
gboolean meta_kms_in_impl_task (MetaKms *kms);
 | 
			
		||||
 | 
			
		||||
#define meta_assert_in_kms_impl(kms) \
 | 
			
		||||
  g_assert (meta_kms_in_impl_task (kms))
 | 
			
		||||
#define meta_assert_not_in_kms_impl(kms) \
 | 
			
		||||
  g_assert (!meta_kms_in_impl_task (kms))
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_PRIVATE_H */
 | 
			
		||||
							
								
								
									
										59
									
								
								src/backends/native/meta-kms-types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/backends/native/meta-kms-types.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_IMPL_TYPES_H
 | 
			
		||||
#define META_KMS_IMPL_TYPES_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKms MetaKms;
 | 
			
		||||
typedef struct _MetaKmsDevice MetaKmsDevice;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsPlane MetaKmsPlane;
 | 
			
		||||
typedef struct _MetaKmsCrtc MetaKmsCrtc;
 | 
			
		||||
typedef struct _MetaKmsConnector MetaKmsConnector;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsUpdate MetaKmsUpdate;
 | 
			
		||||
typedef struct _MetaKmsPlaneAssignment MetaKmsPlaneAssignment;
 | 
			
		||||
typedef struct _MetaKmsModeSet MetaKmsModeSet;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsPageFlipFeedback MetaKmsPageFlipFeedback;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsImpl MetaKmsImpl;
 | 
			
		||||
typedef struct _MetaKmsImplDevice MetaKmsImplDevice;
 | 
			
		||||
 | 
			
		||||
/* 16:16 fixed point */
 | 
			
		||||
typedef int32_t MetaFixed16;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaFixed16Rectangle
 | 
			
		||||
{
 | 
			
		||||
  MetaFixed16 x;
 | 
			
		||||
  MetaFixed16 y;
 | 
			
		||||
  MetaFixed16 width;
 | 
			
		||||
  MetaFixed16 height;
 | 
			
		||||
} MetaFixed16Rectangle;
 | 
			
		||||
 | 
			
		||||
typedef enum _MetaKmsDeviceFlag
 | 
			
		||||
{
 | 
			
		||||
  META_KMS_DEVICE_FLAG_NONE = 0,
 | 
			
		||||
  META_KMS_DEVICE_FLAG_BOOT_VGA = 1 << 0,
 | 
			
		||||
  META_KMS_DEVICE_FLAG_PLATFORM_DEVICE = 1 << 1,
 | 
			
		||||
} MetaKmsDeviceFlag;
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_IMPL_TYPES_H */
 | 
			
		||||
							
								
								
									
										100
									
								
								src/backends/native/meta-kms-update-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/backends/native/meta-kms-update-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 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_KMS_UPDATE_PRIVATE_H
 | 
			
		||||
#define META_KMS_UPDATE_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
#include "backends/native/meta-kms-update.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsProperty
 | 
			
		||||
{
 | 
			
		||||
  uint32_t prop_id;
 | 
			
		||||
  uint64_t value;
 | 
			
		||||
} MetaKmsProperty;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsPlaneAssignment
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCrtc *crtc;
 | 
			
		||||
  MetaKmsPlane *plane;
 | 
			
		||||
  uint32_t fb_id;
 | 
			
		||||
  MetaFixed16Rectangle src_rect;
 | 
			
		||||
  MetaFixed16Rectangle dst_rect;
 | 
			
		||||
 | 
			
		||||
  GList *plane_properties;
 | 
			
		||||
} MetaKmsPlaneAssignment;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsModeSet
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCrtc *crtc;
 | 
			
		||||
  GList *connectors;
 | 
			
		||||
  drmModeModeInfo *drm_mode;
 | 
			
		||||
} MetaKmsModeSet;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsConnectorProperty
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsDevice *device;
 | 
			
		||||
  MetaKmsConnector *connector;
 | 
			
		||||
  uint32_t prop_id;
 | 
			
		||||
  uint64_t value;
 | 
			
		||||
} MetaKmsConnectorProperty;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsPageFlip
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCrtc *crtc;
 | 
			
		||||
  const MetaKmsPageFlipFeedback *feedback;
 | 
			
		||||
  gpointer user_data;
 | 
			
		||||
  MetaKmsCustomPageFlipFunc custom_page_flip_func;
 | 
			
		||||
  gpointer custom_page_flip_user_data;
 | 
			
		||||
} MetaKmsPageFlip;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsCrtcGamma
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCrtc *crtc;
 | 
			
		||||
  gsize size;
 | 
			
		||||
  unsigned short *red;
 | 
			
		||||
  unsigned short *green;
 | 
			
		||||
  unsigned short *blue;
 | 
			
		||||
} MetaKmsCrtcGamma;
 | 
			
		||||
 | 
			
		||||
void meta_kms_update_set_connector_property (MetaKmsUpdate    *update,
 | 
			
		||||
                                             MetaKmsConnector *connector,
 | 
			
		||||
                                             uint32_t          prop_id,
 | 
			
		||||
                                             uint64_t          value);
 | 
			
		||||
 | 
			
		||||
void meta_kms_plane_assignment_set_plane_property (MetaKmsPlaneAssignment *plane_assignment,
 | 
			
		||||
                                                   uint32_t                prop_id,
 | 
			
		||||
                                                   uint64_t                value);
 | 
			
		||||
 | 
			
		||||
GList * meta_kms_update_get_plane_assignments (MetaKmsUpdate *update);
 | 
			
		||||
 | 
			
		||||
GList * meta_kms_update_get_mode_sets (MetaKmsUpdate *update);
 | 
			
		||||
 | 
			
		||||
GList * meta_kms_update_get_page_flips (MetaKmsUpdate *update);
 | 
			
		||||
 | 
			
		||||
GList * meta_kms_update_get_connector_properties (MetaKmsUpdate *update);
 | 
			
		||||
 | 
			
		||||
GList * meta_kms_update_get_crtc_gammas (MetaKmsUpdate *update);
 | 
			
		||||
 | 
			
		||||
gboolean meta_kms_update_has_mode_set (MetaKmsUpdate *update);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_UPDATE_PRIVATE_H */
 | 
			
		||||
							
								
								
									
										291
									
								
								src/backends/native/meta-kms-update.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								src/backends/native/meta-kms-update.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,291 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 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-kms-update.h"
 | 
			
		||||
#include "backends/native/meta-kms-update-private.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-display-config-shared.h"
 | 
			
		||||
#include "backends/native/meta-kms-plane.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaKmsUpdate
 | 
			
		||||
{
 | 
			
		||||
  MetaPowerSave power_save;
 | 
			
		||||
  GList *mode_sets;
 | 
			
		||||
  GList *plane_assignments;
 | 
			
		||||
  GList *page_flips;
 | 
			
		||||
  GList *connector_properties;
 | 
			
		||||
  GList *crtc_gammas;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static MetaKmsProperty *
 | 
			
		||||
meta_kms_property_new (uint32_t prop_id,
 | 
			
		||||
                       uint64_t value)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsProperty *prop;
 | 
			
		||||
 | 
			
		||||
  prop = g_new0 (MetaKmsProperty, 1);
 | 
			
		||||
  *prop = (MetaKmsProperty) {
 | 
			
		||||
    .prop_id = prop_id,
 | 
			
		||||
    .value = value,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return prop;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_property_free (MetaKmsProperty *prop)
 | 
			
		||||
{
 | 
			
		||||
  g_free (prop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_plane_assignment_free (MetaKmsPlaneAssignment *plane_assignment)
 | 
			
		||||
{
 | 
			
		||||
  g_list_free_full (plane_assignment->plane_properties,
 | 
			
		||||
                    (GDestroyNotify) meta_kms_property_free);
 | 
			
		||||
  g_free (plane_assignment);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_mode_set_free (MetaKmsModeSet *mode_set)
 | 
			
		||||
{
 | 
			
		||||
  g_free (mode_set->drm_mode);
 | 
			
		||||
  g_list_free (mode_set->connectors);
 | 
			
		||||
  g_free (mode_set);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_crtc_gamma_free (MetaKmsCrtcGamma *crtc_gamma)
 | 
			
		||||
{
 | 
			
		||||
  g_free (crtc_gamma->red);
 | 
			
		||||
  g_free (crtc_gamma->green);
 | 
			
		||||
  g_free (crtc_gamma->blue);
 | 
			
		||||
  g_free (crtc_gamma);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned short *
 | 
			
		||||
copy_unsigned_short_array (unsigned short *values,
 | 
			
		||||
                           gsize           n_values)
 | 
			
		||||
{
 | 
			
		||||
  unsigned short *copy;
 | 
			
		||||
 | 
			
		||||
  if (!values)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  copy = g_new (unsigned short, n_values);
 | 
			
		||||
  memcpy (copy, values, sizeof (unsigned short) * n_values);
 | 
			
		||||
 | 
			
		||||
  return copy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsPlaneAssignment *
 | 
			
		||||
meta_kms_update_assign_plane (MetaKmsUpdate        *update,
 | 
			
		||||
                              MetaKmsCrtc          *crtc,
 | 
			
		||||
                              MetaKmsPlane         *plane,
 | 
			
		||||
                              uint32_t              fb_id,
 | 
			
		||||
                              MetaFixed16Rectangle  src_rect,
 | 
			
		||||
                              MetaFixed16Rectangle  dst_rect)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsPlaneAssignment *plane_assignment;
 | 
			
		||||
 | 
			
		||||
  plane_assignment = g_new0 (MetaKmsPlaneAssignment, 1);
 | 
			
		||||
  *plane_assignment = (MetaKmsPlaneAssignment) {
 | 
			
		||||
    .crtc = crtc,
 | 
			
		||||
    .plane = plane,
 | 
			
		||||
    .fb_id = fb_id,
 | 
			
		||||
    .src_rect = src_rect,
 | 
			
		||||
    .dst_rect = dst_rect,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  update->plane_assignments = g_list_prepend (update->plane_assignments,
 | 
			
		||||
                                              plane_assignment);
 | 
			
		||||
 | 
			
		||||
  return plane_assignment;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_update_set_crtc_gamma (MetaKmsUpdate  *update,
 | 
			
		||||
                                MetaKmsCrtc    *crtc,
 | 
			
		||||
                                gsize           size,
 | 
			
		||||
                                unsigned short *red,
 | 
			
		||||
                                unsigned short *green,
 | 
			
		||||
                                unsigned short *blue)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCrtcGamma *crtc_gamma;
 | 
			
		||||
 | 
			
		||||
  crtc_gamma = g_new0 (MetaKmsCrtcGamma, 1);
 | 
			
		||||
  *crtc_gamma = (MetaKmsCrtcGamma) {
 | 
			
		||||
    .crtc = crtc,
 | 
			
		||||
    .size = size,
 | 
			
		||||
    .red = copy_unsigned_short_array (red, size),
 | 
			
		||||
    .green = copy_unsigned_short_array (green, size),
 | 
			
		||||
    .blue = copy_unsigned_short_array (blue, size),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  update->crtc_gammas = g_list_prepend (update->crtc_gammas, crtc_gamma);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_update_mode_set (MetaKmsUpdate   *update,
 | 
			
		||||
                          MetaKmsCrtc     *crtc,
 | 
			
		||||
                          GList           *connectors,
 | 
			
		||||
                          drmModeModeInfo *drm_mode)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsModeSet *mode_set;
 | 
			
		||||
 | 
			
		||||
  mode_set = g_new0 (MetaKmsModeSet, 1);
 | 
			
		||||
  *mode_set = (MetaKmsModeSet) {
 | 
			
		||||
    .crtc = crtc,
 | 
			
		||||
    .connectors = connectors,
 | 
			
		||||
    .drm_mode = drm_mode ? g_memdup (drm_mode, sizeof *drm_mode) : NULL,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  update->mode_sets = g_list_prepend (update->mode_sets, mode_set);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_update_set_connector_property (MetaKmsUpdate    *update,
 | 
			
		||||
                                        MetaKmsConnector *connector,
 | 
			
		||||
                                        uint32_t          prop_id,
 | 
			
		||||
                                        uint64_t          value)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsConnectorProperty *prop;
 | 
			
		||||
 | 
			
		||||
  prop = g_new0 (MetaKmsConnectorProperty, 1);
 | 
			
		||||
  *prop = (MetaKmsConnectorProperty) {
 | 
			
		||||
    .connector = connector,
 | 
			
		||||
    .prop_id = prop_id,
 | 
			
		||||
    .value = value,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  update->connector_properties = g_list_prepend (update->connector_properties,
 | 
			
		||||
                                                 prop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_update_page_flip (MetaKmsUpdate                 *update,
 | 
			
		||||
                           MetaKmsCrtc                   *crtc,
 | 
			
		||||
                           const MetaKmsPageFlipFeedback *feedback,
 | 
			
		||||
                           gpointer                       user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsPageFlip *page_flip;
 | 
			
		||||
 | 
			
		||||
  page_flip = g_new0 (MetaKmsPageFlip, 1);
 | 
			
		||||
  *page_flip = (MetaKmsPageFlip) {
 | 
			
		||||
    .crtc = crtc,
 | 
			
		||||
    .feedback = feedback,
 | 
			
		||||
    .user_data = user_data,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  update->page_flips = g_list_prepend (update->page_flips, page_flip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_update_custom_page_flip (MetaKmsUpdate                 *update,
 | 
			
		||||
                                  MetaKmsCrtc                   *crtc,
 | 
			
		||||
                                  const MetaKmsPageFlipFeedback *feedback,
 | 
			
		||||
                                  gpointer                       user_data,
 | 
			
		||||
                                  MetaKmsCustomPageFlipFunc      custom_page_flip_func,
 | 
			
		||||
                                  gpointer                       custom_page_flip_user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsPageFlip *page_flip;
 | 
			
		||||
 | 
			
		||||
  page_flip = g_new0 (MetaKmsPageFlip, 1);
 | 
			
		||||
  *page_flip = (MetaKmsPageFlip) {
 | 
			
		||||
    .crtc = crtc,
 | 
			
		||||
    .feedback = feedback,
 | 
			
		||||
    .user_data = user_data,
 | 
			
		||||
    .custom_page_flip_func = custom_page_flip_func,
 | 
			
		||||
    .custom_page_flip_user_data = custom_page_flip_user_data,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  update->page_flips = g_list_prepend (update->page_flips, page_flip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_plane_assignment_set_plane_property (MetaKmsPlaneAssignment *plane_assignment,
 | 
			
		||||
                                              uint32_t                prop_id,
 | 
			
		||||
                                              uint64_t                value)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsProperty *plane_prop;
 | 
			
		||||
 | 
			
		||||
  plane_prop = meta_kms_property_new (prop_id, value);
 | 
			
		||||
 | 
			
		||||
  plane_assignment->plane_properties =
 | 
			
		||||
    g_list_prepend (plane_assignment->plane_properties, plane_prop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_kms_update_get_plane_assignments (MetaKmsUpdate *update)
 | 
			
		||||
{
 | 
			
		||||
  return update->plane_assignments;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_kms_update_get_mode_sets (MetaKmsUpdate *update)
 | 
			
		||||
{
 | 
			
		||||
  return update->mode_sets;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_kms_update_get_page_flips (MetaKmsUpdate *update)
 | 
			
		||||
{
 | 
			
		||||
  return update->page_flips;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_kms_update_get_connector_properties (MetaKmsUpdate *update)
 | 
			
		||||
{
 | 
			
		||||
  return update->connector_properties;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_kms_update_get_crtc_gammas (MetaKmsUpdate *update)
 | 
			
		||||
{
 | 
			
		||||
  return update->crtc_gammas;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_kms_update_has_mode_set (MetaKmsUpdate *update)
 | 
			
		||||
{
 | 
			
		||||
  return !!update->mode_sets;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsUpdate *
 | 
			
		||||
meta_kms_update_new (void)
 | 
			
		||||
{
 | 
			
		||||
  return g_new0 (MetaKmsUpdate, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_update_free (MetaKmsUpdate *update)
 | 
			
		||||
{
 | 
			
		||||
  g_list_free_full (update->plane_assignments,
 | 
			
		||||
                    (GDestroyNotify) meta_kms_plane_assignment_free);
 | 
			
		||||
  g_list_free_full (update->mode_sets,
 | 
			
		||||
                    (GDestroyNotify) meta_kms_mode_set_free);
 | 
			
		||||
  g_list_free_full (update->page_flips, g_free);
 | 
			
		||||
  g_list_free_full (update->connector_properties, g_free);
 | 
			
		||||
  g_list_free_full (update->crtc_gammas,
 | 
			
		||||
                    (GDestroyNotify) meta_kms_crtc_gamma_free);
 | 
			
		||||
 | 
			
		||||
  g_free (update);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								src/backends/native/meta-kms-update.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/backends/native/meta-kms-update.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 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_KMS_UPDATE_H
 | 
			
		||||
#define META_KMS_UPDATE_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-monitor-transform.h"
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaKmsPageFlipFeedback
 | 
			
		||||
{
 | 
			
		||||
  void (* flipped) (MetaKmsCrtc  *crtc,
 | 
			
		||||
                    unsigned int  sequence,
 | 
			
		||||
                    unsigned int  tv_sec,
 | 
			
		||||
                    unsigned int  tv_usec,
 | 
			
		||||
                    gpointer      user_data);
 | 
			
		||||
 | 
			
		||||
  void (* mode_set_fallback) (MetaKmsCrtc *crtc,
 | 
			
		||||
                              gpointer     user_data);
 | 
			
		||||
 | 
			
		||||
  void (* discarded) (MetaKmsCrtc  *crtc,
 | 
			
		||||
                      gpointer      user_data,
 | 
			
		||||
                      const GError *error);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef int (* MetaKmsCustomPageFlipFunc) (gpointer custom_page_flip_data,
 | 
			
		||||
                                           gpointer user_data);
 | 
			
		||||
 | 
			
		||||
MetaKmsUpdate * meta_kms_update_new (void);
 | 
			
		||||
 | 
			
		||||
void meta_kms_update_free (MetaKmsUpdate *update);
 | 
			
		||||
 | 
			
		||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaKmsUpdate, meta_kms_update_free)
 | 
			
		||||
 | 
			
		||||
void meta_kms_update_mode_set (MetaKmsUpdate   *update,
 | 
			
		||||
                               MetaKmsCrtc     *crtc,
 | 
			
		||||
                               GList           *connectors,
 | 
			
		||||
                               drmModeModeInfo *drm_mode);
 | 
			
		||||
 | 
			
		||||
MetaKmsPlaneAssignment * meta_kms_update_assign_plane (MetaKmsUpdate        *update,
 | 
			
		||||
                                                       MetaKmsCrtc          *crtc,
 | 
			
		||||
                                                       MetaKmsPlane         *plane,
 | 
			
		||||
                                                       uint32_t              fb_id,
 | 
			
		||||
                                                       MetaFixed16Rectangle  src_rect,
 | 
			
		||||
                                                       MetaFixed16Rectangle  dst_rect);
 | 
			
		||||
 | 
			
		||||
void meta_kms_update_set_crtc_gamma (MetaKmsUpdate  *update,
 | 
			
		||||
                                     MetaKmsCrtc    *crtc,
 | 
			
		||||
                                     gsize           size,
 | 
			
		||||
                                     unsigned short *red,
 | 
			
		||||
                                     unsigned short *green,
 | 
			
		||||
                                     unsigned short *blue);
 | 
			
		||||
 | 
			
		||||
void meta_kms_update_page_flip (MetaKmsUpdate                 *update,
 | 
			
		||||
                                MetaKmsCrtc                   *crtc,
 | 
			
		||||
                                const MetaKmsPageFlipFeedback *feedback,
 | 
			
		||||
                                gpointer                       user_data);
 | 
			
		||||
 | 
			
		||||
void meta_kms_update_custom_page_flip (MetaKmsUpdate                 *update,
 | 
			
		||||
                                       MetaKmsCrtc                   *crtc,
 | 
			
		||||
                                       const MetaKmsPageFlipFeedback *feedback,
 | 
			
		||||
                                       gpointer                       user_data,
 | 
			
		||||
                                       MetaKmsCustomPageFlipFunc      custom_page_flip_func,
 | 
			
		||||
                                       gpointer                       custom_page_flip_user_data);
 | 
			
		||||
 | 
			
		||||
static inline MetaFixed16
 | 
			
		||||
meta_fixed_16_from_int (int16_t d)
 | 
			
		||||
{
 | 
			
		||||
  return d * 65536;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int16_t
 | 
			
		||||
meta_fixed_16_to_int (MetaFixed16 fixed)
 | 
			
		||||
{
 | 
			
		||||
  return fixed / 65536;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_UPDATE_H */
 | 
			
		||||
							
								
								
									
										83
									
								
								src/backends/native/meta-kms-utils.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/backends/native/meta-kms-utils.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2013-2019 Red Hat
 | 
			
		||||
 * Copyright (c) 2018 DisplayLink (UK) Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * 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-kms-utils.h"
 | 
			
		||||
 | 
			
		||||
#include <drm_fourcc.h>
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
/* added in libdrm 2.4.95 */
 | 
			
		||||
#ifndef DRM_FORMAT_INVALID
 | 
			
		||||
#define DRM_FORMAT_INVALID 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
float
 | 
			
		||||
meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *drm_mode)
 | 
			
		||||
{
 | 
			
		||||
  float refresh = 0.0;
 | 
			
		||||
 | 
			
		||||
  if (drm_mode->htotal > 0 && drm_mode->vtotal > 0)
 | 
			
		||||
    {
 | 
			
		||||
      /* Calculate refresh rate in milliHz first for extra precision. */
 | 
			
		||||
      refresh = (drm_mode->clock * 1000000LL) / drm_mode->htotal;
 | 
			
		||||
      refresh += (drm_mode->vtotal / 2);
 | 
			
		||||
      refresh /= drm_mode->vtotal;
 | 
			
		||||
      if (drm_mode->vscan > 1)
 | 
			
		||||
        refresh /= drm_mode->vscan;
 | 
			
		||||
      refresh /= 1000.0;
 | 
			
		||||
    }
 | 
			
		||||
  return refresh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_drm_format_to_string:
 | 
			
		||||
 * @tmp: temporary buffer
 | 
			
		||||
 * @drm_format: DRM fourcc pixel format
 | 
			
		||||
 *
 | 
			
		||||
 * Returns a pointer to a string naming the given pixel format,
 | 
			
		||||
 * usually a pointer to the temporary buffer but not always.
 | 
			
		||||
 * Invalid formats may return nonsense names.
 | 
			
		||||
 *
 | 
			
		||||
 * When calling this, allocate one MetaDrmFormatBuf on the stack to
 | 
			
		||||
 * be used as the temporary buffer.
 | 
			
		||||
 */
 | 
			
		||||
const char *
 | 
			
		||||
meta_drm_format_to_string (MetaDrmFormatBuf *tmp,
 | 
			
		||||
                           uint32_t          drm_format)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  if (drm_format == DRM_FORMAT_INVALID)
 | 
			
		||||
    return "INVALID";
 | 
			
		||||
 | 
			
		||||
  G_STATIC_ASSERT (sizeof (tmp->s) == 5);
 | 
			
		||||
  for (i = 0; i < 4; i++)
 | 
			
		||||
    {
 | 
			
		||||
      char c = (drm_format >> (i * 8)) & 0xff;
 | 
			
		||||
      tmp->s[i] = g_ascii_isgraph (c) ? c : '.';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  tmp->s[i] = 0;
 | 
			
		||||
 | 
			
		||||
  return tmp->s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								src/backends/native/meta-kms-utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/backends/native/meta-kms-utils.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 DisplayLink (UK) Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * 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_KMS_UTILS_H
 | 
			
		||||
#define META_KMS_UTILS_H
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaDrmFormatBuf
 | 
			
		||||
{
 | 
			
		||||
  char s[5];
 | 
			
		||||
} MetaDrmFormatBuf;
 | 
			
		||||
 | 
			
		||||
float meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *drm_mode);
 | 
			
		||||
 | 
			
		||||
const char * meta_drm_format_to_string (MetaDrmFormatBuf *tmp,
 | 
			
		||||
                                        uint32_t          drm_format);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_UTILS_H */
 | 
			
		||||
							
								
								
									
										563
									
								
								src/backends/native/meta-kms.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										563
									
								
								src/backends/native/meta-kms.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,563 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 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-kms-private.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-backend-native.h"
 | 
			
		||||
#include "backends/native/meta-kms-device-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-impl.h"
 | 
			
		||||
#include "backends/native/meta-kms-impl-simple.h"
 | 
			
		||||
#include "backends/native/meta-kms-update-private.h"
 | 
			
		||||
#include "backends/native/meta-udev.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:kms
 | 
			
		||||
 * @short description: KMS abstraction
 | 
			
		||||
 * @title: KMS abstraction
 | 
			
		||||
 *
 | 
			
		||||
 * The KMS abstraction consists of various building blocks for helping out with
 | 
			
		||||
 * interacting with the various drm API's, enabling users to use a
 | 
			
		||||
 * transactional API, aiming to hide all interaction with the underlying APIs.
 | 
			
		||||
 *
 | 
			
		||||
 * The subsystem defines two separate contexts, the "main" context, and the
 | 
			
		||||
 * "impl" context. The main context is the context of which mutter as a whole
 | 
			
		||||
 * runs in. It uses the main GLib main loop and main context and always runs in
 | 
			
		||||
 * the main thread.
 | 
			
		||||
 *
 | 
			
		||||
 * The impl context is where all underlying API is being executed. While in the
 | 
			
		||||
 * current state, it always runs in the main thread, the aim is to be able to
 | 
			
		||||
 * execute the impl context in a dedicated thread.
 | 
			
		||||
 *
 | 
			
		||||
 * The public facing MetaKms API is always assumed to be executed from the main
 | 
			
		||||
 * context.
 | 
			
		||||
 *
 | 
			
		||||
 * The KMS abstraction consists of the following public components:
 | 
			
		||||
 *
 | 
			
		||||
 * #MetaKms:
 | 
			
		||||
 *
 | 
			
		||||
 * Main entry point; used by the native backend to create devices, post updates
 | 
			
		||||
 * etc.
 | 
			
		||||
 *
 | 
			
		||||
 * #MetaKmsDevice:
 | 
			
		||||
 *
 | 
			
		||||
 * A device (usually /dev/dri/cardN, where N being a number). Used to get KMS
 | 
			
		||||
 * objects, such as connectors, CRTCs, planes, as well as basic meta data such
 | 
			
		||||
 * as device path etc.
 | 
			
		||||
 *
 | 
			
		||||
 * #MetaKmsCrtc:
 | 
			
		||||
 *
 | 
			
		||||
 * Represents a CRTC. It manages a representation of the current CRTC state,
 | 
			
		||||
 * including current mode, coordinates, possible clones.
 | 
			
		||||
 *
 | 
			
		||||
 * #MetaKmsConnector:
 | 
			
		||||
 *
 | 
			
		||||
 * Represents a connector, e.g. a display port connection. It also manages a
 | 
			
		||||
 * representation of the current state, including meta data such as physical
 | 
			
		||||
 * dimension of the connected, available modes, EDID, tile info etc. It also
 | 
			
		||||
 * contains helper functions for configuration, as well as methods for adding
 | 
			
		||||
 * configuration to a transaction (See #MetaKmsUpdate).
 | 
			
		||||
 *
 | 
			
		||||
 * #MetaKmsPlane:
 | 
			
		||||
 *
 | 
			
		||||
 * Represents a hardware plane. A plane is used to define the content of what
 | 
			
		||||
 * should be presented on a CRTC. Planes can either be primary planes, used as
 | 
			
		||||
 * a backdrop for CRTCs, overlay planes, and cursor planes.
 | 
			
		||||
 *
 | 
			
		||||
 * #MetaKmsUpdate:
 | 
			
		||||
 *
 | 
			
		||||
 * A KMS transaction object, meant to be processed potentially atomically when
 | 
			
		||||
 * posted. An update consists of plane assignments, mode sets and KMS object
 | 
			
		||||
 * property entries. The user adds updates to the object, and then posts it via
 | 
			
		||||
 * MetaKms. It will then be processed by the MetaKms backend (See
 | 
			
		||||
 * #MetaKmsImpl), potentially atomically.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * There are also these private objects, without public facing API:
 | 
			
		||||
 *
 | 
			
		||||
 * #MetaKmsImpl:
 | 
			
		||||
 *
 | 
			
		||||
 * The KMS backend implementation, running in the impl context. #MetaKmsImpl
 | 
			
		||||
 * itself is an abstract object, with potentially multiple implementations.
 | 
			
		||||
 * Currently only #MetaKmsImplSimple exists.
 | 
			
		||||
 *
 | 
			
		||||
 * #MetaKmsImplSimple:
 | 
			
		||||
 *
 | 
			
		||||
 * A KMS backend implementation using the non-atomic drmMode* API. While it's
 | 
			
		||||
 * interacted with using the transactional API, the #MetaKmsUpdate is processed
 | 
			
		||||
 * non-atomically.
 | 
			
		||||
 *
 | 
			
		||||
 * #MetaKmsImplDevice:
 | 
			
		||||
 *
 | 
			
		||||
 * An object linked to a #MetaKmsDevice, but where it is executed in the impl
 | 
			
		||||
 * context. It takes care of the updating of the various KMS object (CRTC,
 | 
			
		||||
 * connector, ..) states.
 | 
			
		||||
 *
 | 
			
		||||
 * #MetaKmsPageFlip:
 | 
			
		||||
 *
 | 
			
		||||
 * A object representing a page flip. It's created when a page flip is queued,
 | 
			
		||||
 * and contains information necessary to provide feedback to the one requesting
 | 
			
		||||
 * the page flip.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsCallbackData
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCallback callback;
 | 
			
		||||
  gpointer user_data;
 | 
			
		||||
  GDestroyNotify user_data_destroy;
 | 
			
		||||
} MetaKmsCallbackData;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsSimpleImplSource
 | 
			
		||||
{
 | 
			
		||||
  GSource source;
 | 
			
		||||
  MetaKms *kms;
 | 
			
		||||
} MetaKmsSimpleImplSource;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaKmsFdImplSource
 | 
			
		||||
{
 | 
			
		||||
  GSource source;
 | 
			
		||||
 | 
			
		||||
  gpointer fd_tag;
 | 
			
		||||
  MetaKms *kms;
 | 
			
		||||
 | 
			
		||||
  MetaKmsImplTaskFunc dispatch;
 | 
			
		||||
  gpointer user_data;
 | 
			
		||||
} MetaKmsFdImplSource;
 | 
			
		||||
 | 
			
		||||
struct _MetaKms
 | 
			
		||||
{
 | 
			
		||||
  GObject parent;
 | 
			
		||||
 | 
			
		||||
  MetaBackend *backend;
 | 
			
		||||
 | 
			
		||||
  guint hotplug_handler_id;
 | 
			
		||||
 | 
			
		||||
  MetaKmsImpl *impl;
 | 
			
		||||
  gboolean in_impl_task;
 | 
			
		||||
 | 
			
		||||
  GList *devices;
 | 
			
		||||
 | 
			
		||||
  MetaKmsUpdate *pending_update;
 | 
			
		||||
 | 
			
		||||
  GList *pending_callbacks;
 | 
			
		||||
  guint callback_source_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_update_states_in_impl (MetaKms *kms);
 | 
			
		||||
 | 
			
		||||
MetaKmsUpdate *
 | 
			
		||||
meta_kms_ensure_pending_update (MetaKms *kms)
 | 
			
		||||
{
 | 
			
		||||
  if (!kms->pending_update)
 | 
			
		||||
    kms->pending_update = meta_kms_update_new ();
 | 
			
		||||
 | 
			
		||||
  return meta_kms_get_pending_update (kms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsUpdate *
 | 
			
		||||
meta_kms_get_pending_update (MetaKms *kms)
 | 
			
		||||
{
 | 
			
		||||
  return kms->pending_update;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_kms_update_process_in_impl (MetaKmsImpl  *impl,
 | 
			
		||||
                                 gpointer      user_data,
 | 
			
		||||
                                 GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  g_autoptr (MetaKmsUpdate) update = user_data;
 | 
			
		||||
  gboolean ret;
 | 
			
		||||
 | 
			
		||||
  ret = meta_kms_impl_process_update (impl, update, error);
 | 
			
		||||
 | 
			
		||||
  if (meta_kms_update_has_mode_set (update))
 | 
			
		||||
    meta_kms_update_states_in_impl (meta_kms_impl_get_kms (impl));
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_kms_post_update_sync (MetaKms        *kms,
 | 
			
		||||
                           MetaKmsUpdate  *update,
 | 
			
		||||
                           GError        **error)
 | 
			
		||||
{
 | 
			
		||||
  return meta_kms_run_impl_task_sync (kms,
 | 
			
		||||
                                      meta_kms_update_process_in_impl,
 | 
			
		||||
                                      update,
 | 
			
		||||
                                      error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_kms_post_pending_update_sync (MetaKms  *kms,
 | 
			
		||||
                                   GError  **error)
 | 
			
		||||
{
 | 
			
		||||
  return meta_kms_post_update_sync (kms,
 | 
			
		||||
                                    g_steal_pointer (&kms->pending_update),
 | 
			
		||||
                                    error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_kms_discard_pending_page_flips_in_impl (MetaKmsImpl  *impl,
 | 
			
		||||
                                             gpointer      user_data,
 | 
			
		||||
                                             GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  meta_kms_impl_discard_pending_page_flips (impl);
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_discard_pending_page_flips (MetaKms *kms)
 | 
			
		||||
{
 | 
			
		||||
  meta_kms_run_impl_task_sync (kms,
 | 
			
		||||
                               meta_kms_discard_pending_page_flips_in_impl,
 | 
			
		||||
                               NULL,
 | 
			
		||||
                               NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_callback_data_free (MetaKmsCallbackData *callback_data)
 | 
			
		||||
{
 | 
			
		||||
  if (callback_data->user_data_destroy)
 | 
			
		||||
    callback_data->user_data_destroy (callback_data->user_data);
 | 
			
		||||
  g_slice_free (MetaKmsCallbackData, callback_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
flush_callbacks (MetaKms *kms)
 | 
			
		||||
{
 | 
			
		||||
  GList *l;
 | 
			
		||||
  int callback_count = 0;
 | 
			
		||||
 | 
			
		||||
  for (l = kms->pending_callbacks; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsCallbackData *callback_data = l->data;
 | 
			
		||||
 | 
			
		||||
      callback_data->callback (kms, callback_data->user_data);
 | 
			
		||||
      meta_kms_callback_data_free (callback_data);
 | 
			
		||||
      callback_count++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_list_free (kms->pending_callbacks);
 | 
			
		||||
  kms->pending_callbacks = NULL;
 | 
			
		||||
 | 
			
		||||
  return callback_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
callback_idle (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKms *kms = user_data;
 | 
			
		||||
 | 
			
		||||
  flush_callbacks (kms);
 | 
			
		||||
 | 
			
		||||
  kms->callback_source_id = 0;
 | 
			
		||||
  return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_kms_queue_callback (MetaKms         *kms,
 | 
			
		||||
                         MetaKmsCallback  callback,
 | 
			
		||||
                         gpointer         user_data,
 | 
			
		||||
                         GDestroyNotify   user_data_destroy)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsCallbackData *callback_data;
 | 
			
		||||
 | 
			
		||||
  callback_data = g_slice_new0 (MetaKmsCallbackData);
 | 
			
		||||
  *callback_data = (MetaKmsCallbackData) {
 | 
			
		||||
    .callback = callback,
 | 
			
		||||
    .user_data = user_data,
 | 
			
		||||
    .user_data_destroy = user_data_destroy,
 | 
			
		||||
  };
 | 
			
		||||
  kms->pending_callbacks = g_list_append (kms->pending_callbacks,
 | 
			
		||||
                                          callback_data);
 | 
			
		||||
  if (!kms->callback_source_id)
 | 
			
		||||
    kms->callback_source_id = g_idle_add (callback_idle, kms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_kms_flush_callbacks (MetaKms *kms)
 | 
			
		||||
{
 | 
			
		||||
  int callback_count;
 | 
			
		||||
 | 
			
		||||
  callback_count = flush_callbacks (kms);
 | 
			
		||||
  g_clear_handle_id (&kms->callback_source_id, g_source_remove);
 | 
			
		||||
 | 
			
		||||
  return callback_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_kms_run_impl_task_sync (MetaKms              *kms,
 | 
			
		||||
                             MetaKmsImplTaskFunc   func,
 | 
			
		||||
                             gpointer              user_data,
 | 
			
		||||
                             GError              **error)
 | 
			
		||||
{
 | 
			
		||||
  gboolean ret;
 | 
			
		||||
 | 
			
		||||
  kms->in_impl_task = TRUE;
 | 
			
		||||
  ret = func (kms->impl, user_data, error);
 | 
			
		||||
  kms->in_impl_task = FALSE;
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
simple_impl_source_dispatch (GSource     *source,
 | 
			
		||||
                             GSourceFunc  callback,
 | 
			
		||||
                             gpointer     user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsSimpleImplSource *simple_impl_source =
 | 
			
		||||
    (MetaKmsSimpleImplSource *) source;
 | 
			
		||||
  MetaKms *kms = simple_impl_source->kms;
 | 
			
		||||
  gboolean ret;
 | 
			
		||||
 | 
			
		||||
  kms->in_impl_task = TRUE;
 | 
			
		||||
  ret = callback (user_data);
 | 
			
		||||
  kms->in_impl_task = FALSE;
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GSourceFuncs simple_impl_source_funcs = {
 | 
			
		||||
  .dispatch = simple_impl_source_dispatch,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GSource *
 | 
			
		||||
meta_kms_add_source_in_impl (MetaKms        *kms,
 | 
			
		||||
                             GSourceFunc     func,
 | 
			
		||||
                             gpointer        user_data,
 | 
			
		||||
                             GDestroyNotify  user_data_destroy)
 | 
			
		||||
{
 | 
			
		||||
  GSource *source;
 | 
			
		||||
  MetaKmsSimpleImplSource *simple_impl_source;
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  source = g_source_new (&simple_impl_source_funcs,
 | 
			
		||||
                         sizeof (MetaKmsSimpleImplSource));
 | 
			
		||||
  simple_impl_source = (MetaKmsSimpleImplSource *) source;
 | 
			
		||||
  simple_impl_source->kms = kms;
 | 
			
		||||
 | 
			
		||||
  g_source_set_callback (source, func, user_data, user_data_destroy);
 | 
			
		||||
  g_source_attach (source, g_main_context_get_thread_default ());
 | 
			
		||||
 | 
			
		||||
  return source;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_kms_fd_impl_source_check (GSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsFdImplSource *fd_impl_source = (MetaKmsFdImplSource *) source;
 | 
			
		||||
 | 
			
		||||
  return g_source_query_unix_fd (source, fd_impl_source->fd_tag) & G_IO_IN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_kms_fd_impl_source_dispatch (GSource     *source,
 | 
			
		||||
                                  GSourceFunc  callback,
 | 
			
		||||
                                  gpointer     user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsFdImplSource *fd_impl_source = (MetaKmsFdImplSource *) source;
 | 
			
		||||
  MetaKms *kms = fd_impl_source->kms;
 | 
			
		||||
  gboolean ret;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  kms->in_impl_task = TRUE;
 | 
			
		||||
  ret = fd_impl_source->dispatch (kms->impl,
 | 
			
		||||
                                  fd_impl_source->user_data,
 | 
			
		||||
                                  &error);
 | 
			
		||||
  kms->in_impl_task = FALSE;
 | 
			
		||||
 | 
			
		||||
  if (!ret)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to dispatch fd source: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return G_SOURCE_CONTINUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GSourceFuncs fd_impl_source_funcs = {
 | 
			
		||||
  NULL,
 | 
			
		||||
  meta_kms_fd_impl_source_check,
 | 
			
		||||
  meta_kms_fd_impl_source_dispatch
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GSource *
 | 
			
		||||
meta_kms_register_fd_in_impl (MetaKms             *kms,
 | 
			
		||||
                              int                  fd,
 | 
			
		||||
                              MetaKmsImplTaskFunc  dispatch,
 | 
			
		||||
                              gpointer             user_data)
 | 
			
		||||
{
 | 
			
		||||
  GSource *source;
 | 
			
		||||
  MetaKmsFdImplSource *fd_impl_source;
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  source = g_source_new (&fd_impl_source_funcs, sizeof (MetaKmsFdImplSource));
 | 
			
		||||
  fd_impl_source = (MetaKmsFdImplSource *) source;
 | 
			
		||||
  fd_impl_source->dispatch = dispatch;
 | 
			
		||||
  fd_impl_source->user_data = user_data;
 | 
			
		||||
  fd_impl_source->kms = kms;
 | 
			
		||||
  fd_impl_source->fd_tag = g_source_add_unix_fd (source, fd,
 | 
			
		||||
                                                 G_IO_IN | G_IO_ERR);
 | 
			
		||||
 | 
			
		||||
  g_source_attach (source, g_main_context_get_thread_default ());
 | 
			
		||||
 | 
			
		||||
  return source;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_kms_in_impl_task (MetaKms *kms)
 | 
			
		||||
{
 | 
			
		||||
  return kms->in_impl_task;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_update_states_in_impl (MetaKms *kms)
 | 
			
		||||
{
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  meta_assert_in_kms_impl (kms);
 | 
			
		||||
 | 
			
		||||
  for (l = kms->devices; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaKmsDevice *device = l->data;
 | 
			
		||||
      MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
 | 
			
		||||
 | 
			
		||||
      meta_kms_impl_device_update_states (impl_device);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
update_states_in_impl (MetaKmsImpl  *impl,
 | 
			
		||||
                       gpointer      user_data,
 | 
			
		||||
                       GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKms *kms = user_data;
 | 
			
		||||
 | 
			
		||||
  meta_kms_update_states_in_impl (kms);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_kms_update_states_sync (MetaKms  *kms,
 | 
			
		||||
                             GError  **error)
 | 
			
		||||
{
 | 
			
		||||
  return meta_kms_run_impl_task_sync (kms,
 | 
			
		||||
                                      update_states_in_impl,
 | 
			
		||||
                                      kms,
 | 
			
		||||
                                      error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_udev_hotplug (MetaUdev *udev,
 | 
			
		||||
                 MetaKms  *kms)
 | 
			
		||||
{
 | 
			
		||||
  g_autoptr (GError) error = NULL;
 | 
			
		||||
 | 
			
		||||
  if (!meta_kms_update_states_sync (kms, &error))
 | 
			
		||||
    g_warning ("Updating KMS state failed: %s", error->message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaBackend *
 | 
			
		||||
meta_kms_get_backend (MetaKms *kms)
 | 
			
		||||
{
 | 
			
		||||
  return kms->backend;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice *
 | 
			
		||||
meta_kms_create_device (MetaKms            *kms,
 | 
			
		||||
                        const char         *path,
 | 
			
		||||
                        MetaKmsDeviceFlag   flags,
 | 
			
		||||
                        GError            **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaKmsDevice *device;
 | 
			
		||||
 | 
			
		||||
  device = meta_kms_device_new (kms, path, flags, error);
 | 
			
		||||
  if (!device)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  kms->devices = g_list_append (kms->devices, device);
 | 
			
		||||
 | 
			
		||||
  return device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaKms *
 | 
			
		||||
meta_kms_new (MetaBackend  *backend,
 | 
			
		||||
              GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
 | 
			
		||||
  MetaUdev *udev = meta_backend_native_get_udev (backend_native);
 | 
			
		||||
  MetaKms *kms;
 | 
			
		||||
 | 
			
		||||
  kms = g_object_new (META_TYPE_KMS, NULL);
 | 
			
		||||
  kms->backend = backend;
 | 
			
		||||
  kms->impl = META_KMS_IMPL (meta_kms_impl_simple_new (kms, error));
 | 
			
		||||
  if (!kms->impl)
 | 
			
		||||
    {
 | 
			
		||||
      g_object_unref (kms);
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  kms->hotplug_handler_id =
 | 
			
		||||
    g_signal_connect (udev, "hotplug", G_CALLBACK (on_udev_hotplug), kms);
 | 
			
		||||
 | 
			
		||||
  return kms;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaKms *kms = META_KMS (object);
 | 
			
		||||
  MetaBackendNative *backend_native = META_BACKEND_NATIVE (kms->backend);
 | 
			
		||||
  MetaUdev *udev = meta_backend_native_get_udev (backend_native);
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = kms->pending_callbacks; l; l = l->next)
 | 
			
		||||
    meta_kms_callback_data_free (l->data);
 | 
			
		||||
  g_list_free (kms->pending_callbacks);
 | 
			
		||||
 | 
			
		||||
  g_clear_handle_id (&kms->callback_source_id, g_source_remove);
 | 
			
		||||
 | 
			
		||||
  g_list_free_full (kms->devices, g_object_unref);
 | 
			
		||||
 | 
			
		||||
  if (kms->hotplug_handler_id)
 | 
			
		||||
    g_signal_handler_disconnect (udev, kms->hotplug_handler_id);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_kms_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_init (MetaKms *kms)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_kms_class_init (MetaKmsClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_kms_finalize;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								src/backends/native/meta-kms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/backends/native/meta-kms.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 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_KMS_H
 | 
			
		||||
#define META_KMS_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_KMS (meta_kms_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaKms, meta_kms, META, KMS, GObject)
 | 
			
		||||
 | 
			
		||||
MetaKmsUpdate * meta_kms_ensure_pending_update (MetaKms *kms);
 | 
			
		||||
 | 
			
		||||
MetaKmsUpdate * meta_kms_get_pending_update (MetaKms *kms);
 | 
			
		||||
 | 
			
		||||
gboolean meta_kms_post_pending_update_sync (MetaKms  *kms,
 | 
			
		||||
                                            GError  **error);
 | 
			
		||||
 | 
			
		||||
void meta_kms_discard_pending_page_flips (MetaKms *kms);
 | 
			
		||||
 | 
			
		||||
MetaBackend * meta_kms_get_backend (MetaKms *kms);
 | 
			
		||||
 | 
			
		||||
MetaKmsDevice * meta_kms_create_device (MetaKms            *kms,
 | 
			
		||||
                                        const char         *path,
 | 
			
		||||
                                        MetaKmsDeviceFlag   flags,
 | 
			
		||||
                                        GError            **error);
 | 
			
		||||
 | 
			
		||||
MetaKms * meta_kms_new (MetaBackend  *backend,
 | 
			
		||||
                        GError      **error);
 | 
			
		||||
 | 
			
		||||
#endif /* META_KMS_H */
 | 
			
		||||
@@ -54,6 +54,8 @@
 | 
			
		||||
#include "backends/native/meta-backend-native.h"
 | 
			
		||||
#include "backends/native/meta-crtc-kms.h"
 | 
			
		||||
#include "backends/native/meta-gpu-kms.h"
 | 
			
		||||
#include "backends/native/meta-kms-update.h"
 | 
			
		||||
#include "backends/native/meta-kms.h"
 | 
			
		||||
#include "backends/native/meta-launcher.h"
 | 
			
		||||
#include "backends/native/meta-output-kms.h"
 | 
			
		||||
#include "backends/native/meta-renderer-native.h"
 | 
			
		||||
@@ -61,17 +63,6 @@
 | 
			
		||||
#include "meta/main.h"
 | 
			
		||||
#include "meta/meta-x11-errors.h"
 | 
			
		||||
 | 
			
		||||
#define DRM_CARD_UDEV_DEVICE_TYPE "drm_minor"
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  GPU_ADDED,
 | 
			
		||||
 | 
			
		||||
  LAST_SIGNAL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static guint signals[LAST_SIGNAL] = { 0 };
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GSource source;
 | 
			
		||||
@@ -84,8 +75,7 @@ struct _MetaMonitorManagerKms
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager parent_instance;
 | 
			
		||||
 | 
			
		||||
  GUdevClient *udev;
 | 
			
		||||
  guint uevent_handler_id;
 | 
			
		||||
  guint hotplug_handler_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorManagerKmsClass
 | 
			
		||||
@@ -127,6 +117,11 @@ static void
 | 
			
		||||
meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
 | 
			
		||||
                                              MetaPowerSave       mode)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
 | 
			
		||||
  MetaKms *kms = meta_backend_native_get_kms (backend_native);
 | 
			
		||||
  MetaKmsUpdate *kms_update;
 | 
			
		||||
  g_autoptr (GError) error = NULL;
 | 
			
		||||
  uint64_t state;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
@@ -147,12 +142,16 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (l = manager->gpus; l; l = l->next)
 | 
			
		||||
  kms_update = meta_kms_ensure_pending_update (kms);
 | 
			
		||||
  for (l = meta_backend_get_gpus (backend); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpuKms *gpu_kms = l->data;
 | 
			
		||||
 | 
			
		||||
      meta_gpu_kms_set_power_save_mode (gpu_kms, state);
 | 
			
		||||
      meta_gpu_kms_set_power_save_mode (gpu_kms, state, kms_update);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!meta_kms_post_pending_update_sync (kms, &error))
 | 
			
		||||
    g_warning ("Failed to DPMS: %s", error->message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -172,7 +171,9 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
                        MetaOutputInfo     **outputs,
 | 
			
		||||
                        unsigned int         n_outputs)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
  unsigned i;
 | 
			
		||||
  GList *gpus;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_crtcs; i++)
 | 
			
		||||
@@ -224,12 +225,11 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
              meta_output_assign_crtc (output, crtc);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_crtc_kms_apply_transform (crtc);
 | 
			
		||||
    }
 | 
			
		||||
  /* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE,
 | 
			
		||||
     because they weren't seen in the first loop) */
 | 
			
		||||
  for (l = manager->gpus; l; l = l->next)
 | 
			
		||||
  gpus = meta_backend_get_gpus (backend);
 | 
			
		||||
  for (l = gpus; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpu *gpu = l->data;
 | 
			
		||||
      GList *k;
 | 
			
		||||
@@ -262,12 +262,10 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
      output->is_primary = output_info->is_primary;
 | 
			
		||||
      output->is_presentation = output_info->is_presentation;
 | 
			
		||||
      output->is_underscanning = output_info->is_underscanning;
 | 
			
		||||
 | 
			
		||||
      meta_output_kms_set_underscan (output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable outputs not mentioned in the list */
 | 
			
		||||
  for (l = manager->gpus; l; l = l->next)
 | 
			
		||||
  for (l = gpus; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpu *gpu = l->data;
 | 
			
		||||
      GList *k;
 | 
			
		||||
@@ -369,20 +367,8 @@ meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager  *manager,
 | 
			
		||||
                                         unsigned short     **green,
 | 
			
		||||
                                         unsigned short     **blue)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = meta_crtc_get_gpu (crtc);
 | 
			
		||||
  int kms_fd = meta_gpu_kms_get_fd (META_GPU_KMS (gpu));
 | 
			
		||||
  drmModeCrtc *kms_crtc;
 | 
			
		||||
 | 
			
		||||
  kms_crtc = drmModeGetCrtc (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 (kms_fd, crtc->crtc_id, *size, *red, *green, *blue);
 | 
			
		||||
 | 
			
		||||
  drmModeFreeCrtc (kms_crtc);
 | 
			
		||||
  meta_kms_crtc_get_gamma (meta_crtc_kms_get_kms_crtc (crtc),
 | 
			
		||||
                           size, red, green, blue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -393,10 +379,19 @@ meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
 | 
			
		||||
                                         unsigned short     *green,
 | 
			
		||||
                                         unsigned short     *blue)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = meta_crtc_get_gpu (crtc);
 | 
			
		||||
  int kms_fd = meta_gpu_kms_get_fd (META_GPU_KMS (gpu));
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
 | 
			
		||||
  MetaKms *kms = meta_backend_native_get_kms (backend_native);
 | 
			
		||||
  MetaKmsUpdate *kms_update;
 | 
			
		||||
  g_autoptr (GError) error = NULL;
 | 
			
		||||
 | 
			
		||||
  drmModeCrtcSetGamma (kms_fd, crtc->crtc_id, size, red, green, blue);
 | 
			
		||||
  kms_update = meta_kms_ensure_pending_update (kms);
 | 
			
		||||
  meta_kms_update_set_crtc_gamma (kms_update,
 | 
			
		||||
                                  meta_crtc_kms_get_kms_crtc (crtc),
 | 
			
		||||
                                  size, red, green, blue);
 | 
			
		||||
 | 
			
		||||
  if (!meta_kms_post_pending_update_sync (kms, &error))
 | 
			
		||||
    g_warning ("Failed to set CRTC gamma: %s", error->message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -407,107 +402,46 @@ handle_hotplug_event (MetaMonitorManager *manager)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
handle_gpu_hotplug (MetaMonitorManagerKms *manager_kms,
 | 
			
		||||
                    GUdevDevice           *device)
 | 
			
		||||
on_udev_hotplug (MetaUdev           *udev,
 | 
			
		||||
                 MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
 | 
			
		||||
  g_autoptr (GError) error = NULL;
 | 
			
		||||
  const char *gpu_path;
 | 
			
		||||
  MetaGpuKms *gpu_kms;
 | 
			
		||||
  GList *gpus, *l;
 | 
			
		||||
 | 
			
		||||
  gpu_path = g_udev_device_get_device_file (device);
 | 
			
		||||
 | 
			
		||||
  gpus = meta_monitor_manager_get_gpus (manager);
 | 
			
		||||
  for (l = gpus; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpuKms *gpu_kms = l->data;
 | 
			
		||||
 | 
			
		||||
      if (!g_strcmp0 (gpu_path, meta_gpu_kms_get_file_path (gpu_kms)))
 | 
			
		||||
        {
 | 
			
		||||
          g_warning ("Failed to hotplug secondary gpu '%s': %s",
 | 
			
		||||
                     gpu_path, "device already present");
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  gpu_kms = meta_gpu_kms_new (manager_kms, gpu_path,
 | 
			
		||||
                              META_GPU_KMS_FLAG_NONE, &error);
 | 
			
		||||
  if (!gpu_kms)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to hotplug secondary gpu '%s': %s",
 | 
			
		||||
                 gpu_path, error->message);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  meta_monitor_manager_add_gpu (manager, META_GPU (gpu_kms));
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (manager_kms, signals[GPU_ADDED], 0, gpu_kms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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_str_equal (action, "add") &&
 | 
			
		||||
      g_udev_device_get_device_file (device) != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
      MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
 | 
			
		||||
      MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
 | 
			
		||||
      const char *device_seat;
 | 
			
		||||
      const char *seat_id;
 | 
			
		||||
 | 
			
		||||
      device_seat = g_udev_device_get_property (device, "ID_SEAT");
 | 
			
		||||
      seat_id = meta_launcher_get_seat_id (launcher);
 | 
			
		||||
 | 
			
		||||
      if (!device_seat)
 | 
			
		||||
        device_seat = "seat0";
 | 
			
		||||
 | 
			
		||||
      if (!g_strcmp0 (seat_id, device_seat))
 | 
			
		||||
        handle_gpu_hotplug (manager_kms, device);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!g_udev_device_get_property_as_boolean (device, "HOTPLUG"))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  handle_hotplug_event (manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_connect_uevent_handler (MetaMonitorManagerKms *manager_kms)
 | 
			
		||||
meta_monitor_manager_kms_connect_hotplug_handler (MetaMonitorManagerKms *manager_kms)
 | 
			
		||||
{
 | 
			
		||||
  manager_kms->uevent_handler_id = g_signal_connect (manager_kms->udev,
 | 
			
		||||
                                                     "uevent",
 | 
			
		||||
                                                     G_CALLBACK (on_uevent),
 | 
			
		||||
                                                     manager_kms);
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
  MetaUdev *udev = meta_backend_native_get_udev (META_BACKEND_NATIVE (backend));
 | 
			
		||||
 | 
			
		||||
  manager_kms->hotplug_handler_id =
 | 
			
		||||
    g_signal_connect_after (udev, "hotplug",
 | 
			
		||||
                            G_CALLBACK (on_udev_hotplug), manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_disconnect_uevent_handler (MetaMonitorManagerKms *manager_kms)
 | 
			
		||||
meta_monitor_manager_kms_disconnect_hotplug_handler (MetaMonitorManagerKms *manager_kms)
 | 
			
		||||
{
 | 
			
		||||
  g_signal_handler_disconnect (manager_kms->udev,
 | 
			
		||||
                               manager_kms->uevent_handler_id);
 | 
			
		||||
  manager_kms->uevent_handler_id = 0;
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
  MetaUdev *udev = meta_backend_native_get_udev (META_BACKEND_NATIVE (backend));
 | 
			
		||||
 | 
			
		||||
  g_signal_handler_disconnect (udev, manager_kms->hotplug_handler_id);
 | 
			
		||||
  manager_kms->hotplug_handler_id = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_kms_pause (MetaMonitorManagerKms *manager_kms)
 | 
			
		||||
{
 | 
			
		||||
  meta_monitor_manager_kms_disconnect_uevent_handler (manager_kms);
 | 
			
		||||
  meta_monitor_manager_kms_disconnect_hotplug_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);
 | 
			
		||||
  meta_monitor_manager_kms_connect_hotplug_handler (manager_kms);
 | 
			
		||||
  handle_hotplug_event (META_MONITOR_MANAGER (manager_kms));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
@@ -593,112 +527,6 @@ meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager)
 | 
			
		||||
    return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
init_gpus (MetaMonitorManagerKms  *manager_kms,
 | 
			
		||||
           GError                **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
 | 
			
		||||
  MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
 | 
			
		||||
  g_autoptr (GUdevEnumerator) enumerator = NULL;
 | 
			
		||||
  const char *seat_id;
 | 
			
		||||
  GList *devices;
 | 
			
		||||
  GList *l;
 | 
			
		||||
  MetaGpuKmsFlag flags = META_GPU_KMS_FLAG_NONE;
 | 
			
		||||
 | 
			
		||||
  enumerator = g_udev_enumerator_new (manager_kms->udev);
 | 
			
		||||
 | 
			
		||||
  g_udev_enumerator_add_match_name (enumerator, "card*");
 | 
			
		||||
  g_udev_enumerator_add_match_tag (enumerator, "seat");
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * We need to explicitly match the subsystem for now.
 | 
			
		||||
   * https://bugzilla.gnome.org/show_bug.cgi?id=773224
 | 
			
		||||
   */
 | 
			
		||||
  g_udev_enumerator_add_match_subsystem (enumerator, "drm");
 | 
			
		||||
 | 
			
		||||
  devices = g_udev_enumerator_execute (enumerator);
 | 
			
		||||
  if (!devices)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                   "No GPUs found with udev");
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  seat_id = meta_launcher_get_seat_id (launcher);
 | 
			
		||||
 | 
			
		||||
  for (l = devices; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      GUdevDevice *dev = l->data;
 | 
			
		||||
      MetaGpuKms *gpu_kms;
 | 
			
		||||
      g_autoptr (GUdevDevice) platform_device = NULL;
 | 
			
		||||
      g_autoptr (GUdevDevice) pci_device = NULL;
 | 
			
		||||
      const char *device_path;
 | 
			
		||||
      const char *device_type;
 | 
			
		||||
      const char *device_seat;
 | 
			
		||||
      GError *local_error = NULL;
 | 
			
		||||
 | 
			
		||||
      /* Filter out devices that are not character device, like card0-VGA-1. */
 | 
			
		||||
      if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      device_type = g_udev_device_get_property (dev, "DEVTYPE");
 | 
			
		||||
      if (g_strcmp0 (device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      device_path = g_udev_device_get_device_file (dev);
 | 
			
		||||
 | 
			
		||||
      device_seat = g_udev_device_get_property (dev, "ID_SEAT");
 | 
			
		||||
      if (!device_seat)
 | 
			
		||||
        {
 | 
			
		||||
          /* When ID_SEAT is not set, it means seat0. */
 | 
			
		||||
          device_seat = "seat0";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* Skip devices that do not belong to our seat. */
 | 
			
		||||
      if (g_strcmp0 (seat_id, device_seat))
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      platform_device = g_udev_device_get_parent_with_subsystem (dev,
 | 
			
		||||
                                                                 "platform",
 | 
			
		||||
                                                                 NULL);
 | 
			
		||||
      if (platform_device != NULL)
 | 
			
		||||
        flags |= META_GPU_KMS_FLAG_PLATFORM_DEVICE;
 | 
			
		||||
 | 
			
		||||
      pci_device = g_udev_device_get_parent_with_subsystem (dev, "pci", NULL);
 | 
			
		||||
      if (pci_device != NULL)
 | 
			
		||||
        {
 | 
			
		||||
          if (g_udev_device_get_sysfs_attr_as_int (pci_device,
 | 
			
		||||
                                                   "boot_vga") == 1)
 | 
			
		||||
            flags |= META_GPU_KMS_FLAG_BOOT_VGA;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      gpu_kms = meta_gpu_kms_new (manager_kms, device_path, flags,
 | 
			
		||||
                                  &local_error);
 | 
			
		||||
      if (!gpu_kms)
 | 
			
		||||
        {
 | 
			
		||||
          g_warning ("Failed to open gpu '%s': %s",
 | 
			
		||||
                     device_path, local_error->message);
 | 
			
		||||
          g_clear_error (&local_error);
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_monitor_manager_add_gpu (manager, META_GPU (gpu_kms));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_list_free_full (devices, g_object_unref);
 | 
			
		||||
 | 
			
		||||
  if (!meta_monitor_manager_get_gpus (manager))
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                   "No GPUs found");
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_monitor_manager_kms_initable_init (GInitable    *initable,
 | 
			
		||||
                                        GCancellable *cancellable,
 | 
			
		||||
@@ -706,21 +534,14 @@ meta_monitor_manager_kms_initable_init (GInitable    *initable,
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (initable);
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
 | 
			
		||||
  const char *subsystems[2] = { "drm", NULL };
 | 
			
		||||
  GList *l;
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
  gboolean can_have_outputs;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  manager_kms->udev = g_udev_client_new (subsystems);
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_kms_connect_uevent_handler (manager_kms);
 | 
			
		||||
 | 
			
		||||
  if (!init_gpus (manager_kms, error))
 | 
			
		||||
    {
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
  meta_monitor_manager_kms_connect_hotplug_handler (manager_kms);
 | 
			
		||||
 | 
			
		||||
  can_have_outputs = FALSE;
 | 
			
		||||
  for (l = meta_monitor_manager_get_gpus (manager); l; l = l->next)
 | 
			
		||||
  for (l = meta_backend_get_gpus (backend); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaGpuKms *gpu_kms = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -746,16 +567,6 @@ initable_iface_init (GInitableIface *initable_iface)
 | 
			
		||||
  initable_iface->init = meta_monitor_manager_kms_initable_init;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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_init (MetaMonitorManagerKms *manager_kms)
 | 
			
		||||
{
 | 
			
		||||
@@ -765,9 +576,6 @@ 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;
 | 
			
		||||
 | 
			
		||||
  manager_class->read_edid = meta_monitor_manager_kms_read_edid;
 | 
			
		||||
  manager_class->read_current_state = meta_monitor_manager_kms_read_current_state;
 | 
			
		||||
@@ -782,12 +590,4 @@ meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
  signals[GPU_ADDED] =
 | 
			
		||||
    g_signal_new ("gpu-added",
 | 
			
		||||
                  G_TYPE_FROM_CLASS (object_class),
 | 
			
		||||
                  G_SIGNAL_RUN_LAST,
 | 
			
		||||
                  0,
 | 
			
		||||
                  NULL, NULL, NULL,
 | 
			
		||||
                  G_TYPE_NONE, 1, META_TYPE_GPU_KMS);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,8 @@
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-crtc.h"
 | 
			
		||||
#include "backends/native/meta-kms-connector.h"
 | 
			
		||||
#include "backends/native/meta-kms-utils.h"
 | 
			
		||||
#include "backends/native/meta-crtc-kms.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-default-modes.h"
 | 
			
		||||
@@ -39,85 +41,51 @@ 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;
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  MetaKmsConnector *kms_connector;
 | 
			
		||||
} MetaOutputKms;
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_output_kms_set_underscan (MetaOutput *output)
 | 
			
		||||
MetaKmsConnector *
 | 
			
		||||
meta_output_kms_get_kms_connector (MetaOutput *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutputKms *output_kms = output->driver_private;
 | 
			
		||||
  MetaGpu *gpu = meta_output_get_gpu (output);
 | 
			
		||||
  MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
 | 
			
		||||
  MetaCrtc *crtc;
 | 
			
		||||
  int kms_fd;
 | 
			
		||||
  uint32_t connector_id;
 | 
			
		||||
 | 
			
		||||
  if (!output_kms->underscan_prop_id)
 | 
			
		||||
  return output_kms->kms_connector;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_output_kms_set_underscan (MetaOutput    *output,
 | 
			
		||||
                               MetaKmsUpdate *kms_update)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutputKms *output_kms = output->driver_private;
 | 
			
		||||
 | 
			
		||||
  if (!output->supports_underscanning)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (output->is_underscanning)
 | 
			
		||||
    {
 | 
			
		||||
      MetaCrtc *crtc;
 | 
			
		||||
      uint64_t hborder, vborder;
 | 
			
		||||
 | 
			
		||||
      crtc = meta_output_get_assigned_crtc (output);
 | 
			
		||||
  kms_fd = meta_gpu_kms_get_fd (gpu_kms);
 | 
			
		||||
  connector_id = output_kms->connector->connector_id;
 | 
			
		||||
      hborder = MIN (128, (uint64_t) round (crtc->current_mode->width * 0.05));
 | 
			
		||||
      vborder = MIN (128, (uint64_t) round (crtc->current_mode->height * 0.05));
 | 
			
		||||
 | 
			
		||||
  if (output->is_underscanning && crtc && crtc->current_mode)
 | 
			
		||||
    {
 | 
			
		||||
      drmModeObjectSetProperty (kms_fd, connector_id,
 | 
			
		||||
                                DRM_MODE_OBJECT_CONNECTOR,
 | 
			
		||||
                                output_kms->underscan_prop_id,
 | 
			
		||||
                                (uint64_t) 1);
 | 
			
		||||
      g_debug ("Setting underscan of connector %s to %lu x %lu",
 | 
			
		||||
               meta_kms_connector_get_name (output_kms->kms_connector),
 | 
			
		||||
               hborder, vborder);
 | 
			
		||||
 | 
			
		||||
      if (output_kms->underscan_hborder_prop_id)
 | 
			
		||||
        {
 | 
			
		||||
          uint64_t value;
 | 
			
		||||
 | 
			
		||||
          value = MIN (128, crtc->current_mode->width * 0.05);
 | 
			
		||||
          drmModeObjectSetProperty (kms_fd, connector_id,
 | 
			
		||||
                                    DRM_MODE_OBJECT_CONNECTOR,
 | 
			
		||||
                                    output_kms->underscan_hborder_prop_id,
 | 
			
		||||
                                    value);
 | 
			
		||||
        }
 | 
			
		||||
      if (output_kms->underscan_vborder_prop_id)
 | 
			
		||||
        {
 | 
			
		||||
          uint64_t value;
 | 
			
		||||
 | 
			
		||||
          value = MIN (128, crtc->current_mode->height * 0.05);
 | 
			
		||||
          drmModeObjectSetProperty (kms_fd, connector_id,
 | 
			
		||||
                                    DRM_MODE_OBJECT_CONNECTOR,
 | 
			
		||||
                                    output_kms->underscan_vborder_prop_id,
 | 
			
		||||
                                    value);
 | 
			
		||||
        }
 | 
			
		||||
      meta_kms_connector_set_underscanning (output_kms->kms_connector,
 | 
			
		||||
                                            kms_update,
 | 
			
		||||
                                            hborder,
 | 
			
		||||
                                            vborder);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      drmModeObjectSetProperty (kms_fd, connector_id,
 | 
			
		||||
                                DRM_MODE_OBJECT_CONNECTOR,
 | 
			
		||||
                                output_kms->underscan_prop_id,
 | 
			
		||||
                                (uint64_t) 0);
 | 
			
		||||
      g_debug ("Unsetting underscan of connector %s",
 | 
			
		||||
               meta_kms_connector_get_name (output_kms->kms_connector));
 | 
			
		||||
 | 
			
		||||
      meta_kms_connector_unset_underscanning (output_kms->kms_connector,
 | 
			
		||||
                                              kms_update);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -126,28 +94,23 @@ meta_output_kms_get_connector_id (MetaOutput *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutputKms *output_kms = output->driver_private;
 | 
			
		||||
 | 
			
		||||
  return output_kms->connector->connector_id;
 | 
			
		||||
  return meta_kms_connector_get_id (output_kms->kms_connector);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_output_kms_set_power_save_mode (MetaOutput    *output,
 | 
			
		||||
                                     uint64_t    state)
 | 
			
		||||
                                     uint64_t       dpms_state,
 | 
			
		||||
                                     MetaKmsUpdate *kms_update)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutputKms *output_kms = output->driver_private;
 | 
			
		||||
  MetaGpu *gpu = meta_output_get_gpu (output);
 | 
			
		||||
  MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
 | 
			
		||||
 | 
			
		||||
  if (output_kms->dpms_prop_id != 0)
 | 
			
		||||
    {
 | 
			
		||||
      int fd;
 | 
			
		||||
  g_debug ("Setting DPMS state of connector %s to %lu",
 | 
			
		||||
           meta_kms_connector_get_name (output_kms->kms_connector),
 | 
			
		||||
           dpms_state);
 | 
			
		||||
 | 
			
		||||
      fd = meta_gpu_kms_get_fd (gpu_kms);
 | 
			
		||||
      if (drmModeObjectSetProperty (fd, output_kms->connector->connector_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));
 | 
			
		||||
    }
 | 
			
		||||
  meta_kms_connector_update_set_dpms_state (output_kms->kms_connector,
 | 
			
		||||
                                            kms_update,
 | 
			
		||||
                                            dpms_state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
@@ -157,266 +120,33 @@ 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;
 | 
			
		||||
  drmModePropertyBlobPtr tile_blob = NULL;
 | 
			
		||||
 | 
			
		||||
  if (output_kms->tile_blob_id == 0)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  fd = meta_gpu_kms_get_fd (gpu_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;
 | 
			
		||||
    }
 | 
			
		||||
  return meta_kms_connector_can_clone (output_kms->kms_connector,
 | 
			
		||||
                                       other_output_kms->kms_connector);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBytes *
 | 
			
		||||
meta_output_kms_read_edid (MetaOutput *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutputKms *output_kms = output->driver_private;
 | 
			
		||||
  MetaGpu *gpu = meta_output_get_gpu (output);
 | 
			
		||||
  MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  GBytes *edid;
 | 
			
		||||
  const MetaKmsConnectorState *connector_state;
 | 
			
		||||
  GBytes *edid_data;
 | 
			
		||||
 | 
			
		||||
  if (output_kms->edid_blob_id == 0)
 | 
			
		||||
  connector_state =
 | 
			
		||||
    meta_kms_connector_get_current_state (output_kms->kms_connector);
 | 
			
		||||
  edid_data = connector_state->edid_data;
 | 
			
		||||
  if (!edid_data)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  edid = read_output_edid (gpu_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
 | 
			
		||||
handle_panel_orientation (MetaOutput        *output,
 | 
			
		||||
                          drmModePropertyPtr prop,
 | 
			
		||||
                          int                orientation)
 | 
			
		||||
{
 | 
			
		||||
  const char *name = prop->enums[orientation].name;
 | 
			
		||||
 | 
			
		||||
  if (strcmp (name, "Upside Down") == 0)
 | 
			
		||||
    {
 | 
			
		||||
      output->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 */
 | 
			
		||||
      output->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 */
 | 
			
		||||
      output->panel_orientation_transform = META_MONITOR_TRANSFORM_270;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      output->panel_orientation_transform = META_MONITOR_TRANSFORM_NORMAL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
find_connector_properties (MetaGpuKms    *gpu_kms,
 | 
			
		||||
                           MetaOutput    *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutputKms *output_kms = output->driver_private;
 | 
			
		||||
  drmModeConnector *connector = output_kms->connector;
 | 
			
		||||
  int fd;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  fd = meta_gpu_kms_get_fd (gpu_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;
 | 
			
		||||
      else if ((prop->flags & DRM_MODE_PROP_ENUM) &&
 | 
			
		||||
               strcmp (prop->name, "panel orientation") == 0)
 | 
			
		||||
        handle_panel_orientation (output, prop,
 | 
			
		||||
                                  output_kms->connector->prop_values[i]);
 | 
			
		||||
      else if ((prop->flags & DRM_MODE_PROP_ENUM) &&
 | 
			
		||||
               strcmp (prop->name, "underscan") == 0)
 | 
			
		||||
        output_kms->underscan_prop_id = prop->prop_id;
 | 
			
		||||
      else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
 | 
			
		||||
               strcmp (prop->name, "underscan hborder") == 0)
 | 
			
		||||
        output_kms->underscan_hborder_prop_id = prop->prop_id;
 | 
			
		||||
      else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
 | 
			
		||||
               strcmp (prop->name, "underscan vborder") == 0)
 | 
			
		||||
        output_kms->underscan_vborder_prop_id = prop->prop_id;
 | 
			
		||||
 | 
			
		||||
      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);
 | 
			
		||||
  return g_bytes_new_from_bytes (edid_data, 0, g_bytes_get_size (edid_data));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -511,20 +241,24 @@ init_output_modes (MetaOutput  *output,
 | 
			
		||||
                   GError     **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutputKms *output_kms = output->driver_private;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
  const MetaKmsConnectorState *connector_state;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  connector_state =
 | 
			
		||||
    meta_kms_connector_get_current_state (output_kms->kms_connector);
 | 
			
		||||
 | 
			
		||||
  output->preferred_mode = NULL;
 | 
			
		||||
  output->n_modes = output_kms->connector->count_modes;
 | 
			
		||||
 | 
			
		||||
  output->n_modes = connector_state->n_modes;
 | 
			
		||||
  output->modes = g_new0 (MetaCrtcMode *, output->n_modes);
 | 
			
		||||
  for (i = 0; i < output->n_modes; i++)
 | 
			
		||||
  for (i = 0; i < connector_state->n_modes; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModeModeInfo *drm_mode;
 | 
			
		||||
      drmModeModeInfo *drm_mode = &connector_state->modes[i];
 | 
			
		||||
      MetaCrtcMode *crtc_mode;
 | 
			
		||||
 | 
			
		||||
      drm_mode = &output_kms->connector->modes[i];
 | 
			
		||||
      crtc_mode = meta_gpu_kms_get_mode_from_drm_mode (gpu_kms, drm_mode);
 | 
			
		||||
      output->modes[i] = crtc_mode;
 | 
			
		||||
      if (output_kms->connector->modes[i].type & DRM_MODE_TYPE_PREFERRED)
 | 
			
		||||
      if (drm_mode->type & DRM_MODE_TYPE_PREFERRED)
 | 
			
		||||
        output->preferred_mode = output->modes[i];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -532,7 +266,7 @@ init_output_modes (MetaOutput  *output,
 | 
			
		||||
  /* 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)
 | 
			
		||||
  if (connector_state->has_scaling)
 | 
			
		||||
    add_common_modes (output, gpu_kms);
 | 
			
		||||
 | 
			
		||||
  if (!output->modes)
 | 
			
		||||
@@ -553,21 +287,19 @@ init_output_modes (MetaOutput  *output,
 | 
			
		||||
 | 
			
		||||
MetaOutput *
 | 
			
		||||
meta_create_kms_output (MetaGpuKms        *gpu_kms,
 | 
			
		||||
                        drmModeConnector  *connector,
 | 
			
		||||
                        MetaKmsResources  *resources,
 | 
			
		||||
                        MetaKmsConnector  *kms_connector,
 | 
			
		||||
                        MetaOutput        *old_output,
 | 
			
		||||
                        GError           **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = META_GPU (gpu_kms);
 | 
			
		||||
  MetaOutput *output;
 | 
			
		||||
  MetaOutputKms *output_kms;
 | 
			
		||||
  const MetaKmsConnectorState *connector_state;
 | 
			
		||||
  MetaMonitorTransform panel_orientation_transform;
 | 
			
		||||
  uint32_t connector_id;
 | 
			
		||||
  GArray *crtcs;
 | 
			
		||||
  GBytes *edid;
 | 
			
		||||
  GList *l;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
  unsigned int crtc_mask;
 | 
			
		||||
  int fd;
 | 
			
		||||
  uint32_t id;
 | 
			
		||||
  uint32_t gpu_id;
 | 
			
		||||
 | 
			
		||||
  output = g_object_new (META_TYPE_OUTPUT, NULL);
 | 
			
		||||
 | 
			
		||||
@@ -576,46 +308,26 @@ meta_create_kms_output (MetaGpuKms        *gpu_kms,
 | 
			
		||||
  output->driver_notify = (GDestroyNotify) meta_output_destroy_notify;
 | 
			
		||||
 | 
			
		||||
  output->gpu = gpu;
 | 
			
		||||
  output->name = make_output_name (connector);
 | 
			
		||||
  output->name = g_strdup (meta_kms_connector_get_name (kms_connector));
 | 
			
		||||
 | 
			
		||||
  id = meta_gpu_kms_get_id (gpu_kms);
 | 
			
		||||
  output->winsys_id = ((uint64_t) id << 32) | connector->connector_id;
 | 
			
		||||
  gpu_id = meta_gpu_kms_get_id (gpu_kms);
 | 
			
		||||
  connector_id = meta_kms_connector_get_id (kms_connector);
 | 
			
		||||
  output->winsys_id = ((uint64_t) gpu_id << 32) | connector_id;
 | 
			
		||||
 | 
			
		||||
  switch (connector->subpixel)
 | 
			
		||||
  output_kms->kms_connector = kms_connector;
 | 
			
		||||
 | 
			
		||||
  connector_state = meta_kms_connector_get_current_state (kms_connector);
 | 
			
		||||
 | 
			
		||||
  panel_orientation_transform = connector_state->panel_orientation_transform;
 | 
			
		||||
  if (meta_monitor_transform_is_rotated (panel_orientation_transform))
 | 
			
		||||
    {
 | 
			
		||||
    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 (gpu_kms, output);
 | 
			
		||||
 | 
			
		||||
  if (meta_monitor_transform_is_rotated (output->panel_orientation_transform))
 | 
			
		||||
    {
 | 
			
		||||
      output->width_mm = connector->mmHeight;
 | 
			
		||||
      output->height_mm = connector->mmWidth;
 | 
			
		||||
      output->width_mm = connector_state->height_mm;
 | 
			
		||||
      output->height_mm = connector_state->width_mm;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      output->width_mm = connector->mmWidth;
 | 
			
		||||
      output->height_mm = connector->mmHeight;
 | 
			
		||||
      output->width_mm = connector_state->width_mm;
 | 
			
		||||
      output->height_mm = connector_state->height_mm;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!init_output_modes (output, gpu_kms, error))
 | 
			
		||||
@@ -624,51 +336,29 @@ meta_create_kms_output (MetaGpuKms        *gpu_kms,
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  output_kms->n_encoders = connector->count_encoders;
 | 
			
		||||
  output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
 | 
			
		||||
 | 
			
		||||
  fd = meta_gpu_kms_get_fd (gpu_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 = meta_gpu_get_crtcs (gpu), i = 0; l; l = l->next, i++)
 | 
			
		||||
    {
 | 
			
		||||
      if (crtc_mask & (1 << i))
 | 
			
		||||
  for (l = meta_gpu_get_crtcs (gpu); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaCrtc *crtc = l->data;
 | 
			
		||||
      MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc);
 | 
			
		||||
      uint32_t crtc_idx;
 | 
			
		||||
 | 
			
		||||
      crtc_idx = meta_kms_crtc_get_idx (kms_crtc);
 | 
			
		||||
      if (connector_state->common_possible_crtcs & (1 << crtc_idx))
 | 
			
		||||
        g_array_append_val (crtcs, crtc);
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  output->n_possible_crtcs = crtcs->len;
 | 
			
		||||
  output->possible_crtcs = (void*)g_array_free (crtcs, FALSE);
 | 
			
		||||
  output->possible_crtcs = (MetaCrtc **) g_array_free (crtcs, FALSE);
 | 
			
		||||
 | 
			
		||||
  if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0)
 | 
			
		||||
  if (connector_state->current_crtc_id)
 | 
			
		||||
    {
 | 
			
		||||
      for (l = meta_gpu_get_crtcs (gpu); l; l = l->next)
 | 
			
		||||
        {
 | 
			
		||||
          MetaCrtc *crtc = l->data;
 | 
			
		||||
 | 
			
		||||
          if (crtc->crtc_id == output_kms->current_encoder->crtc_id)
 | 
			
		||||
          if (crtc->crtc_id == connector_state->current_crtc_id)
 | 
			
		||||
            {
 | 
			
		||||
              meta_output_assign_crtc (output, crtc);
 | 
			
		||||
              break;
 | 
			
		||||
@@ -691,35 +381,17 @@ meta_create_kms_output (MetaGpuKms        *gpu_kms,
 | 
			
		||||
      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;
 | 
			
		||||
  output->supports_underscanning = output_kms->underscan_prop_id != 0;
 | 
			
		||||
  output->suggested_x = connector_state->suggested_x;
 | 
			
		||||
  output->suggested_y = connector_state->suggested_y;
 | 
			
		||||
  output->hotplug_mode_update = connector_state->hotplug_mode_update;
 | 
			
		||||
  output->supports_underscanning =
 | 
			
		||||
    meta_kms_connector_is_underscanning_supported (kms_connector);
 | 
			
		||||
 | 
			
		||||
  if (output_kms->edid_blob_id != 0)
 | 
			
		||||
    {
 | 
			
		||||
      GError *error = NULL;
 | 
			
		||||
  meta_output_parse_edid (output, connector_state->edid_data);
 | 
			
		||||
 | 
			
		||||
      edid = read_output_edid (gpu_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;
 | 
			
		||||
    }
 | 
			
		||||
  output->connector_type = meta_kms_connector_get_connector_type (kms_connector);
 | 
			
		||||
 | 
			
		||||
  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 (gpu_kms, output);
 | 
			
		||||
  output->tile_info = connector_state->tile_info;
 | 
			
		||||
 | 
			
		||||
  /* FIXME: backlight is a very driver specific thing unfortunately,
 | 
			
		||||
     every DDX does its own thing, and the dumb KMS API does not include it.
 | 
			
		||||
@@ -734,28 +406,5 @@ meta_create_kms_output (MetaGpuKms        *gpu_kms,
 | 
			
		||||
  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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,22 +25,26 @@
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-output.h"
 | 
			
		||||
#include "backends/native/meta-gpu-kms.h"
 | 
			
		||||
 | 
			
		||||
void meta_output_kms_set_underscan (MetaOutput *output);
 | 
			
		||||
#include "backends/native/meta-kms-types.h"
 | 
			
		||||
 | 
			
		||||
void meta_output_kms_set_power_save_mode (MetaOutput    *output,
 | 
			
		||||
                                          uint64_t    state);
 | 
			
		||||
                                          uint64_t       dpms_state,
 | 
			
		||||
                                          MetaKmsUpdate *kms_update);
 | 
			
		||||
 | 
			
		||||
void meta_output_kms_set_underscan (MetaOutput    *output,
 | 
			
		||||
                                    MetaKmsUpdate *kms_update);
 | 
			
		||||
 | 
			
		||||
gboolean meta_output_kms_can_clone (MetaOutput *output,
 | 
			
		||||
                                    MetaOutput *other_output);
 | 
			
		||||
 | 
			
		||||
MetaKmsConnector * meta_output_kms_get_kms_connector (MetaOutput *output);
 | 
			
		||||
 | 
			
		||||
uint32_t meta_output_kms_get_connector_id (MetaOutput *output);
 | 
			
		||||
 | 
			
		||||
GBytes * meta_output_kms_read_edid (MetaOutput *output);
 | 
			
		||||
 | 
			
		||||
MetaOutput * meta_create_kms_output (MetaGpuKms        *gpu_kms,
 | 
			
		||||
                                     drmModeConnector  *connector,
 | 
			
		||||
                                     MetaKmsResources  *resources,
 | 
			
		||||
                                     MetaKmsConnector  *kms_connector,
 | 
			
		||||
                                     MetaOutput        *old_output,
 | 
			
		||||
                                     GError           **error);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -46,7 +46,7 @@ typedef enum _MetaRendererNativeMode
 | 
			
		||||
#endif
 | 
			
		||||
} MetaRendererNativeMode;
 | 
			
		||||
 | 
			
		||||
MetaRendererNative * meta_renderer_native_new (MetaMonitorManagerKms *monitor_manager_kms,
 | 
			
		||||
MetaRendererNative * meta_renderer_native_new (MetaBackendNative  *backend_native,
 | 
			
		||||
                                               GError            **error);
 | 
			
		||||
 | 
			
		||||
struct gbm_device * meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										226
									
								
								src/backends/native/meta-udev.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								src/backends/native/meta-udev.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,226 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 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-udev.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-backend-native.h"
 | 
			
		||||
#include "backends/native/meta-launcher.h"
 | 
			
		||||
 | 
			
		||||
#define DRM_CARD_UDEV_DEVICE_TYPE "drm_minor"
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  HOTPLUG,
 | 
			
		||||
  DEVICE_ADDED,
 | 
			
		||||
 | 
			
		||||
  N_SIGNALS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static guint signals[N_SIGNALS];
 | 
			
		||||
 | 
			
		||||
struct _MetaUdev
 | 
			
		||||
{
 | 
			
		||||
  GObject parent;
 | 
			
		||||
 | 
			
		||||
  MetaBackendNative *backend_native;
 | 
			
		||||
 | 
			
		||||
  GUdevClient *gudev_client;
 | 
			
		||||
 | 
			
		||||
  guint uevent_handler_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaUdev, meta_udev, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_is_udev_device_platform_device (GUdevDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  g_autoptr (GUdevDevice) platform_device = NULL;
 | 
			
		||||
 | 
			
		||||
  platform_device = g_udev_device_get_parent_with_subsystem (device,
 | 
			
		||||
                                                             "platform",
 | 
			
		||||
                                                             NULL);
 | 
			
		||||
  return !!platform_device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_is_udev_device_boot_vga (GUdevDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  g_autoptr (GUdevDevice) pci_device = NULL;
 | 
			
		||||
 | 
			
		||||
  pci_device = g_udev_device_get_parent_with_subsystem (device, "pci", NULL);
 | 
			
		||||
  if (!pci_device)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  return g_udev_device_get_sysfs_attr_as_int (pci_device, "boot_vga") == 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_udev_is_drm_device (MetaUdev    *udev,
 | 
			
		||||
                         GUdevDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  MetaLauncher *launcher =
 | 
			
		||||
    meta_backend_native_get_launcher (udev->backend_native);
 | 
			
		||||
  const char *seat_id;
 | 
			
		||||
  const char *device_type;
 | 
			
		||||
  const char *device_seat;
 | 
			
		||||
 | 
			
		||||
  /* Filter out devices that are not character device, like card0-VGA-1. */
 | 
			
		||||
  if (g_udev_device_get_device_type (device) != G_UDEV_DEVICE_TYPE_CHAR)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  device_type = g_udev_device_get_property (device, "DEVTYPE");
 | 
			
		||||
  if (g_strcmp0 (device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  device_seat = g_udev_device_get_property (device, "ID_SEAT");
 | 
			
		||||
  if (!device_seat)
 | 
			
		||||
    {
 | 
			
		||||
      /* When ID_SEAT is not set, it means seat0. */
 | 
			
		||||
      device_seat = "seat0";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Skip devices that do not belong to our seat. */
 | 
			
		||||
  seat_id = meta_launcher_get_seat_id (launcher);
 | 
			
		||||
  if (g_strcmp0 (seat_id, device_seat))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GList *
 | 
			
		||||
meta_udev_list_drm_devices (MetaUdev  *udev,
 | 
			
		||||
                            GError   **error)
 | 
			
		||||
{
 | 
			
		||||
  g_autoptr (GUdevEnumerator) enumerator = NULL;
 | 
			
		||||
  GList *devices;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  enumerator = g_udev_enumerator_new (udev->gudev_client);
 | 
			
		||||
 | 
			
		||||
  g_udev_enumerator_add_match_name (enumerator, "card*");
 | 
			
		||||
  g_udev_enumerator_add_match_tag (enumerator, "seat");
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * We need to explicitly match the subsystem for now.
 | 
			
		||||
   * https://bugzilla.gnome.org/show_bug.cgi?id=773224
 | 
			
		||||
   */
 | 
			
		||||
  g_udev_enumerator_add_match_subsystem (enumerator, "drm");
 | 
			
		||||
 | 
			
		||||
  devices = g_udev_enumerator_execute (enumerator);
 | 
			
		||||
  if (!devices)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                   "No drm devices found");
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (l = devices; l;)
 | 
			
		||||
    {
 | 
			
		||||
      GUdevDevice *device = l->data;
 | 
			
		||||
      GList *l_next = l->next;
 | 
			
		||||
 | 
			
		||||
      if (!meta_udev_is_drm_device (udev, device))
 | 
			
		||||
        {
 | 
			
		||||
          g_object_unref (device);
 | 
			
		||||
          devices = g_list_delete_link (devices, l);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      l = l_next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return devices;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_uevent (GUdevClient *client,
 | 
			
		||||
           const char  *action,
 | 
			
		||||
           GUdevDevice *device,
 | 
			
		||||
           gpointer     user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaUdev *udev = META_UDEV (user_data);
 | 
			
		||||
 | 
			
		||||
  if (!g_udev_device_get_device_file (device))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (g_str_equal (action, "add"))
 | 
			
		||||
    g_signal_emit (udev, signals[DEVICE_ADDED], 0, device);
 | 
			
		||||
 | 
			
		||||
  if (g_udev_device_get_property_as_boolean (device, "HOTPLUG"))
 | 
			
		||||
    g_signal_emit (udev, signals[HOTPLUG], 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaUdev *
 | 
			
		||||
meta_udev_new (MetaBackendNative *backend_native)
 | 
			
		||||
{
 | 
			
		||||
  MetaUdev *udev;
 | 
			
		||||
 | 
			
		||||
  udev = g_object_new (META_TYPE_UDEV, NULL);
 | 
			
		||||
  udev->backend_native = backend_native;
 | 
			
		||||
 | 
			
		||||
  return udev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_udev_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaUdev *udev = META_UDEV (object);
 | 
			
		||||
 | 
			
		||||
  g_signal_handler_disconnect (udev->gudev_client, udev->uevent_handler_id);
 | 
			
		||||
  g_clear_object (&udev->gudev_client);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_udev_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_udev_init (MetaUdev *udev)
 | 
			
		||||
{
 | 
			
		||||
  const char *subsystems[] = { "drm", NULL };
 | 
			
		||||
 | 
			
		||||
  udev->gudev_client = g_udev_client_new (subsystems);
 | 
			
		||||
  udev->uevent_handler_id = g_signal_connect (udev->gudev_client,
 | 
			
		||||
                                              "uevent",
 | 
			
		||||
                                              G_CALLBACK (on_uevent), udev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_udev_class_init (MetaUdevClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_udev_finalize;
 | 
			
		||||
 | 
			
		||||
  signals[HOTPLUG] =
 | 
			
		||||
    g_signal_new ("hotplug",
 | 
			
		||||
                  G_TYPE_FROM_CLASS (object_class),
 | 
			
		||||
                  G_SIGNAL_RUN_LAST,
 | 
			
		||||
                  0, NULL, NULL,
 | 
			
		||||
                  g_cclosure_marshal_VOID__VOID,
 | 
			
		||||
                  G_TYPE_NONE, 0);
 | 
			
		||||
  signals[DEVICE_ADDED] =
 | 
			
		||||
    g_signal_new ("device-added",
 | 
			
		||||
                  G_TYPE_FROM_CLASS (object_class),
 | 
			
		||||
                  G_SIGNAL_RUN_LAST,
 | 
			
		||||
                  0, NULL, NULL,
 | 
			
		||||
                  g_cclosure_marshal_VOID__VOID,
 | 
			
		||||
                  G_TYPE_NONE, 1,
 | 
			
		||||
                  G_UDEV_TYPE_DEVICE);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								src/backends/native/meta-udev.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/backends/native/meta-udev.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 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_UDEV_H
 | 
			
		||||
#define META_UDEV_H
 | 
			
		||||
 | 
			
		||||
#include <gudev/gudev.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/native/meta-backend-native-types.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_UDEV (meta_udev_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaUdev, meta_udev, META, UDEV, GObject)
 | 
			
		||||
 | 
			
		||||
gboolean meta_is_udev_device_platform_device (GUdevDevice *device);
 | 
			
		||||
 | 
			
		||||
gboolean meta_is_udev_device_boot_vga (GUdevDevice *device);
 | 
			
		||||
 | 
			
		||||
gboolean meta_udev_is_drm_device (MetaUdev    *udev,
 | 
			
		||||
                                  GUdevDevice *device);
 | 
			
		||||
 | 
			
		||||
GList * meta_udev_list_drm_devices (MetaUdev  *udev,
 | 
			
		||||
                                    GError   **error);
 | 
			
		||||
 | 
			
		||||
MetaUdev * meta_udev_new (MetaBackendNative *backend_native);
 | 
			
		||||
 | 
			
		||||
#endif /* META_UDEV_H */
 | 
			
		||||
@@ -28,6 +28,7 @@
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "backends/x11/meta-cursor-renderer-x11.h"
 | 
			
		||||
#include "backends/x11/meta-gpu-xrandr.h"
 | 
			
		||||
#include "backends/x11/meta-input-settings-x11.h"
 | 
			
		||||
#include "backends/x11/meta-monitor-manager-xrandr.h"
 | 
			
		||||
#include "backends/x11/cm/meta-renderer-x11-cm.h"
 | 
			
		||||
@@ -389,6 +390,16 @@ meta_backend_x11_cm_translate_crossing_event (MetaBackendX11 *x11,
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_x11_cm_init (MetaBackendX11Cm *backend_x11_cm)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpuXrandr *gpu_xrandr;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * The X server deals with multiple GPUs for us, soe just see what the X
 | 
			
		||||
   * server gives us as one single GPU, even though it may actually be backed
 | 
			
		||||
   * by multiple.
 | 
			
		||||
   */
 | 
			
		||||
  gpu_xrandr = meta_gpu_xrandr_new (META_BACKEND_X11 (backend_x11_cm));
 | 
			
		||||
  meta_backend_add_gpu (META_BACKEND (backend_x11_cm),
 | 
			
		||||
                        META_GPU (gpu_xrandr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <xcb/randr.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "backends/meta-crtc.h"
 | 
			
		||||
#include "backends/x11/meta-crtc-xrandr.h"
 | 
			
		||||
#include "backends/x11/meta-gpu-xrandr.h"
 | 
			
		||||
@@ -60,7 +61,9 @@ meta_crtc_xrandr_set_config (MetaCrtc            *crtc,
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = meta_crtc_get_gpu (crtc);
 | 
			
		||||
  MetaGpuXrandr *gpu_xrandr = META_GPU_XRANDR (gpu);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
 | 
			
		||||
  MetaBackend *backend = meta_gpu_get_backend (gpu);
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  MetaMonitorManagerXrandr *monitor_manager_xrandr =
 | 
			
		||||
    META_MONITOR_MANAGER_XRANDR (monitor_manager);
 | 
			
		||||
  Display *xdisplay;
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,9 @@
 | 
			
		||||
#include <X11/extensions/dpms.h>
 | 
			
		||||
#include <X11/Xlibint.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "backends/meta-output.h"
 | 
			
		||||
#include "backends/x11/meta-backend-x11.h"
 | 
			
		||||
#include "backends/x11/meta-crtc-xrandr.h"
 | 
			
		||||
#include "backends/x11/meta-monitor-manager-xrandr.h"
 | 
			
		||||
#include "backends/x11/meta-output-xrandr.h"
 | 
			
		||||
@@ -86,7 +88,9 @@ meta_gpu_xrandr_read_current (MetaGpu  *gpu,
 | 
			
		||||
                              GError  **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpuXrandr *gpu_xrandr = META_GPU_XRANDR (gpu);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
 | 
			
		||||
  MetaBackend *backend = meta_gpu_get_backend (gpu);
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  MetaMonitorManagerXrandr *monitor_manager_xrandr =
 | 
			
		||||
    META_MONITOR_MANAGER_XRANDR (monitor_manager);
 | 
			
		||||
  Display *xdisplay =
 | 
			
		||||
@@ -229,10 +233,10 @@ meta_gpu_xrandr_read_current (MetaGpu  *gpu,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaGpuXrandr *
 | 
			
		||||
meta_gpu_xrandr_new (MetaMonitorManagerXrandr *monitor_manager_xrandr)
 | 
			
		||||
meta_gpu_xrandr_new (MetaBackendX11 *backend_x11)
 | 
			
		||||
{
 | 
			
		||||
  return g_object_new (META_TYPE_GPU_XRANDR,
 | 
			
		||||
                       "monitor-manager", monitor_manager_xrandr,
 | 
			
		||||
                       "backend", backend_x11,
 | 
			
		||||
                       NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
#include <X11/extensions/Xrandr.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-gpu.h"
 | 
			
		||||
#include "backends/x11/meta-monitor-manager-xrandr.h"
 | 
			
		||||
#include "backends/x11/meta-backend-x11.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_GPU_XRANDR (meta_gpu_xrandr_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaGpuXrandr, meta_gpu_xrandr, META, GPU_XRANDR, MetaGpu)
 | 
			
		||||
@@ -37,6 +37,6 @@ void meta_gpu_xrandr_get_max_screen_size (MetaGpuXrandr *gpu_xrandr,
 | 
			
		||||
                                          int           *max_width,
 | 
			
		||||
                                          int           *max_height);
 | 
			
		||||
 | 
			
		||||
MetaGpuXrandr * meta_gpu_xrandr_new (MetaMonitorManagerXrandr *monitor_manager_xrandr);
 | 
			
		||||
MetaGpuXrandr * meta_gpu_xrandr_new (MetaBackendX11 *backend_x11);
 | 
			
		||||
 | 
			
		||||
#endif /* META_GPU_XRANDR_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -73,13 +73,6 @@ struct _MetaMonitorManagerXrandr
 | 
			
		||||
  int rr_error_base;
 | 
			
		||||
  gboolean has_randr15;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * The X server deals with multiple GPUs for us, soe just see what the X
 | 
			
		||||
   * server gives us as one single GPU, even though it may actually be backed
 | 
			
		||||
   * by multiple.
 | 
			
		||||
   */
 | 
			
		||||
  MetaGpu *gpu;
 | 
			
		||||
 | 
			
		||||
  xcb_timestamp_t last_xrandr_set_timestamp;
 | 
			
		||||
 | 
			
		||||
  GHashTable *tiled_monitor_atoms;
 | 
			
		||||
@@ -344,6 +337,15 @@ is_output_assignment_changed (MetaOutput      *output,
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaGpu *
 | 
			
		||||
meta_monitor_manager_xrandr_get_gpu (MetaMonitorManagerXrandr *manager_xrandr)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
 | 
			
		||||
  return META_GPU (meta_backend_get_gpus (backend)->data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
is_assignments_changed (MetaMonitorManager *manager,
 | 
			
		||||
                        MetaCrtcInfo      **crtc_infos,
 | 
			
		||||
@@ -353,9 +355,10 @@ is_assignments_changed (MetaMonitorManager *manager,
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr =
 | 
			
		||||
    META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
  MetaGpu *gpu = meta_monitor_manager_xrandr_get_gpu (manager_xrandr);
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = meta_gpu_get_crtcs (manager_xrandr->gpu); l; l = l->next)
 | 
			
		||||
  for (l = meta_gpu_get_crtcs (gpu); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaCrtc *crtc = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -363,7 +366,7 @@ is_assignments_changed (MetaMonitorManager *manager,
 | 
			
		||||
        return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (l = meta_gpu_get_outputs (manager_xrandr->gpu); l; l = l->next)
 | 
			
		||||
  for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *output = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -387,6 +390,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
                        unsigned int        n_outputs)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
  MetaGpu *gpu = meta_monitor_manager_xrandr_get_gpu (manager_xrandr);
 | 
			
		||||
  unsigned i;
 | 
			
		||||
  GList *l;
 | 
			
		||||
  int width, height, width_mm, height_mm;
 | 
			
		||||
@@ -448,7 +452,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable CRTCs not mentioned in the list */
 | 
			
		||||
  for (l = meta_gpu_get_crtcs (manager_xrandr->gpu); l; l = l->next)
 | 
			
		||||
  for (l = meta_gpu_get_crtcs (gpu); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaCrtc *crtc = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -568,7 +572,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable outputs not mentioned in the list */
 | 
			
		||||
  for (l = meta_gpu_get_outputs (manager_xrandr->gpu); l; l = l->next)
 | 
			
		||||
  for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *output = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -1003,8 +1007,9 @@ meta_monitor_manager_xrandr_get_max_screen_size (MetaMonitorManager *manager,
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr =
 | 
			
		||||
    META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
  MetaGpu *gpu = meta_monitor_manager_xrandr_get_gpu (manager_xrandr);
 | 
			
		||||
 | 
			
		||||
  meta_gpu_xrandr_get_max_screen_size (META_GPU_XRANDR (manager_xrandr->gpu),
 | 
			
		||||
  meta_gpu_xrandr_get_max_screen_size (META_GPU_XRANDR (gpu),
 | 
			
		||||
                                       max_width, max_height);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
@@ -1022,13 +1027,10 @@ meta_monitor_manager_xrandr_constructed (GObject *object)
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr =
 | 
			
		||||
    META_MONITOR_MANAGER_XRANDR (object);
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
 | 
			
		||||
  MetaBackendX11 *backend =
 | 
			
		||||
    META_BACKEND_X11 (meta_monitor_manager_get_backend (manager));
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
  MetaBackendX11 *backend_x11 = META_BACKEND_X11 (backend);
 | 
			
		||||
 | 
			
		||||
  manager_xrandr->xdisplay = meta_backend_x11_get_xdisplay (backend);
 | 
			
		||||
 | 
			
		||||
  manager_xrandr->gpu = META_GPU (meta_gpu_xrandr_new (manager_xrandr));
 | 
			
		||||
  meta_monitor_manager_add_gpu (manager, manager_xrandr->gpu);
 | 
			
		||||
  manager_xrandr->xdisplay = meta_backend_x11_get_xdisplay (backend_x11);
 | 
			
		||||
 | 
			
		||||
  if (!XRRQueryExtension (manager_xrandr->xdisplay,
 | 
			
		||||
			  &manager_xrandr->rr_event_base,
 | 
			
		||||
@@ -1068,7 +1070,6 @@ meta_monitor_manager_xrandr_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (object);
 | 
			
		||||
 | 
			
		||||
  g_clear_object (&manager_xrandr->gpu);
 | 
			
		||||
  g_hash_table_destroy (manager_xrandr->tiled_monitor_atoms);
 | 
			
		||||
  g_free (manager_xrandr->supported_scales);
 | 
			
		||||
 | 
			
		||||
@@ -1115,6 +1116,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
 | 
			
		||||
					   XEvent                   *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
 | 
			
		||||
  MetaGpu *gpu = meta_monitor_manager_xrandr_get_gpu (manager_xrandr);
 | 
			
		||||
  MetaGpuXrandr *gpu_xrandr;
 | 
			
		||||
  XRRScreenResources *resources;
 | 
			
		||||
  gboolean is_hotplug;
 | 
			
		||||
@@ -1127,7 +1129,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_read_current_state (manager);
 | 
			
		||||
 | 
			
		||||
  gpu_xrandr = META_GPU_XRANDR (manager_xrandr->gpu);
 | 
			
		||||
  gpu_xrandr = META_GPU_XRANDR (gpu);
 | 
			
		||||
  resources = meta_gpu_xrandr_get_resources (gpu_xrandr);
 | 
			
		||||
 | 
			
		||||
  is_hotplug = resources->timestamp < resources->configTimestamp;
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,7 @@
 | 
			
		||||
#include <X11/Xlib-xcb.h>
 | 
			
		||||
#include <xcb/randr.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "backends/meta-crtc.h"
 | 
			
		||||
#include "backends/x11/meta-monitor-manager-xrandr.h"
 | 
			
		||||
#include "meta/util.h"
 | 
			
		||||
@@ -49,7 +50,9 @@ static Display *
 | 
			
		||||
xdisplay_from_output (MetaOutput *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = meta_output_get_gpu (output);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
 | 
			
		||||
  MetaBackend *backend = meta_gpu_get_backend (gpu);
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  MetaMonitorManagerXrandr *monitor_manager_xrandr =
 | 
			
		||||
    META_MONITOR_MANAGER_XRANDR (monitor_manager);
 | 
			
		||||
 | 
			
		||||
@@ -643,7 +646,9 @@ static void
 | 
			
		||||
output_get_tile_info (MetaOutput *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu = meta_output_get_gpu (output);
 | 
			
		||||
  MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
 | 
			
		||||
  MetaBackend *backend = meta_gpu_get_backend (gpu);
 | 
			
		||||
  MetaMonitorManager *monitor_manager =
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  MetaMonitorManagerXrandr *monitor_manager_xrandr =
 | 
			
		||||
    META_MONITOR_MANAGER_XRANDR (monitor_manager);
 | 
			
		||||
  Display *xdisplay = xdisplay_from_output (output);
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,12 @@
 | 
			
		||||
 | 
			
		||||
#include "wayland/meta-wayland.h"
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaBackendX11Nested, meta_backend_x11_nested,
 | 
			
		||||
typedef struct _MetaBackendX11NestedPrivate
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu *gpu;
 | 
			
		||||
} MetaBackendX11NestedPrivate;
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendX11Nested, meta_backend_x11_nested,
 | 
			
		||||
                            META_TYPE_BACKEND_X11)
 | 
			
		||||
 | 
			
		||||
static MetaRenderer *
 | 
			
		||||
@@ -182,6 +187,32 @@ meta_backend_x11_nested_translate_device_event (MetaBackendX11 *x11,
 | 
			
		||||
  g_assert (device_event->event == meta_backend_x11_get_xwindow (x11));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_x11_nested_real_init_gpus (MetaBackendX11Nested *backend_x11_nested)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendX11NestedPrivate *priv =
 | 
			
		||||
    meta_backend_x11_nested_get_instance_private (backend_x11_nested);
 | 
			
		||||
 | 
			
		||||
  priv->gpu = g_object_new (META_TYPE_GPU_DUMMY,
 | 
			
		||||
                            "backend", backend_x11_nested,
 | 
			
		||||
                            NULL);
 | 
			
		||||
  meta_backend_add_gpu (META_BACKEND (backend_x11_nested), priv->gpu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_x11_nested_constructed (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendX11Nested *backend_x11_nested = META_BACKEND_X11_NESTED (object);
 | 
			
		||||
  MetaBackendX11NestedClass *backend_x11_nested_class =
 | 
			
		||||
    META_BACKEND_X11_NESTED_GET_CLASS (backend_x11_nested);
 | 
			
		||||
  GObjectClass *parent_class =
 | 
			
		||||
    G_OBJECT_CLASS (meta_backend_x11_nested_parent_class);
 | 
			
		||||
 | 
			
		||||
  parent_class->constructed (object);
 | 
			
		||||
 | 
			
		||||
  backend_x11_nested_class->init_gpus (backend_x11_nested);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_x11_nested_init (MetaBackendX11Nested *backend_x11_nested)
 | 
			
		||||
{
 | 
			
		||||
@@ -190,9 +221,12 @@ meta_backend_x11_nested_init (MetaBackendX11Nested *backend_x11_nested)
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_x11_nested_class_init (MetaBackendX11NestedClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
  MetaBackendClass *backend_class = META_BACKEND_CLASS (klass);
 | 
			
		||||
  MetaBackendX11Class *backend_x11_class = META_BACKEND_X11_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->constructed = meta_backend_x11_nested_constructed;
 | 
			
		||||
 | 
			
		||||
  backend_class->create_renderer = meta_backend_x11_nested_create_renderer;
 | 
			
		||||
  backend_class->create_monitor_manager = meta_backend_x11_nested_create_monitor_manager;
 | 
			
		||||
  backend_class->create_cursor_renderer = meta_backend_x11_nested_create_cursor_renderer;
 | 
			
		||||
@@ -205,4 +239,6 @@ meta_backend_x11_nested_class_init (MetaBackendX11NestedClass *klass)
 | 
			
		||||
 | 
			
		||||
  backend_x11_class->handle_host_xevent = meta_backend_x11_nested_handle_host_xevent;
 | 
			
		||||
  backend_x11_class->translate_device_event = meta_backend_x11_nested_translate_device_event;
 | 
			
		||||
 | 
			
		||||
  klass->init_gpus = meta_backend_x11_nested_real_init_gpus;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,8 @@ G_DECLARE_DERIVABLE_TYPE (MetaBackendX11Nested, meta_backend_x11_nested,
 | 
			
		||||
struct _MetaBackendX11NestedClass
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendX11Class parent_class;
 | 
			
		||||
 | 
			
		||||
  void (* init_gpus) (MetaBackendX11Nested *backend_x11_nested);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* META_BACKEND_X11_NESTED_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -568,6 +568,7 @@ if have_native_backend
 | 
			
		||||
    'backends/native/meta-backend-native.c',
 | 
			
		||||
    'backends/native/meta-backend-native.h',
 | 
			
		||||
    'backends/native/meta-backend-native-private.h',
 | 
			
		||||
    'backends/native/meta-backend-native-types.h',
 | 
			
		||||
    'backends/native/meta-barrier-native.c',
 | 
			
		||||
    'backends/native/meta-barrier-native.h',
 | 
			
		||||
    'backends/native/meta-clutter-backend-native.c',
 | 
			
		||||
@@ -593,11 +594,41 @@ if have_native_backend
 | 
			
		||||
    'backends/native/meta-output-kms.c',
 | 
			
		||||
    'backends/native/meta-output-kms.h',
 | 
			
		||||
    'backends/native/meta-renderer-native.c',
 | 
			
		||||
    'backends/native/meta-kms-connector-private.h',
 | 
			
		||||
    'backends/native/meta-kms-connector.c',
 | 
			
		||||
    'backends/native/meta-kms-connector.h',
 | 
			
		||||
    'backends/native/meta-kms-crtc-private.h',
 | 
			
		||||
    'backends/native/meta-kms-crtc.c',
 | 
			
		||||
    'backends/native/meta-kms-crtc.h',
 | 
			
		||||
    'backends/native/meta-kms-device-private.h',
 | 
			
		||||
    'backends/native/meta-kms-device.c',
 | 
			
		||||
    'backends/native/meta-kms-device.h',
 | 
			
		||||
    'backends/native/meta-kms-impl-device.c',
 | 
			
		||||
    'backends/native/meta-kms-impl-device.h',
 | 
			
		||||
    'backends/native/meta-kms-impl-simple.c',
 | 
			
		||||
    'backends/native/meta-kms-impl-simple.h',
 | 
			
		||||
    'backends/native/meta-kms-impl.c',
 | 
			
		||||
    'backends/native/meta-kms-impl.h',
 | 
			
		||||
    'backends/native/meta-kms-page-flip.c',
 | 
			
		||||
    'backends/native/meta-kms-page-flip-private.h',
 | 
			
		||||
    'backends/native/meta-kms-plane.c',
 | 
			
		||||
    'backends/native/meta-kms-plane.h',
 | 
			
		||||
    'backends/native/meta-kms-private.h',
 | 
			
		||||
    'backends/native/meta-kms-types.h',
 | 
			
		||||
    'backends/native/meta-kms-update-private.h',
 | 
			
		||||
    'backends/native/meta-kms-update.c',
 | 
			
		||||
    'backends/native/meta-kms-update.h',
 | 
			
		||||
    'backends/native/meta-kms-utils.c',
 | 
			
		||||
    'backends/native/meta-kms-utils.h',
 | 
			
		||||
    'backends/native/meta-kms.c',
 | 
			
		||||
    'backends/native/meta-kms.h',
 | 
			
		||||
    'backends/native/meta-renderer-native-gles3.c',
 | 
			
		||||
    'backends/native/meta-renderer-native-gles3.h',
 | 
			
		||||
    'backends/native/meta-renderer-native.h',
 | 
			
		||||
    'backends/native/meta-stage-native.c',
 | 
			
		||||
    'backends/native/meta-stage-native.h',
 | 
			
		||||
    'backends/native/meta-udev.c',
 | 
			
		||||
    'backends/native/meta-udev.h',
 | 
			
		||||
  ]
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
@@ -774,14 +805,6 @@ endif
 | 
			
		||||
 | 
			
		||||
subdir('meta')
 | 
			
		||||
 | 
			
		||||
mutter_marshal = gnome.genmarshal('meta-marshal',
 | 
			
		||||
  sources: ['meta-marshal.list'],
 | 
			
		||||
  prefix: 'meta_marshal',
 | 
			
		||||
  extra_args: ['--quiet'],
 | 
			
		||||
  internal: true,
 | 
			
		||||
)
 | 
			
		||||
mutter_built_sources += mutter_marshal
 | 
			
		||||
 | 
			
		||||
mutter_built_sources += mutter_enum_types
 | 
			
		||||
mutter_built_sources += mutter_version
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
VOID:OBJECT,OBJECT,INT64
 | 
			
		||||
@@ -79,7 +79,7 @@ meta_test_headless_start (void)
 | 
			
		||||
  GList *gpus;
 | 
			
		||||
  MetaGpu *gpu;
 | 
			
		||||
 | 
			
		||||
  gpus = meta_monitor_manager_get_gpus (monitor_manager);
 | 
			
		||||
  gpus = meta_backend_get_gpus (backend);
 | 
			
		||||
  g_assert_cmpint ((int) g_list_length (gpus), ==, 1);
 | 
			
		||||
 | 
			
		||||
  gpu = gpus->data;
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,8 @@ unit_tests = executable('mutter-test-unit-tests',
 | 
			
		||||
    'boxes-tests.h',
 | 
			
		||||
    'meta-backend-test.c',
 | 
			
		||||
    'meta-backend-test.h',
 | 
			
		||||
    'meta-gpu-test.c',
 | 
			
		||||
    'meta-gpu-test.h',
 | 
			
		||||
    'meta-monitor-manager-test.c',
 | 
			
		||||
    'meta-monitor-manager-test.h',
 | 
			
		||||
    'monitor-config-migration-unit-tests.c',
 | 
			
		||||
@@ -89,6 +91,8 @@ headless_start_test = executable('mutter-headless-start-test',
 | 
			
		||||
    'headless-start-test.c',
 | 
			
		||||
    'meta-backend-test.c',
 | 
			
		||||
    'meta-backend-test.h',
 | 
			
		||||
    'meta-gpu-test.c',
 | 
			
		||||
    'meta-gpu-test.h',
 | 
			
		||||
    'meta-monitor-manager-test.c',
 | 
			
		||||
    'meta-monitor-manager-test.h',
 | 
			
		||||
    'test-utils.c',
 | 
			
		||||
 
 | 
			
		||||
@@ -21,12 +21,15 @@
 | 
			
		||||
 | 
			
		||||
#include "tests/meta-backend-test.h"
 | 
			
		||||
 | 
			
		||||
#include "tests/meta-gpu-test.h"
 | 
			
		||||
#include "tests/meta-monitor-manager-test.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaBackendTest
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendX11Nested parent;
 | 
			
		||||
 | 
			
		||||
  MetaGpu *gpu;
 | 
			
		||||
 | 
			
		||||
  gboolean is_lid_closed;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -39,6 +42,12 @@ meta_backend_test_set_is_lid_closed (MetaBackendTest *backend_test,
 | 
			
		||||
  backend_test->is_lid_closed = is_lid_closed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaGpu *
 | 
			
		||||
meta_backend_test_get_gpu (MetaBackendTest *backend_test)
 | 
			
		||||
{
 | 
			
		||||
  return backend_test->gpu;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_backend_test_is_lid_closed (MetaBackend *backend)
 | 
			
		||||
{
 | 
			
		||||
@@ -47,6 +56,17 @@ meta_backend_test_is_lid_closed (MetaBackend *backend)
 | 
			
		||||
  return backend_test->is_lid_closed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_test_init_gpus (MetaBackendX11Nested *backend_x11_nested)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendTest *backend_test = META_BACKEND_TEST (backend_x11_nested);
 | 
			
		||||
 | 
			
		||||
  backend_test->gpu = g_object_new (META_TYPE_GPU_TEST,
 | 
			
		||||
                                    "backend", backend_test,
 | 
			
		||||
                                    NULL);
 | 
			
		||||
  meta_backend_add_gpu (META_BACKEND (backend_test), backend_test->gpu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_test_init (MetaBackendTest *backend_test)
 | 
			
		||||
{
 | 
			
		||||
@@ -65,7 +85,11 @@ static void
 | 
			
		||||
meta_backend_test_class_init (MetaBackendTestClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendClass *backend_class = META_BACKEND_CLASS (klass);
 | 
			
		||||
  MetaBackendX11NestedClass *backend_x11_nested_class =
 | 
			
		||||
    META_BACKEND_X11_NESTED_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  backend_class->create_monitor_manager = meta_backend_test_create_monitor_manager;
 | 
			
		||||
  backend_class->is_lid_closed = meta_backend_test_is_lid_closed;
 | 
			
		||||
 | 
			
		||||
  backend_x11_nested_class->init_gpus = meta_backend_test_init_gpus;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,4 +29,6 @@ G_DECLARE_FINAL_TYPE (MetaBackendTest, meta_backend_test,
 | 
			
		||||
void meta_backend_test_set_is_lid_closed (MetaBackendTest *backend_test,
 | 
			
		||||
                                          gboolean         is_lid_closed);
 | 
			
		||||
 | 
			
		||||
MetaGpu * meta_backend_test_get_gpu (MetaBackendTest *backend_test);
 | 
			
		||||
 | 
			
		||||
#endif /* META_BACKEND_TEST_H */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										55
									
								
								src/tests/meta-gpu-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/tests/meta-gpu-test.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016-2018 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, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "tests/meta-gpu-test.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "tests/meta-monitor-manager-test.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaGpuTest
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu parent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaGpuTest, meta_gpu_test, META_TYPE_GPU)
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_gpu_test_read_current (MetaGpu  *gpu,
 | 
			
		||||
                            GError  **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend *backend = meta_gpu_get_backend (gpu);
 | 
			
		||||
  MetaMonitorManager *manager = meta_backend_get_monitor_manager (backend);
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_test_read_current (manager);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_gpu_test_init (MetaGpuTest *gpu_test)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_gpu_test_class_init (MetaGpuTestClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpuClass *gpu_class = META_GPU_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  gpu_class->read_current = meta_gpu_test_read_current;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								src/tests/meta-gpu-test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/tests/meta-gpu-test.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016-2018 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, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_GPU_TEST_H
 | 
			
		||||
#define META_GPU_TEST_H
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-gpu.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_GPU_TEST (meta_gpu_test_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaGpuTest, meta_gpu_test, META, GPU_TEST, MetaGpu)
 | 
			
		||||
 | 
			
		||||
#endif /* META_GPU_TEST_H */
 | 
			
		||||
@@ -26,13 +26,12 @@
 | 
			
		||||
#include "backends/meta-gpu.h"
 | 
			
		||||
#include "backends/meta-monitor-config-manager.h"
 | 
			
		||||
#include "backends/meta-output.h"
 | 
			
		||||
#include "tests/meta-backend-test.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorManagerTest
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager parent;
 | 
			
		||||
 | 
			
		||||
  MetaGpu *gpu;
 | 
			
		||||
 | 
			
		||||
  gboolean handles_transforms;
 | 
			
		||||
 | 
			
		||||
  int tiled_monitor_count;
 | 
			
		||||
@@ -43,13 +42,6 @@ struct _MetaMonitorManagerTest
 | 
			
		||||
G_DEFINE_TYPE (MetaMonitorManagerTest, meta_monitor_manager_test,
 | 
			
		||||
               META_TYPE_MONITOR_MANAGER)
 | 
			
		||||
 | 
			
		||||
struct _MetaGpuTest
 | 
			
		||||
{
 | 
			
		||||
  MetaGpu parent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaGpuTest, meta_gpu_test, META_TYPE_GPU)
 | 
			
		||||
 | 
			
		||||
static MetaMonitorTestSetup *_initial_test_setup = NULL;
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -58,12 +50,6 @@ meta_monitor_manager_test_init_test_setup (MetaMonitorTestSetup *test_setup)
 | 
			
		||||
  _initial_test_setup = test_setup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaGpu *
 | 
			
		||||
meta_monitor_manager_test_get_gpu (MetaMonitorManagerTest *manager_test)
 | 
			
		||||
{
 | 
			
		||||
  return manager_test->gpu;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_test_emulate_hotplug (MetaMonitorManagerTest *manager_test,
 | 
			
		||||
                                           MetaMonitorTestSetup   *test_setup)
 | 
			
		||||
@@ -95,11 +81,13 @@ meta_monitor_manager_test_get_tiled_monitor_count (MetaMonitorManagerTest *manag
 | 
			
		||||
  return manager_test->tiled_monitor_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_test_read_current (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerTest *manager_test = META_MONITOR_MANAGER_TEST (manager);
 | 
			
		||||
  MetaGpu *gpu = manager_test->gpu;
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
  MetaBackendTest *backend_test = META_BACKEND_TEST (backend);
 | 
			
		||||
  MetaGpu *gpu = meta_backend_test_get_gpu (backend_test);
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  g_assert (manager_test->test_setup);
 | 
			
		||||
@@ -109,14 +97,9 @@ meta_monitor_manager_test_read_current (MetaMonitorManager *manager)
 | 
			
		||||
  for (l = manager_test->test_setup->crtcs; l; l = l->next)
 | 
			
		||||
    META_CRTC (l->data)->gpu = gpu;
 | 
			
		||||
 | 
			
		||||
  meta_gpu_take_modes (manager_test->gpu,
 | 
			
		||||
                       manager_test->test_setup->modes);
 | 
			
		||||
 | 
			
		||||
  meta_gpu_take_crtcs (manager_test->gpu,
 | 
			
		||||
                       manager_test->test_setup->crtcs);
 | 
			
		||||
 | 
			
		||||
  meta_gpu_take_outputs (manager_test->gpu,
 | 
			
		||||
                         manager_test->test_setup->outputs);
 | 
			
		||||
  meta_gpu_take_modes (gpu, manager_test->test_setup->modes);
 | 
			
		||||
  meta_gpu_take_crtcs (gpu, manager_test->test_setup->crtcs);
 | 
			
		||||
  meta_gpu_take_outputs (gpu, manager_test->test_setup->outputs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -143,7 +126,9 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
                        MetaOutputInfo    **outputs,
 | 
			
		||||
                        unsigned int        n_outputs)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerTest *manager_test = META_MONITOR_MANAGER_TEST (manager);
 | 
			
		||||
  MetaBackend *backend = meta_monitor_manager_get_backend (manager);
 | 
			
		||||
  MetaBackendTest *backend_test = META_BACKEND_TEST (backend);
 | 
			
		||||
  MetaGpu *gpu = meta_backend_test_get_gpu (backend_test);
 | 
			
		||||
  GList *l;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
@@ -209,7 +194,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable CRTCs not mentioned in the list */
 | 
			
		||||
  for (l = meta_gpu_get_crtcs (manager_test->gpu); l; l = l->next)
 | 
			
		||||
  for (l = meta_gpu_get_crtcs (gpu); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaCrtc *crtc = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -229,7 +214,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable outputs not mentioned in the list */
 | 
			
		||||
  for (l = meta_gpu_get_outputs (manager_test->gpu); l; l = l->next)
 | 
			
		||||
  for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *output = l->data;
 | 
			
		||||
 | 
			
		||||
@@ -458,18 +443,11 @@ meta_monitor_manager_test_dispose (GObject *object)
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_test_init (MetaMonitorManagerTest *manager_test)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_test);
 | 
			
		||||
 | 
			
		||||
  g_assert (_initial_test_setup);
 | 
			
		||||
 | 
			
		||||
  manager_test->handles_transforms = TRUE;
 | 
			
		||||
 | 
			
		||||
  manager_test->test_setup = _initial_test_setup;
 | 
			
		||||
 | 
			
		||||
  manager_test->gpu = g_object_new (META_TYPE_GPU_TEST,
 | 
			
		||||
                                    "monitor-manager", manager,
 | 
			
		||||
                                    NULL);
 | 
			
		||||
  meta_monitor_manager_add_gpu (manager, manager_test->gpu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -491,27 +469,3 @@ meta_monitor_manager_test_class_init (MetaMonitorManagerTestClass *klass)
 | 
			
		||||
  manager_class->get_max_screen_size = meta_monitor_manager_test_get_max_screen_size;
 | 
			
		||||
  manager_class->get_default_layout_mode = meta_monitor_manager_test_get_default_layout_mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_gpu_test_read_current (MetaGpu  *gpu,
 | 
			
		||||
                            GError  **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager = meta_gpu_get_monitor_manager (gpu);
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_test_read_current (manager);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_gpu_test_init (MetaGpuTest *gpu_test)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_gpu_test_class_init (MetaGpuTestClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  MetaGpuClass *gpu_class = META_GPU_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  gpu_class->read_current = meta_gpu_test_read_current;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,6 @@
 | 
			
		||||
#ifndef META_MONITOR_MANAGER_TEST_H
 | 
			
		||||
#define META_MONITOR_MANAGER_TEST_H
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-gpu.h"
 | 
			
		||||
#include "backends/meta-monitor-manager-private.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaMonitorTestSetup
 | 
			
		||||
@@ -39,12 +38,9 @@ typedef struct _MetaOutputTest
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaMonitorManagerTest, meta_monitor_manager_test,
 | 
			
		||||
                      META, MONITOR_MANAGER_TEST, MetaMonitorManager)
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_GPU_TEST (meta_gpu_test_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaGpuTest, meta_gpu_test, META, GPU_TEST, MetaGpu)
 | 
			
		||||
 | 
			
		||||
void meta_monitor_manager_test_init_test_setup (MetaMonitorTestSetup *test_setup);
 | 
			
		||||
 | 
			
		||||
MetaGpu * meta_monitor_manager_test_get_gpu (MetaMonitorManagerTest *manager_test);
 | 
			
		||||
void meta_monitor_manager_test_read_current (MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
void meta_monitor_manager_test_emulate_hotplug (MetaMonitorManagerTest *manager_test,
 | 
			
		||||
                                                MetaMonitorTestSetup   *test_setup);
 | 
			
		||||
 
 | 
			
		||||
@@ -408,12 +408,10 @@ destroy_monitor_test_clients (void)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaOutput *
 | 
			
		||||
output_from_winsys_id (MetaMonitorManager *monitor_manager,
 | 
			
		||||
output_from_winsys_id (MetaBackend *backend,
 | 
			
		||||
                       uint64_t     winsys_id)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerTest *monitor_manager_test =
 | 
			
		||||
    META_MONITOR_MANAGER_TEST (monitor_manager);
 | 
			
		||||
  MetaGpu *gpu = meta_monitor_manager_test_get_gpu (monitor_manager_test);
 | 
			
		||||
  MetaGpu *gpu = meta_backend_test_get_gpu (META_BACKEND_TEST (backend));
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
 | 
			
		||||
@@ -429,7 +427,7 @@ output_from_winsys_id (MetaMonitorManager *monitor_manager,
 | 
			
		||||
 | 
			
		||||
typedef struct _CheckMonitorModeData
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *monitor_manager;
 | 
			
		||||
  MetaBackend *backend;
 | 
			
		||||
  MetaTestCaseMonitorCrtcMode *expect_crtc_mode_iter;
 | 
			
		||||
} CheckMonitorModeData;
 | 
			
		||||
 | 
			
		||||
@@ -441,12 +439,12 @@ check_monitor_mode (MetaMonitor         *monitor,
 | 
			
		||||
                    GError             **error)
 | 
			
		||||
{
 | 
			
		||||
  CheckMonitorModeData *data = user_data;
 | 
			
		||||
  MetaMonitorManager *monitor_manager = data->monitor_manager;
 | 
			
		||||
  MetaBackend *backend = data->backend;
 | 
			
		||||
  MetaOutput *output;
 | 
			
		||||
  MetaCrtcMode *crtc_mode;
 | 
			
		||||
  int expect_crtc_mode_index;
 | 
			
		||||
 | 
			
		||||
  output = output_from_winsys_id (monitor_manager,
 | 
			
		||||
  output = output_from_winsys_id (backend,
 | 
			
		||||
                                  data->expect_crtc_mode_iter->output);
 | 
			
		||||
  g_assert (monitor_crtc_mode->output == output);
 | 
			
		||||
 | 
			
		||||
@@ -489,11 +487,11 @@ check_current_monitor_mode (MetaMonitor         *monitor,
 | 
			
		||||
                            GError             **error)
 | 
			
		||||
{
 | 
			
		||||
  CheckMonitorModeData *data = user_data;
 | 
			
		||||
  MetaMonitorManager *monitor_manager = data->monitor_manager;
 | 
			
		||||
  MetaBackend *backend = data->backend;
 | 
			
		||||
  MetaOutput *output;
 | 
			
		||||
  MetaCrtc *crtc;
 | 
			
		||||
 | 
			
		||||
  output = output_from_winsys_id (monitor_manager,
 | 
			
		||||
  output = output_from_winsys_id (backend,
 | 
			
		||||
                                  data->expect_crtc_mode_iter->output);
 | 
			
		||||
  crtc = meta_output_get_assigned_crtc (output);
 | 
			
		||||
 | 
			
		||||
@@ -661,7 +659,7 @@ check_monitor_configuration (MonitorTestCase *test_case)
 | 
			
		||||
    meta_backend_get_monitor_manager (backend);
 | 
			
		||||
  MetaMonitorManagerTest *monitor_manager_test =
 | 
			
		||||
    META_MONITOR_MANAGER_TEST (monitor_manager);
 | 
			
		||||
  MetaGpu *gpu = meta_monitor_manager_test_get_gpu (monitor_manager_test);
 | 
			
		||||
  MetaGpu *gpu = meta_backend_test_get_gpu (META_BACKEND_TEST (backend));
 | 
			
		||||
  int tiled_monitor_count;
 | 
			
		||||
  GList *monitors;
 | 
			
		||||
  GList *crtcs;
 | 
			
		||||
@@ -716,8 +714,7 @@ check_monitor_configuration (MonitorTestCase *test_case)
 | 
			
		||||
          MetaOutput *output = l_output->data;
 | 
			
		||||
          uint64_t winsys_id = test_case->expect.monitors[i].outputs[j];
 | 
			
		||||
 | 
			
		||||
          g_assert (output == output_from_winsys_id (monitor_manager,
 | 
			
		||||
                                                     winsys_id));
 | 
			
		||||
          g_assert (output == output_from_winsys_id (backend, winsys_id));
 | 
			
		||||
          g_assert_cmpint (test_case->expect.monitors[i].is_underscanning,
 | 
			
		||||
                           ==,
 | 
			
		||||
                           output->is_underscanning);
 | 
			
		||||
@@ -763,7 +760,7 @@ check_monitor_configuration (MonitorTestCase *test_case)
 | 
			
		||||
                           test_case->expect.monitors[i].modes[j].flags);
 | 
			
		||||
 | 
			
		||||
          data = (CheckMonitorModeData) {
 | 
			
		||||
            .monitor_manager = monitor_manager,
 | 
			
		||||
            .backend = backend,
 | 
			
		||||
            .expect_crtc_mode_iter =
 | 
			
		||||
              test_case->expect.monitors[i].modes[j].crtc_modes
 | 
			
		||||
          };
 | 
			
		||||
@@ -792,7 +789,7 @@ check_monitor_configuration (MonitorTestCase *test_case)
 | 
			
		||||
          CheckMonitorModeData data;
 | 
			
		||||
 | 
			
		||||
          data = (CheckMonitorModeData) {
 | 
			
		||||
            .monitor_manager = monitor_manager,
 | 
			
		||||
            .backend = backend,
 | 
			
		||||
            .expect_crtc_mode_iter =
 | 
			
		||||
              test_case->expect.monitors[i].modes[expected_current_mode_index].crtc_modes
 | 
			
		||||
          };
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user