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. */ | ||||
| @@ -1176,10 +1178,10 @@ meta_monitor_tiled_generate_modes (MetaMonitorTiled *monitor_tiled) | ||||
| } | ||||
|  | ||||
| MetaMonitorTiled * | ||||
| meta_monitor_tiled_new (MetaGpu    *gpu, | ||||
|                         MetaOutput *output) | ||||
| 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); | ||||
| } | ||||
|   | ||||
| @@ -96,8 +96,9 @@ G_DECLARE_FINAL_TYPE (MetaMonitorTiled, meta_monitor_tiled, | ||||
|                       MetaMonitor) | ||||
|  | ||||
| META_EXPORT_TEST | ||||
| MetaMonitorTiled * meta_monitor_tiled_new (MetaGpu    *gpu, | ||||
|                                            MetaOutput *output); | ||||
| MetaMonitorTiled * meta_monitor_tiled_new (MetaGpu            *gpu, | ||||
|                                            MetaMonitorManager *monitor_manager, | ||||
|                                            MetaOutput         *output); | ||||
|  | ||||
| META_EXPORT_TEST | ||||
| MetaMonitorNormal * meta_monitor_normal_new (MetaGpu    *gpu, | ||||
|   | ||||
| @@ -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 | ||||
|   hw_transform = crtc->transform; | ||||
|   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); | ||||
|  | ||||
|       /* | ||||
|        * Blacklist this HW transform, we want to fallback to our | ||||
|        * fallbacks in this case. | ||||
|        */ | ||||
|       crtc_kms->all_hw_transforms &= ~(1 << hw_transform); | ||||
|     } | ||||
|   meta_kms_plane_update_set_rotation (crtc_kms->primary_plane, | ||||
|                                       kms_plane_assignment, | ||||
|                                       hw_transform); | ||||
| } | ||||
|  | ||||
| static int | ||||
| find_property_index (MetaGpu                    *gpu, | ||||
|                      drmModeObjectPropertiesPtr  props, | ||||
|                      const char                 *prop_name, | ||||
|                      drmModePropertyPtr         *out_prop) | ||||
| void | ||||
| meta_crtc_kms_assign_primary_plane (MetaCrtc      *crtc, | ||||
|                                     uint32_t       fb_id, | ||||
|                                     MetaKmsUpdate *kms_update) | ||||
| { | ||||
|   MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); | ||||
|   int kms_fd; | ||||
|   unsigned int i; | ||||
|   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; | ||||
|  | ||||
|   kms_fd = meta_gpu_kms_get_fd (gpu_kms); | ||||
|   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), | ||||
|   }; | ||||
|  | ||||
|   for (i = 0; i < props->count_props; i++) | ||||
|   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) | ||||
|     { | ||||
|       drmModePropertyPtr prop; | ||||
|       MetaOutput *output = l->data; | ||||
|       MetaCrtc *assigned_crtc; | ||||
|  | ||||
|       prop = drmModeGetProperty (kms_fd, props->props[i]); | ||||
|       if (!prop) | ||||
|         continue; | ||||
|  | ||||
|       if (strcmp (prop->name, prop_name) == 0) | ||||
|       assigned_crtc = meta_output_get_assigned_crtc (output); | ||||
|       if (assigned_crtc == crtc) | ||||
|         { | ||||
|           *out_prop = prop; | ||||
|           return i; | ||||
|         } | ||||
|           MetaKmsConnector *kms_connector = | ||||
|             meta_output_kms_get_kms_connector (output); | ||||
|  | ||||
|       drmModeFreeProperty (prop); | ||||
|           connectors = g_list_prepend (connectors, kms_connector); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   return -1; | ||||
|   return connectors; | ||||
| } | ||||
|  | ||||
| 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); | ||||
|     } | ||||
|  | ||||
|   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) | ||||
| meta_create_kms_crtc (MetaGpuKms  *gpu_kms, | ||||
|                       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_create_kms_crtc (MetaGpuKms   *gpu_kms, | ||||
|                                  drmModeCrtc  *drm_crtc, | ||||
|                                  unsigned int  crtc_index); | ||||
| MetaCrtc * meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc); | ||||
|  | ||||
| MetaCrtc * meta_create_kms_crtc (MetaGpuKms  *gpu_kms, | ||||
|                                  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)); | ||||
|               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; | ||||
|         } | ||||
|     } | ||||
|   if (meta_kms_device_dispatch_sync (gpu_kms->kms_device, error) < 0) | ||||
|     return FALSE; | ||||
|  | ||||
|   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 | ||||
| @@ -419,8 +153,9 @@ meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms) | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms, | ||||
|                                   uint64_t    state) | ||||
| meta_gpu_kms_set_power_save_mode (MetaGpuKms    *gpu_kms, | ||||
|                                   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) | ||||
| @@ -568,8 +280,8 @@ create_mode (const drmModeModeInfo *drm_mode, | ||||
| } | ||||
|  | ||||
| static MetaOutput * | ||||
| find_output_by_connector_id (GList *outputs, | ||||
|                              glong  id) | ||||
| find_output_by_connector_id (GList    *outputs, | ||||
|                              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,44 +429,44 @@ 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++) | ||||
|   for (l = meta_kms_device_get_connectors (gpu_kms->kms_device); l; l = l->next) | ||||
|     { | ||||
|       drmModeConnector *connector; | ||||
|       MetaKmsConnector *kms_connector = l->data; | ||||
|       const MetaKmsConnectorState *connector_state; | ||||
|       MetaOutput *output; | ||||
|       MetaOutput *old_output; | ||||
|       GError *error = NULL; | ||||
|  | ||||
|       connector = gpu_kms->connectors[i]; | ||||
|       connector_state = meta_kms_connector_get_current_state (kms_connector); | ||||
|       if (!connector_state) | ||||
|         continue; | ||||
|  | ||||
|       if (connector && connector->connection == DRM_MODE_CONNECTED) | ||||
|       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) | ||||
|         { | ||||
|           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, | ||||
|                                            old_output, | ||||
|                                            &error); | ||||
|           if (!output) | ||||
|             { | ||||
|               g_warning ("Failed to create KMS output: %s", error->message); | ||||
|               g_error_free (error); | ||||
|             } | ||||
|           else | ||||
|             { | ||||
|               outputs = g_list_prepend (outputs, output); | ||||
|             } | ||||
|           g_warning ("Failed to create KMS output: %s", error->message); | ||||
|           g_error_free (error); | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           outputs = g_list_prepend (outputs, output); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -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, | ||||
|                   GError                **error) | ||||
| 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,39 +28,17 @@ | ||||
| #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, | ||||
|                                GError                **error); | ||||
|  | ||||
| gboolean meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms, | ||||
|                                        MetaCrtc   *crtc, | ||||
|                                        int         x, | ||||
|                                        int         y, | ||||
|                                        uint32_t    fb_id); | ||||
| MetaGpuKms * meta_gpu_kms_new (MetaBackendNative  *backend_native, | ||||
|                                MetaKmsDevice      *kms_device, | ||||
|                                GError            **error); | ||||
|  | ||||
| gboolean meta_gpu_kms_can_have_outputs (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); | ||||
| void meta_gpu_kms_set_power_save_mode (MetaGpuKms    *gpu_kms, | ||||
|                                        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; | ||||
|  | ||||
|   crtc = meta_output_get_assigned_crtc (output); | ||||
|   kms_fd = meta_gpu_kms_get_fd (gpu_kms); | ||||
|   connector_id = output_kms->connector->connector_id; | ||||
|  | ||||
|   if (output->is_underscanning && crtc && crtc->current_mode) | ||||
|   if (output->is_underscanning) | ||||
|     { | ||||
|       drmModeObjectSetProperty (kms_fd, connector_id, | ||||
|                                 DRM_MODE_OBJECT_CONNECTOR, | ||||
|                                 output_kms->underscan_prop_id, | ||||
|                                 (uint64_t) 1); | ||||
|       MetaCrtc *crtc; | ||||
|       uint64_t hborder, vborder; | ||||
|  | ||||
|       if (output_kms->underscan_hborder_prop_id) | ||||
|         { | ||||
|           uint64_t value; | ||||
|       crtc = meta_output_get_assigned_crtc (output); | ||||
|       hborder = MIN (128, (uint64_t) round (crtc->current_mode->width * 0.05)); | ||||
|       vborder = MIN (128, (uint64_t) round (crtc->current_mode->height * 0.05)); | ||||
|  | ||||
|           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; | ||||
|       g_debug ("Setting underscan of connector %s to %lu x %lu", | ||||
|                meta_kms_connector_get_name (output_kms->kms_connector), | ||||
|                hborder, vborder); | ||||
|  | ||||
|           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) | ||||
| meta_output_kms_set_power_save_mode (MetaOutput    *output, | ||||
|                                      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); | ||||
|   crtcs = g_array_new (FALSE, FALSE, sizeof (MetaCrtc *)); | ||||
|  | ||||
|   fd = meta_gpu_kms_get_fd (gpu_kms); | ||||
|  | ||||
|   crtc_mask = ~(unsigned int) 0; | ||||
|   for (i = 0; i < output_kms->n_encoders; i++) | ||||
|   for (l = meta_gpu_get_crtcs (gpu); l; l = l->next) | ||||
|     { | ||||
|       output_kms->encoders[i] = drmModeGetEncoder (fd, connector->encoders[i]); | ||||
|       if (!output_kms->encoders[i]) | ||||
|         continue; | ||||
|       MetaCrtc *crtc = l->data; | ||||
|       MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc); | ||||
|       uint32_t crtc_idx; | ||||
|  | ||||
|       /* 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)) | ||||
|         { | ||||
|           MetaCrtc *crtc = l->data; | ||||
|  | ||||
|           g_array_append_val (crtcs, crtc); | ||||
|         } | ||||
|       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" | ||||
| #include "backends/native/meta-kms-types.h" | ||||
|  | ||||
| void meta_output_kms_set_underscan (MetaOutput *output); | ||||
| void meta_output_kms_set_power_save_mode (MetaOutput    *output, | ||||
|                                           uint64_t       dpms_state, | ||||
|                                           MetaKmsUpdate *kms_update); | ||||
|  | ||||
| void meta_output_kms_set_power_save_mode (MetaOutput *output, | ||||
|                                           uint64_t    state); | ||||
| 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,8 +46,8 @@ typedef enum _MetaRendererNativeMode | ||||
| #endif | ||||
| } MetaRendererNativeMode; | ||||
|  | ||||
| MetaRendererNative * meta_renderer_native_new (MetaMonitorManagerKms *monitor_manager_kms, | ||||
|                                                GError               **error); | ||||
| 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,8 +28,13 @@ | ||||
|  | ||||
| #include "wayland/meta-wayland.h" | ||||
|  | ||||
| G_DEFINE_TYPE (MetaBackendX11Nested, meta_backend_x11_nested, | ||||
|                META_TYPE_BACKEND_X11) | ||||
| typedef struct _MetaBackendX11NestedPrivate | ||||
| { | ||||
|   MetaGpu *gpu; | ||||
| } MetaBackendX11NestedPrivate; | ||||
|  | ||||
| G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendX11Nested, meta_backend_x11_nested, | ||||
|                             META_TYPE_BACKEND_X11) | ||||
|  | ||||
| static MetaRenderer * | ||||
| meta_backend_x11_nested_create_renderer (MetaBackend *backend, | ||||
| @@ -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, | ||||
|                        uint64_t            winsys_id) | ||||
| 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