Compare commits
30 Commits
wip/lantw/
...
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