Compare commits

...

30 Commits

Author SHA1 Message Date
Georges Basile Stavracas Neto
cf9136ecd6 backend/native: Port gamma management to Atomic KMS API
As a side note: fun things happen when gamma is set wrong!
2019-06-19 20:43:27 -03:00
Georges Basile Stavracas Neto
6f436023ed native-renderer: Remove unused variables 2019-06-19 20:34:28 -03:00
Jonas Ådahl
d147cc3ece backends/native: Add some KMS debug logging
Using the g_debug() macro. Set G_DEBUG_MESSAGES to "mutter" to activate
log.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:52 -03:00
Jonas Ådahl
f980445a54 kms: Add high level code documentation
Document the high level components of the KMS abstraction.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:52 -03:00
Jonas Ådahl
5977c1a183 backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.

The API consists of various buliding blocks:

 * MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
 * MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.

This also means various high level changes:

State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.

From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.

EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.

Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.

While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:52 -03:00
Jonas Ådahl
ff6ef0edc4 logical-monitor: Pass output when iterating over CRTCs
While not currently used by any users, it'll be useful in future
commits.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:52 -03:00
Jonas Ådahl
9583632bd0 backend/native: Move some KMS utilities to its own file
They are not strictly related to any of the KMS objects, and should be
reusable without adding a dependency on the non-meta-kms-* files in
meta-kms-*.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:51 -03:00
Jonas Ådahl
0a1ea1407e kms: Add API to register impl file descriptors
To let the MetaKmsImpl implementation register file descriptor GSource
where the invoke function is ensured to be executed in the impl context.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:51 -03:00
Jonas Ådahl
8ba01d3373 kms: Add API to add a GSource that'll be invoked in the impl context
The MetaKmsImpl implementation may need to add a GSource that should be
invoked in the right context; e.g. a idle callback, timeout etc. It
cannot just add it itself, since it's the responsibility of MetaKms to
determine what is the impl context and what is the main context, so add
API to MetaKms to ensure the callback is invoked correctly.

It's the responsibility of the caller to eventually remove and destroy
the GSource.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:51 -03:00
Jonas Ådahl
a47d42f2c6 kms: Add API to post callbacks out of the impl context
While the current impl context is in the same thread as the main
context, the separation still exists, and to post callbacks from the
impl context, it must pass MetaKms to make sure the callback is invoked
in the right context.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:51 -03:00
Jonas Ådahl
1a0f53f5d2 gpu/kms: Remove unused typedef
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:51 -03:00
Jonas Ådahl
f627676878 crtc/kms: Use MetaKmsPlane to check supported rotations and formats
Instead of manually retrieving supported transforms and formats from the
primary plane of the CRTC, use the MetaKmsPlane abstraction to find the
primary plane of the CRTC and check compatibility using the
MetaKmsPlane API. This removes the last user of direct KMS API usage
except for applying configuration.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:50 -03:00
Jonas Ådahl
66079b676f gpu/kms: Init global mode list from MetaKmsConnectors
Instead of iterating over the available drmModeConnector objects to
construct a GPU wide mode list, use the state managed by
MetaKmsConnector. This also removes the last user of drmModeRes from
MetaGpuKms.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:50 -03:00
Jonas Ådahl
c3acb5a6e9 output/kms: Outsource connector state fetching to MetaKmsConnector
As with CRTC state, variable connector state is now fetched via the
MetaKmsConnector. The existance of a connector state is equivalent of
the connector being connected. MetaOutputKms is changed to fetch
variable connector state via MetaKmsConnector intsead of KMS directly.
The drmModeConnector is still used for constructing the MetaOutputKms to
find properties used for applying configuration.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:50 -03:00
Jonas Ådahl
dbcb6e3341 crtc/kms: Outsource CRTC state fetching to MetaKmsCrtc
Read moving state into a struct for MetaCrtcKms to use instead of
querying KMS itself. The state is fetched in the impl context, but
consists of only simple data types, so is made accessible publicly. As
of this, MetaCrtcKms construction does not involve any manual KMS
interaction outside of the MetaKms abstraction.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:50 -03:00
Jonas Ådahl
1f3210f795 crtc/kms: Don't redefine META_MONITOR_N_TRANSFORMS
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:49 -03:00
Jonas Ådahl
a0eac7b417 kms: Add connector representation
Represents drmModeConnector; both connected and disconnected. Currently
only provides non-changing meta data. MetaOutputKms is changed to use
MetaKmsConnector to get basic metadata, but variable metadata, those
changing depending on what is connected (e.g. physical dimension, EDID,
etc), are still manually retrieved by MetaOutputKms.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:49 -03:00
Jonas Ådahl
b9e1e28db8 gpu/kms: Fix connector id type in helper
It's a uint32_t, not a long.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:49 -03:00
Jonas Ådahl
3532766c3e output/kms: Make drmModeEncoderPtr array local
It was only used within one function, where it was always created, but
still was kept around indefinitely for no reason. Lets get rid of it
from the MetaOututKms struct.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:49 -03:00
Jonas Ådahl
881f7a07dc kms: Add plane representation
A plane are one of three possible: primary, overlay and cursor. Each
plane can have various properties, such as possible rotations, formats
etc. Each plane can also be used with a set of CRTCs.

A primary plane is the "backdrop" of a CRTC, i.e. the primary output for
the composited frame that covers the whole CRTC. In general, mutter
composites to a stage view frame onto a framebuffer that is then put on
the primary plane.

An overlay plane is a rectangular area that can be displayed on top of
the primary plane. Eventually it will be used to place non-fullscreen
surfaces, potentially avoiding stage redraws.

A cursor plane is a plane placed on top of all the other planes, usually
used to put the mouse cursor sprite.

Initially, we only fetch the rotation properties, and we so far
blacklist all rotations except ones that ends up with the same
dimensions as with no rotations. This is because non-180° rotations
doesn't work yet due to incorrect buffer modifiers. To make it possible
to use non-180° rotations, changes necessary include among other things
finding compatible modifiers using atomic modesetting. Until then,
simply blacklist the ones we know doesn't work.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:49 -03:00
Jonas Ådahl
a5e8aae839 kms: Add CRTC representation
Add MetaKmsCrtc to represent a CRTC on the associated device. Change
MetaCrtcKms to use the ones discovered by the KMS abstraction. It still
reads the resources handed over by MetaGpuKms, but eventually it will
use only MetaKmsCrtc.

MetaKmsCrtc is a type of object that is usable both from an impl task
and from outside. All the API exposed via the non-private header is
expected to be accessible from outside of the meta-kms namespace.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:48 -03:00
Jonas Ådahl
7dbe79474b backends/native: Add basic KMS abstraction building blocks
The intention weth KMS abstraction is to hide away accessing the drm
functions behind an API that allows us to have different kind of KMS
implementations, including legacy non-atomic and atomic. The intention
is also that the code interacting with the drm device should be able to
be run in a different thread than the main thread. This means that we
need to make sure that all drm*() API usage must only occur from within
tasks that eventually can be run in the dedicated thread.

The idea here is that MetaKms provides a outward facing API other places
of mutter can use (e.g. MetaGpuKms and friends), while MetaKmsImpl is
an internal implementation that only gets interacted with via "tasks"
posted via the MetaKms object. These tasks will in the future
potentially be run on the dedicated KMS thread. Initially, we don't
create any new threads.

Likewise, MetaKmsDevice is a outward facing representation of a KMS
device, while MetaKmsImplDevice is the corresponding implementation,
which only runs from within the MetaKmsImpl tasks.

This commit only moves opening and closing the device to this new API,
while leaking the fd outside of the impl enclosure, effectively making
the isolation for drm*() calls pointless. This, however, is necessary to
allow gradual porting of drm interaction, and eventually the file
descriptor in MetaGpuKms will be removed. For now, it's harmless, since
everything still run in the main thread.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:48 -03:00
Jonas Ådahl
02b549bd0d gpu/kms: Remove max buffer size getter
It was unused.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:48 -03:00
Jonas Ådahl
a56a6a43aa backend: Move GPU ownership from the monitor manager to the backend
Lets work towards making MetaMonitorManager about managing monitors, and
not about managing GPUs. This changes other units to keep a pointer to
the backend instead of a monitor manager, in case their ownership
changed, or their main usage of the monitor manager was to look up GPUs.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:48 -03:00
Jonas Ådahl
45190c46b5 monitor-manager/kms: Use 'hotplug' event from MetaUdev
Instead of dealing with udev details here, use the newly added 'hotplug'
event emitted from MetaUdev.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:47 -03:00
Jonas Ådahl
23ef452721 udev: Add 'hotplug' event
To be used my the monitor manager to handle hotplugs.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:47 -03:00
Jonas Ådahl
174387c4ea udev: Add helpers to list DRM devices
Will be used to move out some udev related logic when adding GPUs.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:47 -03:00
Jonas Ådahl
db50205b1f backends/native: Move some initialization from init() to initable_init()
This means we can report the errors properly, instead of logging a
warning and calling exit(1).

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:47 -03:00
Jonas Ådahl
63c3631850 backends/native: Add udev abstraction layer
To be used to signal devices added, hotplugs and other udev events.
Currently the only event emitted is when a device is added.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:47 -03:00
Jonas Ådahl
fc87b6137c backends/native: Remove instance private
The object struct definition itself is private, so the object instance
private serves no purpose. Thus, move the fields into the object struct
and remove the instance private struct.

https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-06-19 13:15:46 -03:00
75 changed files with 6645 additions and 2514 deletions

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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))

View 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 */

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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 (&params[0], G_TYPE_POINTER);
g_value_set_pointer (&params[0], flip_closure);
g_value_init (&params[1], G_TYPE_OBJECT);
g_value_set_object (&params[1], gpu_kms);
g_value_init (&params[2], G_TYPE_OBJECT);
g_value_set_object (&params[2], crtc);
g_value_init (&params[3], G_TYPE_INT64);
g_value_set_int64 (&params[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;
}

View File

@@ -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);

View 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 */

View 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;
}

View 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 */

View 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 */

View 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];
}
}

View 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 */

View 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 */

View 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;
}

View 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 */

View 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;
}

View 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 */

View 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;
}

View 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 */

View 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);
}

View 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 */

View 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 */

View 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);
}

View 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;
}

View 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 */

View 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 */

View 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 */

View 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 */

View 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);
}

View 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 */

View 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;
}

View 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 */

View 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;
}

View 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 */

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);

View 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);
}

View 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 */

View File

@@ -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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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

View File

@@ -1 +0,0 @@
VOID:OBJECT,OBJECT,INT64

View File

@@ -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;

View File

@@ -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',

View File

@@ -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;
}

View File

@@ -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
View 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
View 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 */

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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
};