backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
/*
|
|
|
|
* 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"
|
|
|
|
|
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-04-04 20:36:41 +00:00
|
|
|
#include <errno.h>
|
2019-01-29 17:33:00 +00:00
|
|
|
#include <xf86drm.h>
|
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
#include "backends/native/meta-backend-native.h"
|
|
|
|
#include "backends/native/meta-device-pool.h"
|
2019-03-08 15:23:15 +00:00
|
|
|
#include "backends/native/meta-kms-connector-private.h"
|
|
|
|
#include "backends/native/meta-kms-connector.h"
|
2019-01-29 17:33:00 +00:00
|
|
|
#include "backends/native/meta-kms-crtc-private.h"
|
|
|
|
#include "backends/native/meta-kms-crtc.h"
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
#include "backends/native/meta-kms-impl.h"
|
2020-07-02 09:54:56 +00:00
|
|
|
#include "backends/native/meta-kms-mode-private.h"
|
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-04-04 20:36:41 +00:00
|
|
|
#include "backends/native/meta-kms-page-flip-private.h"
|
2019-10-31 09:38:19 +00:00
|
|
|
#include "backends/native/meta-kms-plane-private.h"
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
#include "backends/native/meta-kms-plane.h"
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
#include "backends/native/meta-kms-private.h"
|
|
|
|
|
2020-07-02 09:54:56 +00:00
|
|
|
#include "meta-default-modes.h"
|
kms: Add way to run without mode setting
Currently our only entry point for DRM devices is MetaKms*, but in order
to run without being DRM master, we cannot use /dev/dri/card*, nor can
we be either of the existing MetaKmsImplDevice implementation (legacy
KMS, and atomic KMS), as they both depend on being DRM master.
Thus to handle running without being DRM master (i.e. headless), add a
"dummy" MetaKmsImplDevice implementation, that doesn't do any mode
setting at all, and that switches to operate on the render node, instead
of the card node itself.
This means we still use the same GBM code paths as the regular native
backend paths, except we never make use of any CRTC backed onscreen
framebuffers.
Eventually, this "dummy" MetaKmsImplDevice will be replaced separating
"KMS" device objects from "render" device objects, but that will require
more significant changes. It will, however, be necessary for e.g. going
from being headless, only having access to a render node, to turning
into a real session, with a seat, being DRM master, and having access to
a card node.
This is currently not hooked up, but will be in a later commit.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-19 13:54:45 +00:00
|
|
|
#include "meta-private-enum-types.h"
|
2020-07-02 09:54:56 +00:00
|
|
|
|
2020-07-16 20:17:04 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
|
|
|
|
PROP_DEVICE,
|
|
|
|
PROP_IMPL,
|
2021-04-06 10:14:24 +00:00
|
|
|
PROP_PATH,
|
kms: Add way to run without mode setting
Currently our only entry point for DRM devices is MetaKms*, but in order
to run without being DRM master, we cannot use /dev/dri/card*, nor can
we be either of the existing MetaKmsImplDevice implementation (legacy
KMS, and atomic KMS), as they both depend on being DRM master.
Thus to handle running without being DRM master (i.e. headless), add a
"dummy" MetaKmsImplDevice implementation, that doesn't do any mode
setting at all, and that switches to operate on the render node, instead
of the card node itself.
This means we still use the same GBM code paths as the regular native
backend paths, except we never make use of any CRTC backed onscreen
framebuffers.
Eventually, this "dummy" MetaKmsImplDevice will be replaced separating
"KMS" device objects from "render" device objects, but that will require
more significant changes. It will, however, be necessary for e.g. going
from being headless, only having access to a render node, to turning
into a real session, with a seat, being DRM master, and having access to
a card node.
This is currently not hooked up, but will be in a later commit.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-19 13:54:45 +00:00
|
|
|
PROP_FLAGS,
|
2020-07-16 20:17:04 +00:00
|
|
|
|
|
|
|
N_PROPS
|
|
|
|
};
|
|
|
|
|
|
|
|
static GParamSpec *obj_props[N_PROPS];
|
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
typedef struct _MetaKmsImplDevicePrivate
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
{
|
|
|
|
MetaKmsDevice *device;
|
|
|
|
MetaKmsImpl *impl;
|
|
|
|
|
2021-04-12 14:25:53 +00:00
|
|
|
int fd_hold_count;
|
2021-03-31 16:34:45 +00:00
|
|
|
MetaDeviceFile *device_file;
|
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-04-04 20:36:41 +00:00
|
|
|
GSource *fd_source;
|
2020-09-29 14:43:04 +00:00
|
|
|
char *path;
|
kms: Add way to run without mode setting
Currently our only entry point for DRM devices is MetaKms*, but in order
to run without being DRM master, we cannot use /dev/dri/card*, nor can
we be either of the existing MetaKmsImplDevice implementation (legacy
KMS, and atomic KMS), as they both depend on being DRM master.
Thus to handle running without being DRM master (i.e. headless), add a
"dummy" MetaKmsImplDevice implementation, that doesn't do any mode
setting at all, and that switches to operate on the render node, instead
of the card node itself.
This means we still use the same GBM code paths as the regular native
backend paths, except we never make use of any CRTC backed onscreen
framebuffers.
Eventually, this "dummy" MetaKmsImplDevice will be replaced separating
"KMS" device objects from "render" device objects, but that will require
more significant changes. It will, however, be necessary for e.g. going
from being headless, only having access to a render node, to turning
into a real session, with a seat, being DRM master, and having access to
a card node.
This is currently not hooked up, but will be in a later commit.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-19 13:54:45 +00:00
|
|
|
MetaKmsDeviceFlag flags;
|
2021-04-12 14:25:53 +00:00
|
|
|
gboolean has_latched_fd_hold;
|
2019-01-29 17:33:00 +00:00
|
|
|
|
2020-06-17 15:49:12 +00:00
|
|
|
char *driver_name;
|
|
|
|
char *driver_description;
|
|
|
|
|
2019-01-29 17:33:00 +00:00
|
|
|
GList *crtcs;
|
2019-03-08 15:23:15 +00:00
|
|
|
GList *connectors;
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
GList *planes;
|
2019-11-11 17:05:32 +00:00
|
|
|
|
|
|
|
MetaKmsDeviceCaps caps;
|
2020-07-02 09:54:56 +00:00
|
|
|
|
|
|
|
GList *fallback_modes;
|
2020-07-16 15:55:39 +00:00
|
|
|
} MetaKmsImplDevicePrivate;
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
|
2021-04-06 10:14:24 +00:00
|
|
|
static void
|
|
|
|
initable_iface_init (GInitableIface *iface);
|
|
|
|
|
2020-07-16 20:17:04 +00:00
|
|
|
G_DEFINE_TYPE_WITH_CODE (MetaKmsImplDevice, meta_kms_impl_device,
|
|
|
|
G_TYPE_OBJECT,
|
2021-04-06 10:14:24 +00:00
|
|
|
G_ADD_PRIVATE (MetaKmsImplDevice)
|
|
|
|
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
|
|
|
|
initable_iface_init))
|
|
|
|
|
|
|
|
G_DEFINE_QUARK (-meta-kms-error-quark, meta_kms_error)
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
|
|
|
|
MetaKmsDevice *
|
|
|
|
meta_kms_impl_device_get_device (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return priv->device;
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
}
|
|
|
|
|
2019-03-08 15:23:15 +00:00
|
|
|
GList *
|
|
|
|
meta_kms_impl_device_copy_connectors (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return g_list_copy (priv->connectors);
|
2019-03-08 15:23:15 +00:00
|
|
|
}
|
|
|
|
|
2019-01-29 17:33:00 +00:00
|
|
|
GList *
|
|
|
|
meta_kms_impl_device_copy_crtcs (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return g_list_copy (priv->crtcs);
|
2019-01-29 17:33:00 +00:00
|
|
|
}
|
|
|
|
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
GList *
|
|
|
|
meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return g_list_copy (priv->planes);
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 15:38:44 +00:00
|
|
|
GList *
|
|
|
|
meta_kms_impl_device_peek_connectors (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return priv->connectors;
|
|
|
|
}
|
|
|
|
|
2020-10-09 23:25:06 +00:00
|
|
|
GList *
|
|
|
|
meta_kms_impl_device_peek_crtcs (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return priv->crtcs;
|
|
|
|
}
|
|
|
|
|
|
|
|
GList *
|
|
|
|
meta_kms_impl_device_peek_planes (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return priv->planes;
|
|
|
|
}
|
|
|
|
|
2019-11-11 17:05:32 +00:00
|
|
|
const MetaKmsDeviceCaps *
|
|
|
|
meta_kms_impl_device_get_caps (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return &priv->caps;
|
2019-11-11 17:05:32 +00:00
|
|
|
}
|
|
|
|
|
2020-07-02 09:54:56 +00:00
|
|
|
GList *
|
|
|
|
meta_kms_impl_device_copy_fallback_modes (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return g_list_copy (priv->fallback_modes);
|
2020-07-02 09:54:56 +00:00
|
|
|
}
|
|
|
|
|
2020-06-17 15:49:12 +00:00
|
|
|
const char *
|
|
|
|
meta_kms_impl_device_get_driver_name (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return priv->driver_name;
|
2020-06-17 15:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
meta_kms_impl_device_get_driver_description (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return priv->driver_description;
|
2020-06-17 15:49:12 +00:00
|
|
|
}
|
|
|
|
|
2020-09-29 14:43:04 +00:00
|
|
|
const char *
|
|
|
|
meta_kms_impl_device_get_path (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
return priv->path;
|
|
|
|
}
|
|
|
|
|
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-04-04 20:36:41 +00:00
|
|
|
gboolean
|
|
|
|
meta_kms_impl_device_dispatch (MetaKmsImplDevice *impl_device,
|
|
|
|
GError **error)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2020-10-02 14:56:10 +00:00
|
|
|
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
|
2021-03-31 16:34:45 +00:00
|
|
|
int fd;
|
2020-07-16 15:55:39 +00:00
|
|
|
|
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-04-04 20:36:41 +00:00
|
|
|
drmEventContext drm_event_context;
|
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl));
|
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-04-04 20:36:41 +00:00
|
|
|
|
|
|
|
drm_event_context = (drmEventContext) { 0 };
|
2020-10-02 14:56:10 +00:00
|
|
|
klass->setup_drm_event_context (impl_device, &drm_event_context);
|
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-04-04 20:36:41 +00:00
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
fd = meta_device_file_get_fd (priv->device_file);
|
|
|
|
|
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-04-04 20:36:41 +00:00
|
|
|
while (TRUE)
|
|
|
|
{
|
2021-03-31 16:34:45 +00:00
|
|
|
if (drmHandleEvent (fd, &drm_event_context) != 0)
|
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-04-04 20:36:41 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
pfd.fd = fd;
|
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-04-04 20:36:41 +00:00
|
|
|
pfd.events = POLL_IN | POLL_ERR;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
ret = poll (&pfd, 1, -1);
|
|
|
|
}
|
|
|
|
while (ret == -1 && errno == EINTR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-11-08 22:47:48 +00:00
|
|
|
static gpointer
|
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-04-04 20:36:41 +00:00
|
|
|
kms_event_dispatch_in_impl (MetaKmsImpl *impl,
|
|
|
|
gpointer user_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevice *impl_device = user_data;
|
2019-11-08 22:47:48 +00:00
|
|
|
gboolean ret;
|
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-04-04 20:36:41 +00:00
|
|
|
|
2019-11-08 22:47:48 +00:00
|
|
|
ret = meta_kms_impl_device_dispatch (impl_device, error);
|
|
|
|
return GINT_TO_POINTER (ret);
|
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-04-04 20:36:41 +00:00
|
|
|
}
|
|
|
|
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
drmModePropertyPtr
|
|
|
|
meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device,
|
|
|
|
drmModeObjectProperties *props,
|
|
|
|
const char *prop_name,
|
|
|
|
int *out_idx)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2021-03-31 16:34:45 +00:00
|
|
|
int fd;
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl));
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
fd = meta_device_file_get_fd (priv->device_file);
|
|
|
|
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
for (i = 0; i < props->count_props; i++)
|
|
|
|
{
|
|
|
|
drmModePropertyPtr prop;
|
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
prop = drmModeGetProperty (fd, props->props[i]);
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
if (!prop)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (strcmp (prop->name, prop_name) == 0)
|
|
|
|
{
|
|
|
|
*out_idx = i;
|
|
|
|
return prop;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreeProperty (prop);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-11-11 17:05:32 +00:00
|
|
|
static void
|
|
|
|
init_caps (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2021-03-31 16:34:45 +00:00
|
|
|
int fd;
|
2019-11-11 17:05:32 +00:00
|
|
|
uint64_t cursor_width, cursor_height;
|
2021-03-29 09:48:59 +00:00
|
|
|
uint64_t prefer_shadow;
|
2021-03-29 09:56:49 +00:00
|
|
|
uint64_t uses_monotonic_clock;
|
2022-04-05 09:05:17 +00:00
|
|
|
uint64_t addfb2_modifiers;
|
2019-11-11 17:05:32 +00:00
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
fd = meta_device_file_get_fd (priv->device_file);
|
2019-11-11 17:05:32 +00:00
|
|
|
if (drmGetCap (fd, DRM_CAP_CURSOR_WIDTH, &cursor_width) == 0 &&
|
|
|
|
drmGetCap (fd, DRM_CAP_CURSOR_HEIGHT, &cursor_height) == 0)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
priv->caps.has_cursor_size = TRUE;
|
|
|
|
priv->caps.cursor_width = cursor_width;
|
|
|
|
priv->caps.cursor_height = cursor_height;
|
2019-11-11 17:05:32 +00:00
|
|
|
}
|
2021-03-29 09:48:59 +00:00
|
|
|
|
|
|
|
if (drmGetCap (fd, DRM_CAP_DUMB_PREFER_SHADOW, &prefer_shadow) == 0)
|
|
|
|
{
|
|
|
|
if (prefer_shadow)
|
|
|
|
g_message ("Device '%s' prefers shadow buffer", priv->path);
|
|
|
|
|
|
|
|
priv->caps.prefers_shadow_buffer = prefer_shadow;
|
|
|
|
}
|
2021-03-29 09:56:49 +00:00
|
|
|
|
|
|
|
if (drmGetCap (fd, DRM_CAP_TIMESTAMP_MONOTONIC, &uses_monotonic_clock) == 0)
|
|
|
|
{
|
|
|
|
priv->caps.uses_monotonic_clock = uses_monotonic_clock;
|
|
|
|
}
|
2022-04-05 09:05:17 +00:00
|
|
|
|
|
|
|
if (drmGetCap (fd, DRM_CAP_ADDFB2_MODIFIERS, &addfb2_modifiers) == 0)
|
|
|
|
{
|
|
|
|
priv->caps.addfb2_modifiers = (addfb2_modifiers != 0);
|
|
|
|
}
|
2019-11-11 17:05:32 +00:00
|
|
|
}
|
|
|
|
|
2019-01-29 17:33:00 +00:00
|
|
|
static void
|
|
|
|
init_crtcs (MetaKmsImplDevice *impl_device,
|
|
|
|
drmModeRes *drm_resources)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2019-01-29 17:33:00 +00:00
|
|
|
int idx;
|
2021-03-31 16:34:45 +00:00
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = meta_device_file_get_fd (priv->device_file);
|
2019-01-29 17:33:00 +00:00
|
|
|
|
|
|
|
for (idx = 0; idx < drm_resources->count_crtcs; idx++)
|
|
|
|
{
|
2020-09-23 15:07:37 +00:00
|
|
|
uint32_t crtc_id;
|
2019-01-29 17:33:00 +00:00
|
|
|
drmModeCrtc *drm_crtc;
|
|
|
|
MetaKmsCrtc *crtc;
|
2020-09-23 15:07:37 +00:00
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
|
|
|
crtc_id = drm_resources->crtcs[idx];
|
2021-03-31 16:34:45 +00:00
|
|
|
drm_crtc = drmModeGetCrtc (fd, crtc_id);
|
2020-09-23 15:07:37 +00:00
|
|
|
if (!drm_crtc)
|
|
|
|
{
|
|
|
|
g_warning ("Failed to get CRTC %u info on '%s': %s",
|
|
|
|
crtc_id, priv->path, error->message);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
crtc = meta_kms_crtc_new (impl_device, drm_crtc, idx, &error);
|
2019-01-29 17:33:00 +00:00
|
|
|
|
|
|
|
drmModeFreeCrtc (drm_crtc);
|
|
|
|
|
2020-09-23 15:07:37 +00:00
|
|
|
if (!crtc)
|
|
|
|
{
|
|
|
|
g_warning ("Failed to create CRTC for %u on '%s': %s",
|
|
|
|
crtc_id, priv->path, error->message);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
priv->crtcs = g_list_prepend (priv->crtcs, crtc);
|
2019-01-29 17:33:00 +00:00
|
|
|
}
|
2020-07-16 15:55:39 +00:00
|
|
|
priv->crtcs = g_list_reverse (priv->crtcs);
|
2019-01-29 17:33:00 +00:00
|
|
|
}
|
|
|
|
|
2019-08-22 12:26:54 +00:00
|
|
|
static MetaKmsConnector *
|
|
|
|
find_existing_connector (MetaKmsImplDevice *impl_device,
|
|
|
|
drmModeConnector *drm_connector)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2019-08-22 12:26:54 +00:00
|
|
|
GList *l;
|
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
for (l = priv->connectors; l; l = l->next)
|
2019-08-22 12:26:54 +00:00
|
|
|
{
|
|
|
|
MetaKmsConnector *connector = l->data;
|
|
|
|
|
|
|
|
if (meta_kms_connector_is_same_as (connector, drm_connector))
|
|
|
|
return connector;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-03-17 09:22:05 +00:00
|
|
|
static MetaKmsResourceChanges
|
2019-08-22 12:26:54 +00:00
|
|
|
update_connectors (MetaKmsImplDevice *impl_device,
|
|
|
|
drmModeRes *drm_resources)
|
2019-03-08 15:23:15 +00:00
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2020-07-31 19:37:17 +00:00
|
|
|
g_autolist (MetaKmsConnector) connectors = NULL;
|
2021-11-18 16:34:40 +00:00
|
|
|
gboolean added_connector = FALSE;
|
2019-03-08 15:23:15 +00:00
|
|
|
unsigned int i;
|
2021-03-31 16:34:45 +00:00
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = meta_device_file_get_fd (priv->device_file);
|
2019-03-08 15:23:15 +00:00
|
|
|
|
|
|
|
for (i = 0; i < drm_resources->count_connectors; i++)
|
|
|
|
{
|
|
|
|
drmModeConnector *drm_connector;
|
|
|
|
MetaKmsConnector *connector;
|
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
drm_connector = drmModeGetConnector (fd, drm_resources->connectors[i]);
|
2019-08-02 20:48:41 +00:00
|
|
|
if (!drm_connector)
|
|
|
|
continue;
|
|
|
|
|
2019-08-22 12:26:54 +00:00
|
|
|
connector = find_existing_connector (impl_device, drm_connector);
|
|
|
|
if (connector)
|
2020-07-31 19:37:17 +00:00
|
|
|
{
|
|
|
|
connector = g_object_ref (connector);
|
|
|
|
}
|
2019-08-22 12:26:54 +00:00
|
|
|
else
|
2020-07-31 19:37:17 +00:00
|
|
|
{
|
|
|
|
connector = meta_kms_connector_new (impl_device, drm_connector,
|
|
|
|
drm_resources);
|
2021-11-18 16:34:40 +00:00
|
|
|
added_connector = TRUE;
|
2020-07-31 19:37:17 +00:00
|
|
|
}
|
|
|
|
|
2019-03-08 15:23:15 +00:00
|
|
|
drmModeFreeConnector (drm_connector);
|
|
|
|
|
2019-08-22 12:26:54 +00:00
|
|
|
connectors = g_list_prepend (connectors, connector);
|
2019-03-08 15:23:15 +00:00
|
|
|
}
|
2019-08-22 12:26:54 +00:00
|
|
|
|
2021-11-18 16:34:40 +00:00
|
|
|
if (!added_connector &&
|
|
|
|
g_list_length (connectors) == g_list_length (priv->connectors))
|
2022-03-17 09:22:05 +00:00
|
|
|
return META_KMS_RESOURCE_CHANGE_NONE;
|
2020-07-31 19:37:17 +00:00
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
g_list_free_full (priv->connectors, g_object_unref);
|
2020-07-31 19:37:17 +00:00
|
|
|
priv->connectors = g_list_reverse (g_steal_pointer (&connectors));
|
|
|
|
|
2022-03-17 09:22:05 +00:00
|
|
|
return META_KMS_RESOURCE_CHANGE_FULL;
|
2019-03-08 15:23:15 +00:00
|
|
|
}
|
|
|
|
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
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:
|
2019-09-06 09:54:00 +00:00
|
|
|
g_warning ("Unhandled plane type %" G_GUINT64_FORMAT,
|
|
|
|
props->prop_values[idx]);
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-21 11:06:28 +00:00
|
|
|
MetaKmsPlane *
|
|
|
|
meta_kms_impl_device_add_fake_plane (MetaKmsImplDevice *impl_device,
|
|
|
|
MetaKmsPlaneType plane_type,
|
|
|
|
MetaKmsCrtc *crtc)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2020-02-21 11:06:28 +00:00
|
|
|
MetaKmsPlane *plane;
|
|
|
|
|
|
|
|
plane = meta_kms_plane_new_fake (plane_type, crtc);
|
2020-07-16 15:55:39 +00:00
|
|
|
priv->planes = g_list_append (priv->planes, plane);
|
2020-02-21 11:06:28 +00:00
|
|
|
|
|
|
|
return plane;
|
|
|
|
}
|
|
|
|
|
2022-04-20 19:52:10 +00:00
|
|
|
uint64_t
|
|
|
|
meta_kms_prop_convert_value (MetaKmsProp *prop,
|
|
|
|
uint64_t value)
|
|
|
|
{
|
|
|
|
switch (prop->type)
|
|
|
|
{
|
|
|
|
case DRM_MODE_PROP_RANGE:
|
|
|
|
case DRM_MODE_PROP_SIGNED_RANGE:
|
|
|
|
case DRM_MODE_PROP_BLOB:
|
|
|
|
case DRM_MODE_PROP_OBJECT:
|
|
|
|
return value;
|
|
|
|
case DRM_MODE_PROP_ENUM:
|
|
|
|
g_assert (prop->enum_values[value].valid);
|
|
|
|
return prop->enum_values[value].value;
|
|
|
|
case DRM_MODE_PROP_BITMASK:
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uint64_t result = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < prop->num_enum_values; i++)
|
|
|
|
{
|
|
|
|
if (!prop->enum_values[i].valid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (value & prop->enum_values[i].bitmask)
|
|
|
|
{
|
|
|
|
result |= (1 << prop->enum_values[i].value);
|
|
|
|
value &= ~(prop->enum_values[i].bitmask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert (value == 0);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_prop_value (MetaKmsProp *prop,
|
|
|
|
uint64_t drm_value)
|
|
|
|
{
|
|
|
|
switch (prop->type)
|
|
|
|
{
|
|
|
|
case DRM_MODE_PROP_RANGE:
|
|
|
|
case DRM_MODE_PROP_SIGNED_RANGE:
|
|
|
|
case DRM_MODE_PROP_BLOB:
|
|
|
|
case DRM_MODE_PROP_OBJECT:
|
|
|
|
prop->value = drm_value;
|
|
|
|
return;
|
|
|
|
case DRM_MODE_PROP_ENUM:
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < prop->num_enum_values; i++)
|
|
|
|
{
|
|
|
|
if (prop->enum_values[i].valid &&
|
|
|
|
prop->enum_values[i].value == drm_value)
|
|
|
|
{
|
|
|
|
prop->value = i;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
prop->value = prop->default_value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case DRM_MODE_PROP_BITMASK:
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uint64_t result = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < prop->num_enum_values; i++)
|
|
|
|
{
|
|
|
|
if (!prop->enum_values[i].valid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (drm_value & (1 << prop->enum_values[i].value))
|
|
|
|
{
|
|
|
|
result |= prop->enum_values[i].bitmask;
|
|
|
|
drm_value &= ~(1 << prop->enum_values[i].value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (drm_value != 0)
|
|
|
|
result |= prop->default_value;
|
|
|
|
|
|
|
|
prop->value = result;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_prop_enum_value(MetaKmsEnum *prop_enum,
|
|
|
|
drmModePropertyRes *drm_prop)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < drm_prop->count_enums; i++)
|
|
|
|
{
|
|
|
|
if (strcmp (prop_enum->name, drm_prop->enums[i].name) == 0)
|
|
|
|
{
|
|
|
|
prop_enum->value = drm_prop->enums[i].value;
|
|
|
|
prop_enum->valid = TRUE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
prop_enum->valid = FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-13 19:42:04 +00:00
|
|
|
static MetaKmsProp *
|
|
|
|
find_prop (MetaKmsProp *props,
|
|
|
|
int n_props,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < n_props; i++)
|
|
|
|
{
|
|
|
|
MetaKmsProp *prop = &props[i];
|
|
|
|
|
|
|
|
g_warn_if_fail (prop->name);
|
|
|
|
|
|
|
|
if (g_strcmp0 (prop->name, name) == 0)
|
|
|
|
return prop;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-04-20 20:43:13 +00:00
|
|
|
meta_kms_impl_device_update_prop_table (MetaKmsImplDevice *impl_device,
|
|
|
|
uint32_t *drm_props,
|
|
|
|
uint64_t *drm_prop_values,
|
|
|
|
int n_drm_props,
|
|
|
|
MetaKmsProp *props,
|
|
|
|
int n_props)
|
2020-07-13 19:42:04 +00:00
|
|
|
{
|
|
|
|
int fd;
|
2022-04-20 19:52:10 +00:00
|
|
|
uint32_t i, j;
|
2020-07-13 19:42:04 +00:00
|
|
|
|
|
|
|
fd = meta_kms_impl_device_get_fd (impl_device);
|
|
|
|
|
2022-04-20 19:52:10 +00:00
|
|
|
for (i = 0; i < n_props; i++)
|
|
|
|
{
|
|
|
|
MetaKmsProp *prop = &props[i];
|
|
|
|
|
|
|
|
prop->prop_id = 0;
|
|
|
|
prop->value = 0;
|
|
|
|
|
|
|
|
for (j = 0; j < prop->num_enum_values; j++)
|
|
|
|
{
|
|
|
|
prop->enum_values[j].valid = FALSE;
|
|
|
|
prop->enum_values[j].value = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-13 19:42:04 +00:00
|
|
|
for (i = 0; i < n_drm_props; i++)
|
|
|
|
{
|
2022-04-20 19:52:10 +00:00
|
|
|
uint32_t prop_id;
|
|
|
|
uint64_t prop_value;
|
2020-07-13 19:42:04 +00:00
|
|
|
drmModePropertyRes *drm_prop;
|
|
|
|
MetaKmsProp *prop;
|
|
|
|
|
2022-04-20 19:52:10 +00:00
|
|
|
prop_id = drm_props[i];
|
|
|
|
prop_value = drm_prop_values[i];
|
|
|
|
|
|
|
|
drm_prop = drmModeGetProperty (fd, prop_id);
|
2020-07-13 19:42:04 +00:00
|
|
|
if (!drm_prop)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
prop = find_prop (props, n_props, drm_prop->name);
|
|
|
|
if (!prop)
|
|
|
|
{
|
|
|
|
drmModeFreeProperty (drm_prop);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(drm_prop->flags & prop->type))
|
|
|
|
{
|
|
|
|
g_warning ("DRM property '%s' (%u) had unexpected flags (0x%x), "
|
|
|
|
"ignoring",
|
2022-04-20 19:52:10 +00:00
|
|
|
drm_prop->name, prop_id, drm_prop->flags);
|
2020-07-13 19:42:04 +00:00
|
|
|
drmModeFreeProperty (drm_prop);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-04-20 19:52:10 +00:00
|
|
|
prop->prop_id = prop_id;
|
|
|
|
|
|
|
|
if (prop->type == DRM_MODE_PROP_BITMASK ||
|
|
|
|
prop->type == DRM_MODE_PROP_ENUM)
|
|
|
|
{
|
|
|
|
for (j = 0; j < prop->num_enum_values; j++)
|
|
|
|
update_prop_enum_value (&prop->enum_values[j], drm_prop);
|
|
|
|
}
|
|
|
|
|
|
|
|
update_prop_value (prop, prop_value);
|
2020-07-13 19:42:04 +00:00
|
|
|
|
2022-06-14 08:27:53 +00:00
|
|
|
if (prop->type == DRM_MODE_PROP_RANGE)
|
|
|
|
{
|
|
|
|
if (drm_prop->count_values == 2)
|
|
|
|
{
|
|
|
|
prop->range_min = drm_prop->values[0];
|
|
|
|
prop->range_max = drm_prop->values[1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("DRM property '%s' is a range with %d values, ignoring",
|
|
|
|
drm_prop->name, drm_prop->count_values);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-13 19:42:04 +00:00
|
|
|
drmModeFreeProperty (drm_prop);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
static void
|
|
|
|
init_planes (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2021-03-31 16:34:45 +00:00
|
|
|
int fd;
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
drmModePlaneRes *drm_planes;
|
|
|
|
unsigned int i;
|
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
fd = meta_device_file_get_fd (priv->device_file);
|
|
|
|
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
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);
|
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
priv->planes = g_list_prepend (priv->planes, plane);
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_clear_pointer (&props, drmModeFreeObjectProperties);
|
|
|
|
drmModeFreePlane (drm_plane);
|
|
|
|
}
|
2020-07-16 15:55:39 +00:00
|
|
|
priv->planes = g_list_reverse (priv->planes);
|
kms: Add plane representation
A plane is 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-01-31 17:48:19 +00:00
|
|
|
}
|
|
|
|
|
2020-07-02 09:54:56 +00:00
|
|
|
static void
|
|
|
|
init_fallback_modes (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2020-07-02 09:54:56 +00:00
|
|
|
GList *modes = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (meta_default_landscape_drm_mode_infos); i++)
|
|
|
|
{
|
|
|
|
MetaKmsMode *mode;
|
|
|
|
|
|
|
|
mode = meta_kms_mode_new (impl_device,
|
|
|
|
&meta_default_landscape_drm_mode_infos[i],
|
|
|
|
META_KMS_MODE_FLAG_FALLBACK_LANDSCAPE);
|
|
|
|
modes = g_list_prepend (modes, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (meta_default_portrait_drm_mode_infos); i++)
|
|
|
|
{
|
|
|
|
MetaKmsMode *mode;
|
|
|
|
|
|
|
|
mode = meta_kms_mode_new (impl_device,
|
|
|
|
&meta_default_portrait_drm_mode_infos[i],
|
|
|
|
META_KMS_MODE_FLAG_FALLBACK_PORTRAIT);
|
|
|
|
modes = g_list_prepend (modes, mode);
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
priv->fallback_modes = g_list_reverse (modes);
|
2020-07-02 09:54:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-12 14:25:53 +00:00
|
|
|
static MetaDeviceFile *
|
|
|
|
meta_kms_impl_device_open_device_file (MetaKmsImplDevice *impl_device,
|
|
|
|
const char *path,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
|
|
|
|
|
|
|
|
return klass->open_device_file (impl_device, priv->path, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
ensure_device_file (MetaKmsImplDevice *impl_device,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
MetaDeviceFile *device_file;
|
|
|
|
|
|
|
|
if (priv->device_file)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
device_file = meta_kms_impl_device_open_device_file (impl_device,
|
|
|
|
priv->path,
|
|
|
|
error);
|
|
|
|
if (!device_file)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
priv->device_file = device_file;
|
|
|
|
|
|
|
|
if (!(priv->flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING))
|
|
|
|
{
|
|
|
|
priv->fd_source =
|
|
|
|
meta_kms_register_fd_in_impl (meta_kms_impl_get_kms (priv->impl),
|
|
|
|
meta_device_file_get_fd (device_file),
|
|
|
|
kms_event_dispatch_in_impl,
|
|
|
|
impl_device);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ensure_latched_fd_hold (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
if (!priv->has_latched_fd_hold)
|
|
|
|
{
|
|
|
|
meta_kms_impl_device_hold_fd (impl_device);
|
|
|
|
priv->has_latched_fd_hold = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clear_latched_fd_hold (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
if (priv->has_latched_fd_hold)
|
|
|
|
{
|
|
|
|
meta_kms_impl_device_unhold_fd (impl_device);
|
|
|
|
priv->has_latched_fd_hold = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-17 09:22:05 +00:00
|
|
|
MetaKmsResourceChanges
|
2020-08-04 17:28:04 +00:00
|
|
|
meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device,
|
|
|
|
uint32_t crtc_id,
|
|
|
|
uint32_t connector_id)
|
2019-03-08 18:19:18 +00:00
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2021-04-12 14:25:53 +00:00
|
|
|
g_autoptr (GError) error = NULL;
|
2021-03-31 16:34:45 +00:00
|
|
|
int fd;
|
2019-03-09 14:55:24 +00:00
|
|
|
drmModeRes *drm_resources;
|
2022-03-17 09:22:05 +00:00
|
|
|
MetaKmsResourceChanges changes;
|
2020-07-31 19:37:17 +00:00
|
|
|
GList *l;
|
2019-03-09 14:55:24 +00:00
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl));
|
2020-12-15 21:45:05 +00:00
|
|
|
|
|
|
|
meta_topic (META_DEBUG_KMS, "Updating device state for %s", priv->path);
|
2019-03-08 18:19:18 +00:00
|
|
|
|
2021-04-12 14:25:53 +00:00
|
|
|
if (!ensure_device_file (impl_device, &error))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to reopen '%s': %s", priv->path, error->message);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ensure_latched_fd_hold (impl_device);
|
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
fd = meta_device_file_get_fd (priv->device_file);
|
|
|
|
drm_resources = drmModeGetResources (fd);
|
2020-03-11 10:46:48 +00:00
|
|
|
if (!drm_resources)
|
|
|
|
{
|
2021-04-12 14:25:53 +00:00
|
|
|
meta_topic (META_DEBUG_KMS, "Device '%s' didn't return any resources",
|
|
|
|
priv->path);
|
|
|
|
goto err;
|
2020-03-11 10:46:48 +00:00
|
|
|
}
|
2019-08-22 12:26:54 +00:00
|
|
|
|
2020-07-31 19:37:17 +00:00
|
|
|
changes = update_connectors (impl_device, drm_resources);
|
|
|
|
|
|
|
|
for (l = priv->crtcs; l; l = l->next)
|
2020-08-04 17:28:04 +00:00
|
|
|
{
|
|
|
|
MetaKmsCrtc *crtc = META_KMS_CRTC (l->data);
|
|
|
|
|
|
|
|
if (crtc_id > 0 &&
|
|
|
|
meta_kms_crtc_get_id (crtc) != crtc_id)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
changes |= meta_kms_crtc_update_state (crtc);
|
|
|
|
}
|
2020-07-31 19:37:17 +00:00
|
|
|
|
|
|
|
for (l = priv->connectors; l; l = l->next)
|
2020-08-04 17:28:04 +00:00
|
|
|
{
|
|
|
|
MetaKmsConnector *connector = META_KMS_CONNECTOR (l->data);
|
|
|
|
|
|
|
|
if (connector_id > 0 &&
|
|
|
|
meta_kms_connector_get_id (connector) != connector_id)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
changes |= meta_kms_connector_update_state (connector, drm_resources);
|
|
|
|
}
|
2019-08-22 12:26:54 +00:00
|
|
|
|
2019-03-09 14:55:24 +00:00
|
|
|
drmModeFreeResources (drm_resources);
|
2021-04-12 14:25:53 +00:00
|
|
|
|
2020-07-31 19:37:17 +00:00
|
|
|
return changes;
|
2021-04-12 14:25:53 +00:00
|
|
|
|
|
|
|
err:
|
|
|
|
g_clear_list (&priv->planes, g_object_unref);
|
|
|
|
g_clear_list (&priv->crtcs, g_object_unref);
|
|
|
|
g_clear_list (&priv->connectors, g_object_unref);
|
2020-07-31 19:37:17 +00:00
|
|
|
|
2022-03-17 09:22:05 +00:00
|
|
|
return META_KMS_RESOURCE_CHANGE_FULL;
|
2019-03-08 18:19:18 +00:00
|
|
|
}
|
|
|
|
|
2022-03-17 09:33:23 +00:00
|
|
|
static MetaKmsResourceChanges
|
2019-10-04 09:54:29 +00:00
|
|
|
meta_kms_impl_device_predict_states (MetaKmsImplDevice *impl_device,
|
|
|
|
MetaKmsUpdate *update)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2022-03-17 09:33:23 +00:00
|
|
|
MetaKmsResourceChanges changes = META_KMS_RESOURCE_CHANGE_NONE;
|
|
|
|
GList *l;
|
2020-07-16 15:55:39 +00:00
|
|
|
|
2022-07-26 09:02:32 +00:00
|
|
|
g_list_foreach (priv->crtcs, (GFunc) meta_kms_crtc_predict_state, update);
|
2022-03-17 09:33:23 +00:00
|
|
|
|
|
|
|
for (l = priv->connectors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaKmsConnector *connector = l->data;
|
|
|
|
|
|
|
|
changes |= meta_kms_connector_predict_state (connector, update);
|
|
|
|
}
|
|
|
|
|
|
|
|
return changes;
|
2019-10-04 09:54:29 +00:00
|
|
|
}
|
|
|
|
|
2021-04-12 14:25:53 +00:00
|
|
|
void
|
|
|
|
meta_kms_impl_device_notify_modes_set (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
clear_latched_fd_hold (impl_device);
|
|
|
|
}
|
|
|
|
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
int
|
|
|
|
meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl));
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
return meta_device_file_get_fd (priv->device_file);
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
}
|
|
|
|
|
2022-03-17 09:33:23 +00:00
|
|
|
static void
|
|
|
|
emit_resources_changed_callback (MetaKms *kms,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaKmsResourceChanges changes = GPOINTER_TO_UINT (user_data);
|
|
|
|
|
|
|
|
meta_kms_emit_resources_changed (kms, changes);
|
|
|
|
}
|
|
|
|
|
2020-07-17 07:38:11 +00:00
|
|
|
MetaKmsFeedback *
|
|
|
|
meta_kms_impl_device_process_update (MetaKmsImplDevice *impl_device,
|
kms: Gracefully handle page flipping direct scanouts failing
When drmModePageFlip() or drmModeAtomicCommit() unexpectedly failed (e.g.
ENOSPC, which has been seen in the wild), this failure was not handled
very gracefully. The page flip listener for the scanout was left in the
MetaKmsUpdate, meaning when the primary plane composition was later page
flipped, two page flip listeners were added, one for the primary plane,
and one for the scanout. This caused the 'page-flipped' event to be
handled twice, the second time being fatal.
Handle this by making 'no-discard' listener flag be somewhat reversed,
and say 'drop-on-error', and then drop all 'drop-on-error' listeners
when a MetaKmsUpdate failed to be processed.
Also for a "preserve" flagged update, don't ever trigger "discard"
callbacks just yet, as preserved updates are used again for the primary
plane composition, in order to not miss e.g. CRTC gamma updates, or
cursor plane updates, which were added separately.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1809
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1910>
2021-07-01 17:45:03 +00:00
|
|
|
MetaKmsUpdate *update,
|
|
|
|
MetaKmsUpdateFlag flags)
|
2020-07-17 07:38:11 +00:00
|
|
|
{
|
2022-03-17 09:33:23 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2020-07-17 07:38:11 +00:00
|
|
|
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
|
2021-04-12 14:25:53 +00:00
|
|
|
MetaKmsFeedback *feedback;
|
|
|
|
g_autoptr (GError) error = NULL;
|
2022-03-17 09:33:23 +00:00
|
|
|
MetaKmsResourceChanges changes = META_KMS_RESOURCE_CHANGE_NONE;
|
2021-04-12 14:25:53 +00:00
|
|
|
|
|
|
|
if (!ensure_device_file (impl_device, &error))
|
|
|
|
return meta_kms_feedback_new_failed (NULL, g_steal_pointer (&error));
|
|
|
|
|
|
|
|
meta_kms_impl_device_hold_fd (impl_device);
|
|
|
|
feedback = klass->process_update (impl_device, update, flags);
|
2021-06-24 10:30:00 +00:00
|
|
|
if (!(flags & META_KMS_UPDATE_FLAG_TEST_ONLY))
|
2022-03-17 09:33:23 +00:00
|
|
|
changes = meta_kms_impl_device_predict_states (impl_device, update);
|
2021-04-12 14:25:53 +00:00
|
|
|
meta_kms_impl_device_unhold_fd (impl_device);
|
2020-07-17 07:38:11 +00:00
|
|
|
|
2022-03-17 09:33:23 +00:00
|
|
|
if (changes != META_KMS_RESOURCE_CHANGE_NONE)
|
|
|
|
{
|
|
|
|
MetaKms *kms = meta_kms_device_get_kms (priv->device);
|
|
|
|
|
|
|
|
meta_kms_queue_callback (kms,
|
|
|
|
emit_resources_changed_callback,
|
|
|
|
GUINT_TO_POINTER (changes), NULL);
|
|
|
|
}
|
2021-04-12 14:25:53 +00:00
|
|
|
return feedback;
|
2020-07-17 07:38:11 +00:00
|
|
|
}
|
|
|
|
|
2021-06-28 08:11:31 +00:00
|
|
|
void
|
|
|
|
meta_kms_impl_device_disable (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
|
|
|
|
|
|
|
|
if (!priv->device_file)
|
|
|
|
return;
|
|
|
|
|
|
|
|
meta_kms_impl_device_hold_fd (impl_device);
|
|
|
|
klass->disable (impl_device);
|
|
|
|
g_list_foreach (priv->crtcs, (GFunc) meta_kms_crtc_disable, NULL);
|
|
|
|
g_list_foreach (priv->connectors, (GFunc) meta_kms_connector_disable, NULL);
|
|
|
|
meta_kms_impl_device_unhold_fd (impl_device);
|
|
|
|
}
|
|
|
|
|
2020-10-02 14:56:10 +00:00
|
|
|
void
|
2020-07-17 07:38:11 +00:00
|
|
|
meta_kms_impl_device_handle_page_flip_callback (MetaKmsImplDevice *impl_device,
|
|
|
|
MetaKmsPageFlipData *page_flip_data)
|
|
|
|
{
|
|
|
|
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
|
|
|
|
|
|
|
|
klass->handle_page_flip_callback (impl_device, page_flip_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_kms_impl_device_discard_pending_page_flips (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
|
|
|
|
|
|
|
|
klass->discard_pending_page_flips (impl_device);
|
|
|
|
}
|
|
|
|
|
2021-04-12 14:25:53 +00:00
|
|
|
void
|
|
|
|
meta_kms_impl_device_hold_fd (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
MetaKms *kms = meta_kms_device_get_kms (priv->device);
|
|
|
|
|
|
|
|
meta_assert_in_kms_impl (kms);
|
|
|
|
|
|
|
|
g_assert (priv->device_file);
|
|
|
|
|
|
|
|
priv->fd_hold_count++;
|
|
|
|
}
|
|
|
|
|
2021-06-11 17:42:41 +00:00
|
|
|
static void
|
|
|
|
clear_fd_source (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
if (!priv->fd_source)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_source_destroy (priv->fd_source);
|
|
|
|
g_clear_pointer (&priv->fd_source, g_source_unref);
|
|
|
|
}
|
|
|
|
|
2021-04-12 14:25:53 +00:00
|
|
|
void
|
|
|
|
meta_kms_impl_device_unhold_fd (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
MetaKms *kms = meta_kms_device_get_kms (priv->device);
|
|
|
|
|
|
|
|
meta_assert_in_kms_impl (kms);
|
|
|
|
|
|
|
|
g_return_if_fail (priv->fd_hold_count > 0);
|
|
|
|
|
|
|
|
priv->fd_hold_count--;
|
|
|
|
if (priv->fd_hold_count == 0)
|
|
|
|
{
|
|
|
|
g_clear_pointer (&priv->device_file, meta_device_file_release);
|
2021-06-11 17:42:41 +00:00
|
|
|
clear_fd_source (impl_device);
|
2021-04-12 14:25:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-16 20:17:04 +00:00
|
|
|
static void
|
|
|
|
meta_kms_impl_device_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (object);
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_DEVICE:
|
|
|
|
g_value_set_object (value, priv->device);
|
|
|
|
break;
|
|
|
|
case PROP_IMPL:
|
|
|
|
g_value_set_object (value, priv->impl);
|
|
|
|
break;
|
kms: Add way to run without mode setting
Currently our only entry point for DRM devices is MetaKms*, but in order
to run without being DRM master, we cannot use /dev/dri/card*, nor can
we be either of the existing MetaKmsImplDevice implementation (legacy
KMS, and atomic KMS), as they both depend on being DRM master.
Thus to handle running without being DRM master (i.e. headless), add a
"dummy" MetaKmsImplDevice implementation, that doesn't do any mode
setting at all, and that switches to operate on the render node, instead
of the card node itself.
This means we still use the same GBM code paths as the regular native
backend paths, except we never make use of any CRTC backed onscreen
framebuffers.
Eventually, this "dummy" MetaKmsImplDevice will be replaced separating
"KMS" device objects from "render" device objects, but that will require
more significant changes. It will, however, be necessary for e.g. going
from being headless, only having access to a render node, to turning
into a real session, with a seat, being DRM master, and having access to
a card node.
This is currently not hooked up, but will be in a later commit.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-19 13:54:45 +00:00
|
|
|
case PROP_FLAGS:
|
|
|
|
g_value_set_flags (value, priv->flags);
|
|
|
|
break;
|
2020-07-16 20:17:04 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_kms_impl_device_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (object);
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_DEVICE:
|
|
|
|
priv->device = g_value_get_object (value);
|
|
|
|
break;
|
|
|
|
case PROP_IMPL:
|
|
|
|
priv->impl = g_value_get_object (value);
|
|
|
|
break;
|
2021-04-06 10:14:24 +00:00
|
|
|
case PROP_PATH:
|
|
|
|
priv->path = g_value_dup_string (value);
|
2020-09-29 14:43:04 +00:00
|
|
|
break;
|
kms: Add way to run without mode setting
Currently our only entry point for DRM devices is MetaKms*, but in order
to run without being DRM master, we cannot use /dev/dri/card*, nor can
we be either of the existing MetaKmsImplDevice implementation (legacy
KMS, and atomic KMS), as they both depend on being DRM master.
Thus to handle running without being DRM master (i.e. headless), add a
"dummy" MetaKmsImplDevice implementation, that doesn't do any mode
setting at all, and that switches to operate on the render node, instead
of the card node itself.
This means we still use the same GBM code paths as the regular native
backend paths, except we never make use of any CRTC backed onscreen
framebuffers.
Eventually, this "dummy" MetaKmsImplDevice will be replaced separating
"KMS" device objects from "render" device objects, but that will require
more significant changes. It will, however, be necessary for e.g. going
from being headless, only having access to a render node, to turning
into a real session, with a seat, being DRM master, and having access to
a card node.
This is currently not hooked up, but will be in a later commit.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-19 13:54:45 +00:00
|
|
|
case PROP_FLAGS:
|
|
|
|
priv->flags = g_value_get_flags (value);
|
|
|
|
break;
|
2020-07-16 20:17:04 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-29 17:33:00 +00:00
|
|
|
static void
|
|
|
|
meta_kms_impl_device_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (object);
|
2020-07-16 15:55:39 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2019-01-29 17:33:00 +00:00
|
|
|
|
2020-07-16 21:29:31 +00:00
|
|
|
meta_kms_impl_remove_impl_device (priv->impl, impl_device);
|
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
g_list_free_full (priv->planes, g_object_unref);
|
|
|
|
g_list_free_full (priv->crtcs, g_object_unref);
|
|
|
|
g_list_free_full (priv->connectors, g_object_unref);
|
|
|
|
g_list_free_full (priv->fallback_modes,
|
2020-07-02 09:54:56 +00:00
|
|
|
(GDestroyNotify) meta_kms_mode_free);
|
2021-03-31 16:34:45 +00:00
|
|
|
|
2021-04-12 14:25:53 +00:00
|
|
|
clear_latched_fd_hold (impl_device);
|
|
|
|
g_warn_if_fail (!priv->device_file);
|
2021-03-31 16:34:45 +00:00
|
|
|
|
2020-07-16 15:55:39 +00:00
|
|
|
g_free (priv->driver_name);
|
|
|
|
g_free (priv->driver_description);
|
2020-09-29 14:43:04 +00:00
|
|
|
g_free (priv->path);
|
2019-01-29 17:33:00 +00:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_kms_impl_device_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2021-01-18 17:27:07 +00:00
|
|
|
gboolean
|
|
|
|
meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device,
|
|
|
|
GError **error)
|
2020-07-16 20:17:04 +00:00
|
|
|
{
|
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2021-03-31 16:34:45 +00:00
|
|
|
int fd;
|
2020-07-16 20:17:04 +00:00
|
|
|
drmModeRes *drm_resources;
|
|
|
|
|
2021-03-31 16:34:45 +00:00
|
|
|
fd = meta_device_file_get_fd (priv->device_file);
|
|
|
|
|
|
|
|
drm_resources = drmModeGetResources (fd);
|
2020-07-16 20:17:04 +00:00
|
|
|
if (!drm_resources)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to activate universal planes: %s",
|
|
|
|
g_strerror (errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
init_caps (impl_device);
|
|
|
|
|
|
|
|
init_crtcs (impl_device, drm_resources);
|
|
|
|
init_planes (impl_device);
|
|
|
|
|
|
|
|
init_fallback_modes (impl_device);
|
|
|
|
|
|
|
|
update_connectors (impl_device, drm_resources);
|
|
|
|
|
|
|
|
drmModeFreeResources (drm_resources);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2021-04-13 16:18:46 +00:00
|
|
|
void
|
|
|
|
meta_kms_impl_device_prepare_shutdown (MetaKmsImplDevice *impl_device)
|
|
|
|
{
|
|
|
|
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
|
|
|
|
|
|
|
|
if (klass->prepare_shutdown)
|
|
|
|
klass->prepare_shutdown (impl_device);
|
2021-06-11 17:42:41 +00:00
|
|
|
|
|
|
|
clear_fd_source (impl_device);
|
2021-04-13 16:18:46 +00:00
|
|
|
}
|
|
|
|
|
2021-04-06 10:14:24 +00:00
|
|
|
static gboolean
|
|
|
|
get_driver_info (int fd,
|
|
|
|
char **name,
|
|
|
|
char **description)
|
2021-03-31 16:34:45 +00:00
|
|
|
{
|
2021-04-06 10:14:24 +00:00
|
|
|
drmVersion *drm_version;
|
|
|
|
|
|
|
|
drm_version = drmGetVersion (fd);
|
|
|
|
if (!drm_version)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
*name = g_strndup (drm_version->name,
|
|
|
|
drm_version->name_len);
|
|
|
|
*description = g_strndup (drm_version->desc,
|
|
|
|
drm_version->desc_len);
|
|
|
|
drmFreeVersion (drm_version);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_kms_impl_device_initable_init (GInitable *initable,
|
|
|
|
GCancellable *cancellable,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable);
|
2021-03-31 16:34:45 +00:00
|
|
|
MetaKmsImplDevicePrivate *priv =
|
|
|
|
meta_kms_impl_device_get_instance_private (impl_device);
|
2021-04-06 10:14:24 +00:00
|
|
|
int fd;
|
|
|
|
|
2021-04-12 14:25:53 +00:00
|
|
|
if (!ensure_device_file (impl_device, error))
|
2021-04-06 10:14:24 +00:00
|
|
|
return FALSE;
|
2021-03-31 16:34:45 +00:00
|
|
|
|
2021-04-12 14:25:53 +00:00
|
|
|
ensure_latched_fd_hold (impl_device);
|
|
|
|
|
2021-04-06 10:14:24 +00:00
|
|
|
g_clear_pointer (&priv->path, g_free);
|
2021-03-31 16:34:45 +00:00
|
|
|
priv->path = g_strdup (meta_device_file_get_path (priv->device_file));
|
|
|
|
|
2021-04-06 10:14:24 +00:00
|
|
|
fd = meta_device_file_get_fd (priv->device_file);
|
|
|
|
if (!get_driver_info (fd, &priv->driver_name, &priv->driver_description))
|
|
|
|
{
|
|
|
|
priv->driver_name = g_strdup ("unknown");
|
|
|
|
priv->driver_description = g_strdup ("Unknown");
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
2021-03-31 16:34:45 +00:00
|
|
|
}
|
|
|
|
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
static void
|
2021-04-01 09:56:22 +00:00
|
|
|
meta_kms_impl_device_init (MetaKmsImplDevice *impl_device)
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-04-06 10:14:24 +00:00
|
|
|
static void
|
|
|
|
initable_iface_init (GInitableIface *iface)
|
|
|
|
{
|
|
|
|
iface->init = meta_kms_impl_device_initable_init;
|
|
|
|
}
|
|
|
|
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
static void
|
|
|
|
meta_kms_impl_device_class_init (MetaKmsImplDeviceClass *klass)
|
|
|
|
{
|
2019-01-29 17:33:00 +00:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
2020-07-16 20:17:04 +00:00
|
|
|
object_class->get_property = meta_kms_impl_device_get_property;
|
|
|
|
object_class->set_property = meta_kms_impl_device_set_property;
|
2019-01-29 17:33:00 +00:00
|
|
|
object_class->finalize = meta_kms_impl_device_finalize;
|
backends/native: Add basic KMS abstraction building blocks
The intention with 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-01-29 09:24:44 +00:00
|
|
|
|
2020-07-16 20:17:04 +00:00
|
|
|
obj_props[PROP_DEVICE] =
|
|
|
|
g_param_spec_object ("device",
|
|
|
|
"device",
|
|
|
|
"MetaKmsDevice",
|
|
|
|
META_TYPE_KMS_DEVICE,
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_props[PROP_IMPL] =
|
|
|
|
g_param_spec_object ("impl",
|
|
|
|
"impl",
|
|
|
|
"MetaKmsImpl",
|
|
|
|
META_TYPE_KMS_IMPL,
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
2021-04-06 10:14:24 +00:00
|
|
|
obj_props[PROP_PATH] =
|
|
|
|
g_param_spec_string ("path",
|
|
|
|
"path",
|
|
|
|
"Device path",
|
|
|
|
NULL,
|
|
|
|
G_PARAM_WRITABLE |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
kms: Add way to run without mode setting
Currently our only entry point for DRM devices is MetaKms*, but in order
to run without being DRM master, we cannot use /dev/dri/card*, nor can
we be either of the existing MetaKmsImplDevice implementation (legacy
KMS, and atomic KMS), as they both depend on being DRM master.
Thus to handle running without being DRM master (i.e. headless), add a
"dummy" MetaKmsImplDevice implementation, that doesn't do any mode
setting at all, and that switches to operate on the render node, instead
of the card node itself.
This means we still use the same GBM code paths as the regular native
backend paths, except we never make use of any CRTC backed onscreen
framebuffers.
Eventually, this "dummy" MetaKmsImplDevice will be replaced separating
"KMS" device objects from "render" device objects, but that will require
more significant changes. It will, however, be necessary for e.g. going
from being headless, only having access to a render node, to turning
into a real session, with a seat, being DRM master, and having access to
a card node.
This is currently not hooked up, but will be in a later commit.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-19 13:54:45 +00:00
|
|
|
obj_props[PROP_FLAGS] =
|
|
|
|
g_param_spec_flags ("flags",
|
|
|
|
"flags",
|
|
|
|
"KMS impl device flags",
|
|
|
|
META_TYPE_KMS_DEVICE_FLAG,
|
|
|
|
META_KMS_DEVICE_FLAG_NONE,
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
2020-07-16 20:17:04 +00:00
|
|
|
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
|
|
|
}
|