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
This commit is contained in:
Jonas Ådahl 2019-04-04 22:36:41 +02:00 committed by Georges Basile Stavracas Neto
parent bea7600471
commit 75dff3e7c9
31 changed files with 2364 additions and 1084 deletions

View File

@ -25,9 +25,12 @@
#include "backends/native/meta-crtc-kms.h" #include "backends/native/meta-crtc-kms.h"
#include "backends/meta-backend-private.h" #include "backends/meta-backend-private.h"
#include "backends/meta-logical-monitor.h"
#include "backends/native/meta-gpu-kms.h" #include "backends/native/meta-gpu-kms.h"
#include "backends/native/meta-output-kms.h"
#include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms-device.h"
#include "backends/native/meta-kms-plane.h" #include "backends/native/meta-kms-plane.h"
#include "backends/native/meta-kms-update.h"
#define ALL_TRANSFORMS_MASK ((1 << META_MONITOR_N_TRANSFORMS) - 1) #define ALL_TRANSFORMS_MASK ((1 << META_MONITOR_N_TRANSFORMS) - 1)
@ -35,12 +38,11 @@ typedef struct _MetaCrtcKms
{ {
MetaKmsCrtc *kms_crtc; MetaKmsCrtc *kms_crtc;
uint32_t rotation_prop_id;
uint32_t rotation_map[META_MONITOR_N_TRANSFORMS];
MetaKmsPlane *primary_plane; MetaKmsPlane *primary_plane;
} MetaCrtcKms; } MetaCrtcKms;
static GQuark kms_crtc_crtc_kms_quark;
gboolean gboolean
meta_crtc_kms_is_transform_handled (MetaCrtc *crtc, meta_crtc_kms_is_transform_handled (MetaCrtc *crtc,
MetaMonitorTransform transform) MetaMonitorTransform transform)
@ -55,60 +57,123 @@ meta_crtc_kms_is_transform_handled (MetaCrtc *crtc,
} }
void void
meta_crtc_kms_apply_transform (MetaCrtc *crtc) meta_crtc_kms_apply_transform (MetaCrtc *crtc,
MetaKmsPlaneAssignment *kms_plane_assignment)
{ {
MetaCrtcKms *crtc_kms = crtc->driver_private; MetaCrtcKms *crtc_kms = crtc->driver_private;
MetaGpu *gpu = meta_crtc_get_gpu (crtc);
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
int kms_fd;
MetaMonitorTransform hw_transform; MetaMonitorTransform hw_transform;
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
hw_transform = crtc->transform; hw_transform = crtc->transform;
if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform)) if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform))
hw_transform = META_MONITOR_TRANSFORM_NORMAL; hw_transform = META_MONITOR_TRANSFORM_NORMAL;
if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform)) if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform))
return; return;
if (drmModeObjectSetProperty (kms_fd, meta_kms_plane_update_set_rotation (crtc_kms->primary_plane,
meta_kms_plane_get_id (crtc_kms->primary_plane), kms_plane_assignment,
DRM_MODE_OBJECT_PLANE, hw_transform);
crtc_kms->rotation_prop_id,
crtc_kms->rotation_map[hw_transform]) != 0)
g_warning ("Failed to apply DRM plane transform %d: %m", hw_transform);
} }
static int void
find_property_index (MetaGpu *gpu, meta_crtc_kms_assign_primary_plane (MetaCrtc *crtc,
drmModeObjectPropertiesPtr props, uint32_t fb_id,
const char *prop_name, MetaKmsUpdate *kms_update)
drmModePropertyPtr *out_prop)
{ {
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); MetaRectangle logical_monitor_rect;
int kms_fd; int x, y;
unsigned int i; MetaFixed16Rectangle src_rect;
MetaFixed16Rectangle dst_rect;
MetaKmsCrtc *kms_crtc;
MetaKmsDevice *kms_device;
MetaKmsPlane *primary_kms_plane;
MetaKmsPlaneAssignment *plane_assignment;
kms_fd = meta_gpu_kms_get_fd (gpu_kms); logical_monitor_rect =
meta_logical_monitor_get_layout (crtc->logical_monitor);
x = crtc->rect.x - logical_monitor_rect.x;
y = crtc->rect.y - logical_monitor_rect.y;
src_rect = (MetaFixed16Rectangle) {
.x = meta_fixed_16_from_int (x),
.y = meta_fixed_16_from_int (y),
.width = meta_fixed_16_from_int (crtc->rect.width),
.height = meta_fixed_16_from_int (crtc->rect.height),
};
dst_rect = (MetaFixed16Rectangle) {
.x = meta_fixed_16_from_int (0),
.y = meta_fixed_16_from_int (0),
.width = meta_fixed_16_from_int (crtc->rect.width),
.height = meta_fixed_16_from_int (crtc->rect.height),
};
for (i = 0; i < props->count_props; i++) kms_crtc = meta_crtc_kms_get_kms_crtc (crtc);
kms_device = meta_kms_crtc_get_device (kms_crtc);
primary_kms_plane = meta_kms_device_get_primary_plane_for (kms_device,
kms_crtc);
plane_assignment = meta_kms_update_assign_plane (kms_update,
kms_crtc,
primary_kms_plane,
fb_id,
src_rect,
dst_rect);
meta_crtc_kms_apply_transform (crtc, plane_assignment);
}
static GList *
generate_crtc_connector_list (MetaGpu *gpu,
MetaCrtc *crtc)
{
GList *connectors = NULL;
GList *l;
for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
{ {
drmModePropertyPtr prop; MetaOutput *output = l->data;
MetaCrtc *assigned_crtc;
prop = drmModeGetProperty (kms_fd, props->props[i]); assigned_crtc = meta_output_get_assigned_crtc (output);
if (!prop) if (assigned_crtc == crtc)
continue;
if (strcmp (prop->name, prop_name) == 0)
{ {
*out_prop = prop; MetaKmsConnector *kms_connector =
return i; meta_output_kms_get_kms_connector (output);
}
drmModeFreeProperty (prop); connectors = g_list_prepend (connectors, kms_connector);
}
} }
return -1; return connectors;
}
void
meta_crtc_kms_set_mode (MetaCrtc *crtc,
MetaKmsUpdate *kms_update)
{
MetaGpu *gpu = meta_crtc_get_gpu (crtc);
GList *connectors;
drmModeModeInfo *mode;
connectors = generate_crtc_connector_list (gpu, crtc);
if (connectors)
mode = crtc->current_mode->driver_private;
else
mode = NULL;
meta_kms_update_mode_set (kms_update,
meta_crtc_kms_get_kms_crtc (crtc),
g_steal_pointer (&connectors),
mode);
}
void
meta_crtc_kms_page_flip (MetaCrtc *crtc,
const MetaKmsPageFlipFeedback *page_flip_feedback,
gpointer user_data,
MetaKmsUpdate *kms_update)
{
meta_kms_update_page_flip (kms_update,
meta_crtc_kms_get_kms_crtc (crtc),
page_flip_feedback,
user_data);
} }
MetaKmsCrtc * MetaKmsCrtc *
@ -176,62 +241,10 @@ meta_crtc_kms_supports_format (MetaCrtc *crtc,
drm_format); drm_format);
} }
static void MetaCrtc *
parse_transforms (MetaCrtc *crtc, meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc)
drmModePropertyPtr prop)
{ {
MetaCrtcKms *crtc_kms = crtc->driver_private; return g_object_get_qdata (G_OBJECT (kms_crtc), kms_crtc_crtc_kms_quark);
int i;
for (i = 0; i < prop->count_enums; i++)
{
int transform = -1;
if (strcmp (prop->enums[i].name, "rotate-0") == 0)
transform = META_MONITOR_TRANSFORM_NORMAL;
else if (strcmp (prop->enums[i].name, "rotate-90") == 0)
transform = META_MONITOR_TRANSFORM_90;
else if (strcmp (prop->enums[i].name, "rotate-180") == 0)
transform = META_MONITOR_TRANSFORM_180;
else if (strcmp (prop->enums[i].name, "rotate-270") == 0)
transform = META_MONITOR_TRANSFORM_270;
if (transform != -1)
crtc_kms->rotation_map[transform] = 1 << prop->enums[i].value;
}
}
static void
init_crtc_rotations (MetaCrtc *crtc,
MetaGpu *gpu)
{
MetaCrtcKms *crtc_kms = crtc->driver_private;
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
int kms_fd;
uint32_t primary_plane_id;
drmModePlane *drm_plane;
drmModeObjectPropertiesPtr props;
drmModePropertyPtr prop;
int rotation_idx;
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
primary_plane_id = meta_kms_plane_get_id (crtc_kms->primary_plane);
drm_plane = drmModeGetPlane (kms_fd, primary_plane_id);
props = drmModeObjectGetProperties (kms_fd,
primary_plane_id,
DRM_MODE_OBJECT_PLANE);
rotation_idx = find_property_index (gpu, props,
"rotation", &prop);
if (rotation_idx >= 0)
{
crtc_kms->rotation_prop_id = props->props[rotation_idx];
parse_transforms (crtc, prop);
drmModeFreeProperty (prop);
}
drmModeFreeObjectProperties (props);
drmModeFreePlane (drm_plane);
} }
static void static void
@ -287,7 +300,13 @@ meta_create_kms_crtc (MetaGpuKms *gpu_kms,
crtc->driver_private = crtc_kms; crtc->driver_private = crtc_kms;
crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify; crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
init_crtc_rotations (crtc, gpu); if (!kms_crtc_crtc_kms_quark)
{
kms_crtc_crtc_kms_quark =
g_quark_from_static_string ("meta-kms-crtc-crtc-kms-quark");
}
g_object_set_qdata (G_OBJECT (kms_crtc), kms_crtc_crtc_kms_quark, crtc);
return crtc; return crtc;
} }

View File

@ -34,7 +34,23 @@
gboolean meta_crtc_kms_is_transform_handled (MetaCrtc *crtc, gboolean meta_crtc_kms_is_transform_handled (MetaCrtc *crtc,
MetaMonitorTransform transform); MetaMonitorTransform transform);
void meta_crtc_kms_apply_transform (MetaCrtc *crtc); void meta_crtc_kms_apply_transform (MetaCrtc *crtc,
MetaKmsPlaneAssignment *kms_plane_assignment);
void meta_crtc_kms_assign_primary_plane (MetaCrtc *crtc,
uint32_t fb_id,
MetaKmsUpdate *kms_update);
void meta_crtc_kms_set_mode (MetaCrtc *crtc,
MetaKmsUpdate *kms_update);
void meta_crtc_kms_page_flip (MetaCrtc *crtc,
const MetaKmsPageFlipFeedback *page_flip_feedback,
gpointer user_data,
MetaKmsUpdate *kms_update);
void meta_crtc_kms_set_is_underscanning (MetaCrtc *crtc,
gboolean is_underscanning);
MetaKmsCrtc * meta_crtc_kms_get_kms_crtc (MetaCrtc *crtc); MetaKmsCrtc * meta_crtc_kms_get_kms_crtc (MetaCrtc *crtc);
@ -48,6 +64,8 @@ gboolean
meta_crtc_kms_supports_format (MetaCrtc *crtc, meta_crtc_kms_supports_format (MetaCrtc *crtc,
uint32_t drm_format); uint32_t drm_format);
MetaCrtc * meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc);
MetaCrtc * meta_create_kms_crtc (MetaGpuKms *gpu_kms, MetaCrtc * meta_create_kms_crtc (MetaGpuKms *gpu_kms,
MetaKmsCrtc *kms_crtc); MetaKmsCrtc *kms_crtc);

View File

@ -39,6 +39,7 @@
#include "backends/native/meta-crtc-kms.h" #include "backends/native/meta-crtc-kms.h"
#include "backends/native/meta-kms-connector.h" #include "backends/native/meta-kms-connector.h"
#include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms-device.h"
#include "backends/native/meta-kms-update.h"
#include "backends/native/meta-kms-utils.h" #include "backends/native/meta-kms-utils.h"
#include "backends/native/meta-kms.h" #include "backends/native/meta-kms.h"
#include "backends/native/meta-launcher.h" #include "backends/native/meta-launcher.h"
@ -46,21 +47,6 @@
#include "meta-default-modes.h" #include "meta-default-modes.h"
typedef struct _MetaKmsSource
{
GSource source;
gpointer fd_tag;
MetaGpuKms *gpu_kms;
} MetaKmsSource;
typedef struct _MetaGpuKmsFlipClosureContainer
{
GClosure *flip_closure;
MetaGpuKms *gpu_kms;
MetaCrtc *crtc;
} MetaGpuKmsFlipClosureContainer;
struct _MetaGpuKms struct _MetaGpuKms
{ {
MetaGpu parent; MetaGpu parent;
@ -69,7 +55,6 @@ struct _MetaGpuKms
uint32_t id; uint32_t id;
int fd; int fd;
GSource *source;
clockid_t clock_id; clockid_t clock_id;
@ -78,124 +63,6 @@ struct _MetaGpuKms
G_DEFINE_TYPE (MetaGpuKms, meta_gpu_kms, META_TYPE_GPU) G_DEFINE_TYPE (MetaGpuKms, meta_gpu_kms, META_TYPE_GPU)
static gboolean
kms_event_check (GSource *source)
{
MetaKmsSource *kms_source = (MetaKmsSource *) source;
return g_source_query_unix_fd (source, kms_source->fd_tag) & G_IO_IN;
}
static gboolean
kms_event_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
MetaKmsSource *kms_source = (MetaKmsSource *) source;
meta_gpu_kms_wait_for_flip (kms_source->gpu_kms, NULL);
return G_SOURCE_CONTINUE;
}
static GSourceFuncs kms_event_funcs = {
NULL,
kms_event_check,
kms_event_dispatch
};
static void
get_crtc_drm_connectors (MetaGpu *gpu,
MetaCrtc *crtc,
uint32_t **connectors,
unsigned int *n_connectors)
{
GArray *connectors_array = g_array_new (FALSE, FALSE, sizeof (uint32_t));
GList *l;
for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
{
MetaOutput *output = l->data;
MetaCrtc *assigned_crtc;
assigned_crtc = meta_output_get_assigned_crtc (output);
if (assigned_crtc == crtc)
{
uint32_t connector_id;
connector_id = meta_output_kms_get_connector_id (output);
g_array_append_val (connectors_array, connector_id);
}
}
*n_connectors = connectors_array->len;
*connectors = (uint32_t *) g_array_free (connectors_array, FALSE);
}
gboolean
meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
int x,
int y,
uint32_t fb_id)
{
MetaGpu *gpu = meta_crtc_get_gpu (crtc);
int kms_fd = meta_gpu_kms_get_fd (gpu_kms);
uint32_t *connectors;
unsigned int n_connectors;
drmModeModeInfo *mode;
get_crtc_drm_connectors (gpu, crtc, &connectors, &n_connectors);
if (connectors)
mode = crtc->current_mode->driver_private;
else
mode = NULL;
if (drmModeSetCrtc (kms_fd,
crtc->crtc_id,
fb_id,
x, y,
connectors, n_connectors,
mode) != 0)
{
if (mode)
g_warning ("Failed to set CRTC mode %s: %m", crtc->current_mode->name);
else
g_warning ("Failed to disable CRTC");
g_free (connectors);
return FALSE;
}
g_free (connectors);
return TRUE;
}
static void
invoke_flip_closure (GClosure *flip_closure,
MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
int64_t page_flip_time_ns)
{
GValue params[] = {
G_VALUE_INIT,
G_VALUE_INIT,
G_VALUE_INIT,
G_VALUE_INIT,
};
g_value_init (&params[0], G_TYPE_POINTER);
g_value_set_pointer (&params[0], flip_closure);
g_value_init (&params[1], G_TYPE_OBJECT);
g_value_set_object (&params[1], gpu_kms);
g_value_init (&params[2], G_TYPE_OBJECT);
g_value_set_object (&params[2], crtc);
g_value_init (&params[3], G_TYPE_INT64);
g_value_set_int64 (&params[3], page_flip_time_ns);
g_closure_invoke (flip_closure, NULL, 4, params, NULL);
}
gboolean gboolean
meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms, meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
MetaCrtc *crtc) MetaCrtc *crtc)
@ -232,79 +99,6 @@ meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
return TRUE; return TRUE;
} }
MetaGpuKmsFlipClosureContainer *
meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
GClosure *flip_closure)
{
MetaGpuKmsFlipClosureContainer *closure_container;
closure_container = g_new0 (MetaGpuKmsFlipClosureContainer, 1);
*closure_container = (MetaGpuKmsFlipClosureContainer) {
.flip_closure = g_closure_ref (flip_closure),
.gpu_kms = gpu_kms,
.crtc = crtc
};
return closure_container;
}
void
meta_gpu_kms_flip_closure_container_free (MetaGpuKmsFlipClosureContainer *closure_container)
{
g_closure_unref (closure_container->flip_closure);
g_free (closure_container);
}
gboolean
meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
uint32_t fb_id,
GClosure *flip_closure,
GError **error)
{
MetaGpu *gpu = META_GPU (gpu_kms);
MetaBackend *backend = meta_gpu_get_backend (gpu);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaGpuKmsFlipClosureContainer *closure_container;
int kms_fd = meta_gpu_kms_get_fd (gpu_kms);
uint32_t *connectors;
unsigned int n_connectors;
int ret = -1;
g_assert (meta_crtc_get_gpu (crtc) == gpu);
g_assert (monitor_manager);
g_assert (meta_monitor_manager_get_power_save_mode (monitor_manager) ==
META_POWER_SAVE_ON);
get_crtc_drm_connectors (gpu, crtc, &connectors, &n_connectors);
g_assert (n_connectors > 0);
g_free (connectors);
g_assert (fb_id != 0);
closure_container = meta_gpu_kms_wrap_flip_closure (gpu_kms,
crtc,
flip_closure);
ret = drmModePageFlip (kms_fd,
crtc->crtc_id,
fb_id,
DRM_MODE_PAGE_FLIP_EVENT,
closure_container);
if (ret != 0)
{
meta_gpu_kms_flip_closure_container_free (closure_container);
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (-ret),
"drmModePageFlip failed: %s", g_strerror (-ret));
return FALSE;
}
return TRUE;
}
static int64_t static int64_t
timespec_to_nanoseconds (const struct timespec *ts) timespec_to_nanoseconds (const struct timespec *ts)
{ {
@ -313,71 +107,12 @@ timespec_to_nanoseconds (const struct timespec *ts)
return ((int64_t) ts->tv_sec) * one_billion + ts->tv_nsec; return ((int64_t) ts->tv_sec) * one_billion + ts->tv_nsec;
} }
static int64_t
timeval_to_nanoseconds (const struct timeval *tv)
{
int64_t usec = ((int64_t) tv->tv_sec) * G_USEC_PER_SEC + tv->tv_usec;
int64_t nsec = usec * 1000;
return nsec;
}
static void
page_flip_handler (int fd,
unsigned int frame,
unsigned int sec,
unsigned int usec,
void *user_data)
{
MetaGpuKmsFlipClosureContainer *closure_container = user_data;
GClosure *flip_closure = closure_container->flip_closure;
MetaGpuKms *gpu_kms = closure_container->gpu_kms;
struct timeval page_flip_time = {sec, usec};
invoke_flip_closure (flip_closure,
gpu_kms,
closure_container->crtc,
timeval_to_nanoseconds (&page_flip_time));
meta_gpu_kms_flip_closure_container_free (closure_container);
}
gboolean gboolean
meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms, meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms,
GError **error) GError **error)
{ {
drmEventContext evctx; if (meta_kms_device_dispatch_sync (gpu_kms->kms_device, error) < 0)
return FALSE;
memset (&evctx, 0, sizeof evctx);
evctx.version = 2;
evctx.page_flip_handler = page_flip_handler;
while (TRUE)
{
if (drmHandleEvent (gpu_kms->fd, &evctx) != 0)
{
struct pollfd pfd;
int ret;
if (errno != EAGAIN)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
strerror (errno));
return FALSE;
}
pfd.fd = gpu_kms->fd;
pfd.events = POLL_IN | POLL_ERR;
do
{
ret = poll (&pfd, 1, -1);
}
while (ret == -1 && errno == EINTR);
}
else
{
break;
}
}
return TRUE; return TRUE;
} }
@ -418,8 +153,9 @@ meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms)
} }
void void
meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms, meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
uint64_t state) uint64_t state,
MetaKmsUpdate *kms_update)
{ {
GList *l; GList *l;
@ -427,7 +163,7 @@ meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
{ {
MetaOutput *output = l->data; MetaOutput *output = l->data;
meta_output_kms_set_power_save_mode (output, state); meta_output_kms_set_power_save_mode (output, state, kms_update);
} }
} }
@ -707,16 +443,13 @@ init_outputs (MetaGpuKms *gpu_kms)
for (l = meta_kms_device_get_connectors (gpu_kms->kms_device); l; l = l->next) for (l = meta_kms_device_get_connectors (gpu_kms->kms_device); l; l = l->next)
{ {
MetaKmsConnector *kms_connector = l->data; MetaKmsConnector *kms_connector = l->data;
const MetaKmsConnectorState *connector_state;
MetaOutput *output; MetaOutput *output;
MetaOutput *old_output; MetaOutput *old_output;
GError *error = NULL; GError *error = NULL;
uint32_t connector_id;
drmModeConnector *connector;
connector_id = meta_kms_connector_get_id (kms_connector); connector_state = meta_kms_connector_get_current_state (kms_connector);
connector = drmModeGetConnector (gpu_kms->fd, connector_id); if (!connector_state)
if (!connector || connector->connection != DRM_MODE_CONNECTED)
continue; continue;
old_output = old_output =
@ -724,7 +457,6 @@ init_outputs (MetaGpuKms *gpu_kms)
meta_kms_connector_get_id (kms_connector)); meta_kms_connector_get_id (kms_connector));
output = meta_create_kms_output (gpu_kms, output = meta_create_kms_output (gpu_kms,
kms_connector, kms_connector,
connector,
old_output, old_output,
&error); &error);
if (!output) if (!output)
@ -787,8 +519,6 @@ meta_gpu_kms_new (MetaBackendNative *backend_native,
MetaKmsDevice *kms_device, MetaKmsDevice *kms_device,
GError **error) GError **error)
{ {
GSource *source;
MetaKmsSource *kms_source;
MetaGpuKms *gpu_kms; MetaGpuKms *gpu_kms;
int kms_fd; int kms_fd;
@ -803,29 +533,9 @@ meta_gpu_kms_new (MetaBackendNative *backend_native,
meta_gpu_kms_read_current (META_GPU (gpu_kms), NULL); meta_gpu_kms_read_current (META_GPU (gpu_kms), NULL);
source = g_source_new (&kms_event_funcs, sizeof (MetaKmsSource));
kms_source = (MetaKmsSource *) source;
kms_source->fd_tag = g_source_add_unix_fd (source,
gpu_kms->fd,
G_IO_IN | G_IO_ERR);
kms_source->gpu_kms = gpu_kms;
gpu_kms->source = source;
g_source_attach (gpu_kms->source, NULL);
return gpu_kms; return gpu_kms;
} }
static void
meta_gpu_kms_finalize (GObject *object)
{
MetaGpuKms *gpu_kms = META_GPU_KMS (object);
g_source_destroy (gpu_kms->source);
G_OBJECT_CLASS (meta_gpu_kms_parent_class)->finalize (object);
}
static void static void
meta_gpu_kms_init (MetaGpuKms *gpu_kms) meta_gpu_kms_init (MetaGpuKms *gpu_kms)
{ {
@ -838,10 +548,7 @@ meta_gpu_kms_init (MetaGpuKms *gpu_kms)
static void static void
meta_gpu_kms_class_init (MetaGpuKmsClass *klass) meta_gpu_kms_class_init (MetaGpuKmsClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaGpuClass *gpu_class = META_GPU_CLASS (klass); MetaGpuClass *gpu_class = META_GPU_CLASS (klass);
object_class->finalize = meta_gpu_kms_finalize;
gpu_class->read_current = meta_gpu_kms_read_current; gpu_class->read_current = meta_gpu_kms_read_current;
} }

View File

@ -29,6 +29,7 @@
#include "backends/meta-gpu.h" #include "backends/meta-gpu.h"
#include "backends/native/meta-backend-native.h" #include "backends/native/meta-backend-native.h"
#include "backends/native/meta-kms-types.h"
#define META_TYPE_GPU_KMS (meta_gpu_kms_get_type ()) #define META_TYPE_GPU_KMS (meta_gpu_kms_get_type ())
G_DECLARE_FINAL_TYPE (MetaGpuKms, meta_gpu_kms, META, GPU_KMS, MetaGpu) G_DECLARE_FINAL_TYPE (MetaGpuKms, meta_gpu_kms, META, GPU_KMS, MetaGpu)
@ -39,12 +40,6 @@ MetaGpuKms * meta_gpu_kms_new (MetaBackendNative *backend_native,
MetaKmsDevice *kms_device, MetaKmsDevice *kms_device,
GError **error); GError **error);
gboolean meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
int x,
int y,
uint32_t fb_id);
gboolean meta_gpu_kms_can_have_outputs (MetaGpuKms *gpu_kms); gboolean meta_gpu_kms_can_have_outputs (MetaGpuKms *gpu_kms);
gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms, gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
@ -53,12 +48,6 @@ gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
gboolean meta_gpu_kms_is_boot_vga (MetaGpuKms *gpu_kms); gboolean meta_gpu_kms_is_boot_vga (MetaGpuKms *gpu_kms);
gboolean meta_gpu_kms_is_platform_device (MetaGpuKms *gpu_kms); gboolean meta_gpu_kms_is_platform_device (MetaGpuKms *gpu_kms);
gboolean meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
uint32_t fb_id,
GClosure *flip_closure,
GError **error);
gboolean meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms, gboolean meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms,
GError **error); GError **error);
@ -72,8 +61,9 @@ const char * meta_gpu_kms_get_file_path (MetaGpuKms *gpu_kms);
int64_t meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms); int64_t meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms);
void meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms, void meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
uint64_t state); uint64_t state,
MetaKmsUpdate *kms_update);
MetaCrtcMode * meta_gpu_kms_get_mode_from_drm_mode (MetaGpuKms *gpu_kms, MetaCrtcMode * meta_gpu_kms_get_mode_from_drm_mode (MetaGpuKms *gpu_kms,
const drmModeModeInfo *drm_mode); const drmModeModeInfo *drm_mode);

View File

@ -26,6 +26,7 @@
#include "backends/native/meta-kms-device-private.h" #include "backends/native/meta-kms-device-private.h"
#include "backends/native/meta-kms-impl-device.h" #include "backends/native/meta-kms-impl-device.h"
#include "backends/native/meta-kms-update-private.h"
struct _MetaKmsConnector struct _MetaKmsConnector
{ {
@ -38,6 +39,13 @@ struct _MetaKmsConnector
char *name; char *name;
MetaKmsConnectorState *current_state; MetaKmsConnectorState *current_state;
uint32_t dpms_prop_id;
uint32_t underscan_prop_id;
uint32_t underscan_hborder_prop_id;
uint32_t underscan_vborder_prop_id;
uint32_t edid_blob_id;
uint32_t tile_blob_id;
}; };
G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT) G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT)
@ -48,6 +56,47 @@ meta_kms_connector_get_device (MetaKmsConnector *connector)
return connector->device; return connector->device;
} }
void
meta_kms_connector_update_set_dpms_state (MetaKmsConnector *connector,
MetaKmsUpdate *update,
uint64_t state)
{
meta_kms_update_set_connector_property (update,
connector,
connector->dpms_prop_id,
state);
}
void
meta_kms_connector_set_underscanning (MetaKmsConnector *connector,
MetaKmsUpdate *update,
uint64_t hborder,
uint64_t vborder)
{
meta_kms_update_set_connector_property (update,
connector,
connector->underscan_prop_id,
1);
meta_kms_update_set_connector_property (update,
connector,
connector->underscan_hborder_prop_id,
hborder);
meta_kms_update_set_connector_property (update,
connector,
connector->underscan_vborder_prop_id,
vborder);
}
void
meta_kms_connector_unset_underscanning (MetaKmsConnector *connector,
MetaKmsUpdate *update)
{
meta_kms_update_set_connector_property (update,
connector,
connector->underscan_prop_id,
0);
}
MetaConnectorType MetaConnectorType
meta_kms_connector_get_connector_type (MetaKmsConnector *connector) meta_kms_connector_get_connector_type (MetaKmsConnector *connector)
{ {
@ -89,6 +138,12 @@ meta_kms_connector_get_current_state (MetaKmsConnector *connector)
return connector->current_state; return connector->current_state;
} }
gboolean
meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector)
{
return connector->underscan_prop_id != 0;
}
static void static void
set_panel_orientation (MetaKmsConnectorState *state, set_panel_orientation (MetaKmsConnectorState *state,
drmModePropertyPtr prop, drmModePropertyPtr prop,
@ -437,6 +492,41 @@ meta_kms_connector_update_state (MetaKmsConnector *connector,
drm_resources); drm_resources);
} }
static void
find_property_ids (MetaKmsConnector *connector,
MetaKmsImplDevice *impl_device,
drmModeConnector *drm_connector)
{
int fd;
int i;
fd = meta_kms_impl_device_get_fd (impl_device);
for (i = 0; i < drm_connector->count_props; i++)
{
drmModePropertyPtr prop;
prop = drmModeGetProperty (fd, drm_connector->props[i]);
if (!prop)
continue;
if ((prop->flags & DRM_MODE_PROP_ENUM) &&
strcmp (prop->name, "DPMS") == 0)
connector->dpms_prop_id = prop->prop_id;
else if ((prop->flags & DRM_MODE_PROP_ENUM) &&
strcmp (prop->name, "underscan") == 0)
connector->underscan_prop_id = prop->prop_id;
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
strcmp (prop->name, "underscan hborder") == 0)
connector->underscan_hborder_prop_id = prop->prop_id;
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
strcmp (prop->name, "underscan vborder") == 0)
connector->underscan_vborder_prop_id = prop->prop_id;
drmModeFreeProperty (prop);
}
}
static char * static char *
make_connector_name (drmModeConnector *drm_connector) make_connector_name (drmModeConnector *drm_connector)
{ {
@ -483,6 +573,8 @@ meta_kms_connector_new (MetaKmsImplDevice *impl_device,
connector->type = (MetaConnectorType) drm_connector->connector_type; connector->type = (MetaConnectorType) drm_connector->connector_type;
connector->name = make_connector_name (drm_connector); connector->name = make_connector_name (drm_connector);
find_property_ids (connector, impl_device, drm_connector);
meta_kms_connector_read_state (connector, impl_device, meta_kms_connector_read_state (connector, impl_device,
drm_connector, drm_connector,
drm_resources); drm_resources);

View File

@ -61,6 +61,18 @@ typedef struct _MetaKmsConnectorState
MetaKmsDevice * meta_kms_connector_get_device (MetaKmsConnector *connector); MetaKmsDevice * meta_kms_connector_get_device (MetaKmsConnector *connector);
void meta_kms_connector_update_set_dpms_state (MetaKmsConnector *connector,
MetaKmsUpdate *update,
uint64_t state);
void meta_kms_connector_set_underscanning (MetaKmsConnector *connector,
MetaKmsUpdate *update,
uint64_t hborder,
uint64_t vborder);
void meta_kms_connector_unset_underscanning (MetaKmsConnector *connector,
MetaKmsUpdate *update);
MetaConnectorType meta_kms_connector_get_connector_type (MetaKmsConnector *connector); MetaConnectorType meta_kms_connector_get_connector_type (MetaKmsConnector *connector);
uint32_t meta_kms_connector_get_id (MetaKmsConnector *connector); uint32_t meta_kms_connector_get_id (MetaKmsConnector *connector);
@ -72,4 +84,6 @@ gboolean meta_kms_connector_can_clone (MetaKmsConnector *connector,
const MetaKmsConnectorState * meta_kms_connector_get_current_state (MetaKmsConnector *connector); const MetaKmsConnectorState * meta_kms_connector_get_current_state (MetaKmsConnector *connector);
gboolean meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector);
#endif /* META_KMS_CONNECTOR_H */ #endif /* META_KMS_CONNECTOR_H */

View File

@ -24,6 +24,7 @@
#include "backends/native/meta-kms-device-private.h" #include "backends/native/meta-kms-device-private.h"
#include "backends/native/meta-kms-impl-device.h" #include "backends/native/meta-kms-impl-device.h"
#include "backends/native/meta-kms-update-private.h"
struct _MetaKmsCrtc struct _MetaKmsCrtc
{ {

View File

@ -108,6 +108,35 @@ meta_kms_device_get_primary_plane_for (MetaKmsDevice *device,
return NULL; return NULL;
} }
static gboolean
dispatch_in_impl (MetaKmsImpl *impl,
gpointer user_data,
GError **error)
{
MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (user_data);
return meta_kms_impl_device_dispatch (impl_device, error);
}
int
meta_kms_device_dispatch_sync (MetaKmsDevice *device,
GError **error)
{
int callback_count;
callback_count = meta_kms_flush_callbacks (device->kms);
if (callback_count > 0)
return TRUE;
if (!meta_kms_run_impl_task_sync (device->kms,
dispatch_in_impl,
device->impl_device,
error))
return -1;
return meta_kms_flush_callbacks (device->kms);
}
typedef struct _CreateImplDeviceData typedef struct _CreateImplDeviceData
{ {
MetaKmsDevice *device; MetaKmsDevice *device;

View File

@ -42,6 +42,9 @@ GList * meta_kms_device_get_crtcs (MetaKmsDevice *device);
MetaKmsPlane * meta_kms_device_get_primary_plane_for (MetaKmsDevice *device, MetaKmsPlane * meta_kms_device_get_primary_plane_for (MetaKmsDevice *device,
MetaKmsCrtc *crtc); MetaKmsCrtc *crtc);
int meta_kms_device_dispatch_sync (MetaKmsDevice *device,
GError **error);
MetaKmsDevice * meta_kms_device_new (MetaKms *kms, MetaKmsDevice * meta_kms_device_new (MetaKms *kms,
const char *path, const char *path,
MetaKmsDeviceFlag flags, MetaKmsDeviceFlag flags,

View File

@ -21,6 +21,7 @@
#include "backends/native/meta-kms-impl-device.h" #include "backends/native/meta-kms-impl-device.h"
#include <errno.h>
#include <xf86drm.h> #include <xf86drm.h>
#include "backends/native/meta-kms-connector-private.h" #include "backends/native/meta-kms-connector-private.h"
@ -28,8 +29,10 @@
#include "backends/native/meta-kms-crtc-private.h" #include "backends/native/meta-kms-crtc-private.h"
#include "backends/native/meta-kms-crtc.h" #include "backends/native/meta-kms-crtc.h"
#include "backends/native/meta-kms-impl.h" #include "backends/native/meta-kms-impl.h"
#include "backends/native/meta-kms-page-flip-private.h"
#include "backends/native/meta-kms-plane.h" #include "backends/native/meta-kms-plane.h"
#include "backends/native/meta-kms-private.h" #include "backends/native/meta-kms-private.h"
#include "backends/native/meta-kms-update.h"
struct _MetaKmsImplDevice struct _MetaKmsImplDevice
{ {
@ -39,6 +42,7 @@ struct _MetaKmsImplDevice
MetaKmsImpl *impl; MetaKmsImpl *impl;
int fd; int fd;
GSource *fd_source;
GList *crtcs; GList *crtcs;
GList *connectors; GList *connectors;
@ -71,6 +75,77 @@ meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device)
return g_list_copy (impl_device->planes); return g_list_copy (impl_device->planes);
} }
static void
page_flip_handler (int fd,
unsigned int sequence,
unsigned int sec,
unsigned int usec,
void *user_data)
{
MetaKmsPageFlipData *page_flip_data = user_data;
MetaKmsImpl *impl;
meta_kms_page_flip_data_set_timings_in_impl (page_flip_data,
sequence, sec, usec);
impl = meta_kms_page_flip_data_get_kms_impl (page_flip_data);
meta_kms_impl_handle_page_flip_callback (impl, page_flip_data);
}
gboolean
meta_kms_impl_device_dispatch (MetaKmsImplDevice *impl_device,
GError **error)
{
drmEventContext drm_event_context;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
drm_event_context = (drmEventContext) { 0 };
drm_event_context.version = 2;
drm_event_context.page_flip_handler = page_flip_handler;
while (TRUE)
{
if (drmHandleEvent (impl_device->fd, &drm_event_context) != 0)
{
struct pollfd pfd;
int ret;
if (errno != EAGAIN)
{
g_set_error_literal (error, G_IO_ERROR,
g_io_error_from_errno (errno),
strerror (errno));
return FALSE;
}
pfd.fd = impl_device->fd;
pfd.events = POLL_IN | POLL_ERR;
do
{
ret = poll (&pfd, 1, -1);
}
while (ret == -1 && errno == EINTR);
}
else
{
break;
}
}
return TRUE;
}
static gboolean
kms_event_dispatch_in_impl (MetaKmsImpl *impl,
gpointer user_data,
GError **error)
{
MetaKmsImplDevice *impl_device = user_data;
return meta_kms_impl_device_dispatch (impl_device, error);
}
drmModePropertyPtr drmModePropertyPtr
meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device, meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device,
drmModeObjectProperties *props, drmModeObjectProperties *props,
@ -236,10 +311,11 @@ meta_kms_impl_device_new (MetaKmsDevice *device,
MetaKmsImpl *impl, MetaKmsImpl *impl,
int fd) int fd)
{ {
MetaKms *kms = meta_kms_impl_get_kms (impl);
MetaKmsImplDevice *impl_device; MetaKmsImplDevice *impl_device;
drmModeRes *drm_resources; drmModeRes *drm_resources;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl)); meta_assert_in_kms_impl (kms);
impl_device = g_object_new (META_TYPE_KMS_IMPL_DEVICE, NULL); impl_device = g_object_new (META_TYPE_KMS_IMPL_DEVICE, NULL);
impl_device->device = device; impl_device->device = device;
@ -256,6 +332,11 @@ meta_kms_impl_device_new (MetaKmsDevice *device,
drmModeFreeResources (drm_resources); drmModeFreeResources (drm_resources);
impl_device->fd_source =
meta_kms_register_fd_in_impl (kms, fd,
kms_event_dispatch_in_impl,
impl_device);
return impl_device; return impl_device;
} }
@ -280,6 +361,7 @@ meta_kms_impl_device_close (MetaKmsImplDevice *impl_device)
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl)); meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
g_clear_pointer (&impl_device->fd_source, g_source_destroy);
fd = impl_device->fd; fd = impl_device->fd;
impl_device->fd = -1; impl_device->fd = -1;

View File

@ -26,6 +26,7 @@
#include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms-device.h"
#include "backends/native/meta-kms-types.h" #include "backends/native/meta-kms-types.h"
#include "backends/native/meta-kms-update.h"
#define META_TYPE_KMS_IMPL_DEVICE (meta_kms_impl_device_get_type ()) #define META_TYPE_KMS_IMPL_DEVICE (meta_kms_impl_device_get_type ())
G_DECLARE_FINAL_TYPE (MetaKmsImplDevice, meta_kms_impl_device, G_DECLARE_FINAL_TYPE (MetaKmsImplDevice, meta_kms_impl_device,
@ -40,6 +41,9 @@ GList * meta_kms_impl_device_copy_crtcs (MetaKmsImplDevice *impl_device);
GList * meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device); GList * meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device);
gboolean meta_kms_impl_device_dispatch (MetaKmsImplDevice *impl_device,
GError **error);
drmModePropertyPtr meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device, drmModePropertyPtr meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device,
drmModeObjectProperties *props, drmModeObjectProperties *props,
const char *prop_name, const char *prop_name,

View File

@ -21,16 +21,47 @@
#include "backends/native/meta-kms-impl-simple.h" #include "backends/native/meta-kms-impl-simple.h"
#include <errno.h>
#include <gbm.h> #include <gbm.h>
#include <xf86drmMode.h>
#include "backends/native/meta-kms-connector.h"
#include "backends/native/meta-kms-crtc.h"
#include "backends/native/meta-kms-device-private.h"
#include "backends/native/meta-kms-page-flip-private.h"
#include "backends/native/meta-kms-plane.h"
#include "backends/native/meta-kms-private.h"
#include "backends/native/meta-kms-update-private.h"
#include "backends/native/meta-kms-utils.h"
typedef struct _CachedModeSet
{
GList *connectors;
drmModeModeInfo *drm_mode;
} CachedModeSet;
struct _MetaKmsImplSimple struct _MetaKmsImplSimple
{ {
MetaKmsImpl parent; MetaKmsImpl parent;
GSource *mode_set_fallback_feedback_source;
GList *mode_set_fallback_page_flip_datas;
GList *pending_page_flip_retries;
GSource *retry_page_flips_source;
GList *postponed_page_flip_datas;
GList *postponed_mode_set_fallback_datas;
GHashTable *cached_mode_sets;
}; };
G_DEFINE_TYPE (MetaKmsImplSimple, meta_kms_impl_simple, G_DEFINE_TYPE (MetaKmsImplSimple, meta_kms_impl_simple,
META_TYPE_KMS_IMPL) META_TYPE_KMS_IMPL)
static void
flush_postponed_page_flip_datas (MetaKmsImplSimple *impl_simple);
MetaKmsImplSimple * MetaKmsImplSimple *
meta_kms_impl_simple_new (MetaKms *kms, meta_kms_impl_simple_new (MetaKms *kms,
GError **error) GError **error)
@ -40,12 +71,755 @@ meta_kms_impl_simple_new (MetaKms *kms,
NULL); NULL);
} }
static gboolean
process_connector_property (MetaKmsImpl *impl,
MetaKmsUpdate *update,
MetaKmsConnectorProperty *connector_property,
GError **error)
{
MetaKmsConnector *connector = connector_property->connector;
MetaKmsDevice *device = meta_kms_connector_get_device (connector);
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
int fd;
int ret;
fd = meta_kms_impl_device_get_fd (impl_device);
ret = drmModeObjectSetProperty (fd,
meta_kms_connector_get_id (connector),
DRM_MODE_OBJECT_CONNECTOR,
connector_property->prop_id,
connector_property->value);
if (ret != 0)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
"Failed to set connector %u property %u: %s",
meta_kms_connector_get_id (connector),
connector_property->prop_id,
g_strerror (-ret));
return FALSE;
}
return TRUE;
}
static gboolean
process_plane_property (MetaKmsImpl *impl,
MetaKmsPlane *plane,
MetaKmsProperty *prop,
GError **error)
{
MetaKmsDevice *device = meta_kms_plane_get_device (plane);
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
int fd;
int ret;
fd = meta_kms_impl_device_get_fd (impl_device);
ret = drmModeObjectSetProperty (fd,
meta_kms_plane_get_id (plane),
DRM_MODE_OBJECT_PLANE,
prop->prop_id,
prop->value);
if (ret != 0)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
"Failed to set plane %u property %u: %s",
meta_kms_plane_get_id (plane),
prop->prop_id,
g_strerror (-ret));
return FALSE;
}
return TRUE;
}
static MetaKmsPlaneAssignment *
get_primary_plane_assignment (MetaKmsImpl *impl,
MetaKmsUpdate *update,
MetaKmsCrtc *crtc)
{
GList *l;
for (l = meta_kms_update_get_plane_assignments (update); l; l = l->next)
{
MetaKmsPlaneAssignment *plane_assignment = l->data;
if (plane_assignment->crtc == crtc)
return plane_assignment;
}
return NULL;
}
static CachedModeSet *
cached_mode_set_new (GList *connectors,
const drmModeModeInfo *drm_mode)
{
CachedModeSet *cached_mode_set;
cached_mode_set = g_new0 (CachedModeSet, 1);
*cached_mode_set = (CachedModeSet) {
.connectors = g_list_copy (connectors),
.drm_mode = g_memdup (drm_mode, sizeof *drm_mode),
};
return cached_mode_set;
}
static void
cached_mode_set_free (CachedModeSet *cached_mode_set)
{
g_list_free (cached_mode_set->connectors);
g_free (cached_mode_set->drm_mode);
g_free (cached_mode_set);
}
static void
fill_connector_ids_array (GList *connectors,
uint32_t **out_connectors,
int *out_n_connectors)
{
GList *l;
int i;
*out_n_connectors = g_list_length (connectors);
*out_connectors = g_new0 (uint32_t, *out_n_connectors);
i = 0;
for (l = connectors; l; l = l->next)
{
MetaKmsConnector *connector = l->data;
(*out_connectors)[i++] = meta_kms_connector_get_id (connector);
}
}
static gboolean
process_mode_set (MetaKmsImpl *impl,
MetaKmsUpdate *update,
MetaKmsModeSet *mode_set,
GError **error)
{
MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl);
MetaKmsCrtc *crtc = mode_set->crtc;;
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
g_autofree uint32_t *connectors = NULL;
int n_connectors;
MetaKmsPlaneAssignment *plane_assignment;
uint32_t x, y;
uint32_t fb_id;
int fd;
int ret;
crtc = mode_set->crtc;
if (mode_set->drm_mode)
{
GList *l;
fill_connector_ids_array (mode_set->connectors,
&connectors,
&n_connectors);
plane_assignment = get_primary_plane_assignment (impl, update, crtc);
if (!plane_assignment)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Missing primary plane assignment for legacy mode set on CRTC %u",
meta_kms_crtc_get_id (crtc));
return FALSE;
}
x = meta_fixed_16_to_int (plane_assignment->src_rect.x);
y = meta_fixed_16_to_int (plane_assignment->src_rect.y);
for (l = plane_assignment->plane_properties; l; l = l->next)
{
MetaKmsProperty *prop = l->data;
if (!process_plane_property (impl, plane_assignment->plane,
prop, error))
return FALSE;
}
fb_id = plane_assignment->fb_id;
}
else
{
x = y = 0;
n_connectors = 0;
connectors = NULL;
fb_id = 0;
}
fd = meta_kms_impl_device_get_fd (impl_device);
ret = drmModeSetCrtc (fd,
meta_kms_crtc_get_id (crtc),
fb_id,
x, y,
connectors, n_connectors,
mode_set->drm_mode);
if (ret != 0)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
"Failed to set mode on CRTC %u: %s",
meta_kms_crtc_get_id (crtc),
g_strerror (-ret));
return FALSE;
}
if (mode_set->drm_mode)
{
g_hash_table_replace (impl_simple->cached_mode_sets,
crtc,
cached_mode_set_new (mode_set->connectors,
mode_set->drm_mode));
}
else
{
g_hash_table_remove (impl_simple->cached_mode_sets, crtc);
}
return TRUE;
}
static gboolean
is_timestamp_earlier_than (uint64_t ts1,
uint64_t ts2)
{
if (ts1 == ts2)
return FALSE;
else
return ts2 - ts1 < UINT64_MAX / 2;
}
typedef struct _RetryPageFlipData
{
MetaKmsCrtc *crtc;
uint32_t fb_id;
MetaKmsPageFlipData *page_flip_data;
float refresh_rate;
uint64_t retry_time_us;
} RetryPageFlipData;
static void
retry_page_flip_data_free (RetryPageFlipData *retry_page_flip_data)
{
g_assert (!retry_page_flip_data->page_flip_data);
g_free (retry_page_flip_data);
}
static float
get_cached_crtc_refresh_rate (MetaKmsImplSimple *impl_simple,
MetaKmsCrtc *crtc)
{
CachedModeSet *cached_mode_set;
cached_mode_set = g_hash_table_lookup (impl_simple->cached_mode_sets,
crtc);
g_assert (cached_mode_set);
return meta_calculate_drm_mode_refresh_rate (cached_mode_set->drm_mode);
}
static gboolean
retry_page_flips (gpointer user_data)
{
MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (user_data);
uint64_t now_us;
GList *l;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (META_KMS_IMPL (impl_simple)));
now_us = g_source_get_time (impl_simple->retry_page_flips_source);
l = impl_simple->pending_page_flip_retries;
while (l)
{
RetryPageFlipData *retry_page_flip_data = l->data;
MetaKmsCrtc *crtc = retry_page_flip_data->crtc;
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
GList *l_next = l->next;
int fd;
int ret;
MetaKmsPageFlipData *page_flip_data;
if (is_timestamp_earlier_than (now_us,
retry_page_flip_data->retry_time_us))
{
l = l_next;
continue;
}
fd = meta_kms_impl_device_get_fd (impl_device);
ret = drmModePageFlip (fd,
meta_kms_crtc_get_id (crtc),
retry_page_flip_data->fb_id,
DRM_MODE_PAGE_FLIP_EVENT,
retry_page_flip_data->page_flip_data);
if (ret == -EBUSY)
{
float refresh_rate;
refresh_rate = get_cached_crtc_refresh_rate (impl_simple, crtc);
retry_page_flip_data->retry_time_us +=
(uint64_t) (G_USEC_PER_SEC / refresh_rate);
l = l_next;
continue;
}
impl_simple->pending_page_flip_retries =
g_list_remove_link (impl_simple->pending_page_flip_retries, l);
page_flip_data = g_steal_pointer (&retry_page_flip_data->page_flip_data);
if (ret != 0)
{
g_autoptr (GError) error = NULL;
g_set_error (&error, G_IO_ERROR, g_io_error_from_errno (-ret),
"drmModePageFlip on CRTC %u failed: %s",
meta_kms_crtc_get_id (crtc),
g_strerror (-ret));
if (!g_error_matches (error,
G_IO_ERROR,
G_IO_ERROR_PERMISSION_DENIED))
g_critical ("Failed to page flip: %s", error->message);
meta_kms_page_flip_data_discard_in_impl (page_flip_data, error);
}
retry_page_flip_data_free (retry_page_flip_data);
l = l_next;
}
if (impl_simple->pending_page_flip_retries)
{
GList *l;
uint64_t earliest_retry_time_us = 0;
for (l = impl_simple->pending_page_flip_retries; l; l = l->next)
{
RetryPageFlipData *retry_page_flip_data = l->data;
if (l == impl_simple->pending_page_flip_retries ||
is_timestamp_earlier_than (retry_page_flip_data->retry_time_us,
earliest_retry_time_us))
earliest_retry_time_us = retry_page_flip_data->retry_time_us;
}
g_source_set_ready_time (impl_simple->retry_page_flips_source,
earliest_retry_time_us);
return G_SOURCE_CONTINUE;
}
else
{
g_clear_pointer (&impl_simple->retry_page_flips_source,
g_source_unref);
flush_postponed_page_flip_datas (impl_simple);
return G_SOURCE_REMOVE;
}
}
static void
schedule_retry_page_flip (MetaKmsImplSimple *impl_simple,
MetaKmsCrtc *crtc,
uint32_t fb_id,
float refresh_rate,
MetaKmsPageFlipData *page_flip_data)
{
RetryPageFlipData *retry_page_flip_data;
uint64_t now_us;
uint64_t retry_time_us;
now_us = g_get_monotonic_time ();
retry_time_us = now_us + (uint64_t) (G_USEC_PER_SEC / refresh_rate);
retry_page_flip_data = g_new0 (RetryPageFlipData, 1);
*retry_page_flip_data = (RetryPageFlipData) {
.crtc = crtc,
.fb_id = fb_id,
.page_flip_data = meta_kms_page_flip_data_ref (page_flip_data),
.refresh_rate = refresh_rate,
.retry_time_us = retry_time_us,
};
if (!impl_simple->retry_page_flips_source)
{
MetaKms *kms = meta_kms_impl_get_kms (META_KMS_IMPL (impl_simple));
GSource *source;
source = meta_kms_add_source_in_impl (kms, retry_page_flips,
impl_simple, NULL);
g_source_set_ready_time (source, retry_time_us);
impl_simple->retry_page_flips_source = source;
}
else
{
GList *l;
for (l = impl_simple->pending_page_flip_retries; l; l = l->next)
{
RetryPageFlipData *pending_retry_page_flip_data = l->data;
uint64_t pending_retry_time_us =
pending_retry_page_flip_data->retry_time_us;
if (is_timestamp_earlier_than (retry_time_us, pending_retry_time_us))
{
g_source_set_ready_time (impl_simple->retry_page_flips_source,
retry_time_us);
break;
}
}
}
impl_simple->pending_page_flip_retries =
g_list_append (impl_simple->pending_page_flip_retries,
retry_page_flip_data);
}
static void
invoke_page_flip_datas (GList *page_flip_datas,
MetaPageFlipDataFeedbackFunc func)
{
g_list_foreach (page_flip_datas, (GFunc) func, NULL);
}
static void
clear_page_flip_datas (GList **page_flip_datas)
{
g_list_free_full (*page_flip_datas,
(GDestroyNotify) meta_kms_page_flip_data_unref);
*page_flip_datas = NULL;
}
static gboolean
mode_set_fallback_feedback_idle (gpointer user_data)
{
MetaKmsImplSimple *impl_simple = user_data;
g_clear_pointer (&impl_simple->mode_set_fallback_feedback_source,
g_source_unref);
if (!impl_simple->pending_page_flip_retries)
{
impl_simple->postponed_mode_set_fallback_datas =
g_steal_pointer (&impl_simple->mode_set_fallback_page_flip_datas);
}
else
{
invoke_page_flip_datas (impl_simple->mode_set_fallback_page_flip_datas,
meta_kms_page_flip_data_mode_set_fallback_in_impl);
clear_page_flip_datas (&impl_simple->mode_set_fallback_page_flip_datas);
}
return G_SOURCE_REMOVE;
}
static gboolean
mode_set_fallback (MetaKmsImplSimple *impl_simple,
MetaKmsUpdate *update,
MetaKmsPageFlip *page_flip,
MetaKmsPlaneAssignment *plane_assignment,
MetaKmsPageFlipData *page_flip_data,
GError **error)
{
MetaKms *kms = meta_kms_impl_get_kms (META_KMS_IMPL (impl_simple));
MetaKmsCrtc *crtc = page_flip->crtc;
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
CachedModeSet *cached_mode_set;
g_autofree uint32_t *connectors = NULL;
int n_connectors;
uint32_t x, y;
int fd;
int ret;
cached_mode_set = g_hash_table_lookup (impl_simple->cached_mode_sets,
crtc);
g_assert (cached_mode_set);
fill_connector_ids_array (cached_mode_set->connectors,
&connectors,
&n_connectors);
x = meta_fixed_16_to_int (plane_assignment->src_rect.x);
y = meta_fixed_16_to_int (plane_assignment->src_rect.y);
fd = meta_kms_impl_device_get_fd (impl_device);
ret = drmModeSetCrtc (fd,
meta_kms_crtc_get_id (crtc),
plane_assignment->fb_id,
x, y,
connectors, n_connectors,
cached_mode_set->drm_mode);
if (ret != 0)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
"drmModeSetCrtc mode '%s' on CRTC %u failed: %s",
cached_mode_set->drm_mode->name,
meta_kms_crtc_get_id (crtc),
g_strerror (-ret));
return FALSE;
}
if (!impl_simple->mode_set_fallback_feedback_source)
{
GSource *source;
source = meta_kms_add_source_in_impl (kms,
mode_set_fallback_feedback_idle,
impl_simple,
NULL);
impl_simple->mode_set_fallback_feedback_source = source;
}
impl_simple->mode_set_fallback_page_flip_datas =
g_list_prepend (impl_simple->mode_set_fallback_page_flip_datas,
meta_kms_page_flip_data_ref (page_flip_data));
return TRUE;
}
static gboolean
process_page_flip (MetaKmsImpl *impl,
MetaKmsUpdate *update,
MetaKmsPageFlip *page_flip,
GError **error)
{
MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl);
MetaKmsCrtc *crtc;
MetaKmsDevice *device;
MetaKmsImplDevice *impl_device;
MetaKmsPlaneAssignment *plane_assignment;
MetaKmsPageFlipData *page_flip_data;
MetaKmsCustomPageFlipFunc custom_page_flip_func;
int fd;
int ret;
crtc = page_flip->crtc;
plane_assignment = get_primary_plane_assignment (impl, update, crtc);
page_flip_data = meta_kms_page_flip_data_new (impl,
crtc,
page_flip->feedback,
page_flip->user_data);
device = meta_kms_crtc_get_device (crtc);
impl_device = meta_kms_device_get_impl_device (device);
fd = meta_kms_impl_device_get_fd (impl_device);
custom_page_flip_func = page_flip->custom_page_flip_func;
if (custom_page_flip_func)
{
ret = custom_page_flip_func (page_flip->custom_page_flip_user_data,
meta_kms_page_flip_data_ref (page_flip_data));
}
else
{
ret = drmModePageFlip (fd,
meta_kms_crtc_get_id (crtc),
plane_assignment->fb_id,
DRM_MODE_PAGE_FLIP_EVENT,
meta_kms_page_flip_data_ref (page_flip_data));
}
if (ret == -EBUSY)
{
float refresh_rate;
refresh_rate = get_cached_crtc_refresh_rate (impl_simple, crtc);
schedule_retry_page_flip (impl_simple,
crtc,
plane_assignment->fb_id,
refresh_rate,
page_flip_data);
}
else if (ret == -EINVAL)
{
if (!mode_set_fallback (impl_simple,
update,
page_flip,
plane_assignment,
page_flip_data,
error))
{
meta_kms_page_flip_data_unref (page_flip_data);
return FALSE;
}
}
else if (ret != 0)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
"drmModePageFlip on CRTC %u failed: %s",
meta_kms_crtc_get_id (crtc),
g_strerror (-ret));
meta_kms_page_flip_data_unref (page_flip_data);
return FALSE;
}
meta_kms_page_flip_data_unref (page_flip_data);
return TRUE;
}
static void
discard_page_flip (MetaKmsImpl *impl,
MetaKmsUpdate *update,
MetaKmsPageFlip *page_flip)
{
MetaKmsCrtc *crtc;
MetaKmsPageFlipData *page_flip_data;
crtc = page_flip->crtc;
page_flip_data = meta_kms_page_flip_data_new (impl,
crtc,
page_flip->feedback,
page_flip->user_data);
meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL);
meta_kms_page_flip_data_unref (page_flip_data);
}
static gboolean
meta_kms_impl_simple_process_update (MetaKmsImpl *impl,
MetaKmsUpdate *update,
GError **error)
{
GList *l;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl));
for (l = meta_kms_update_get_connector_properties (update); l; l = l->next)
{
MetaKmsConnectorProperty *connector_property = l->data;
if (!process_connector_property (impl, update, connector_property, error))
goto discard_page_flips;
}
for (l = meta_kms_update_get_mode_sets (update); l; l = l->next)
{
MetaKmsModeSet *mode_set = l->data;
if (!process_mode_set (impl, update, mode_set, error))
goto discard_page_flips;
}
for (l = meta_kms_update_get_page_flips (update); l; l = l->next)
{
MetaKmsPageFlip *page_flip = l->data;
if (!process_page_flip (impl, update, page_flip, error))
goto discard_page_flips;
}
return TRUE;
discard_page_flips:
for (l = meta_kms_update_get_page_flips (update); l; l = l->next)
{
MetaKmsPageFlip *page_flip = l->data;
discard_page_flip (impl, update, page_flip);
}
return FALSE;
}
static void
flush_postponed_page_flip_datas (MetaKmsImplSimple *impl_simple)
{
invoke_page_flip_datas (impl_simple->postponed_page_flip_datas,
meta_kms_page_flip_data_flipped_in_impl);
clear_page_flip_datas (&impl_simple->postponed_page_flip_datas);
invoke_page_flip_datas (impl_simple->postponed_mode_set_fallback_datas,
meta_kms_page_flip_data_mode_set_fallback_in_impl);
clear_page_flip_datas (&impl_simple->postponed_mode_set_fallback_datas);
}
static void
meta_kms_impl_simple_handle_page_flip_callback (MetaKmsImpl *impl,
MetaKmsPageFlipData *page_flip_data)
{
MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl);
if (impl_simple->pending_page_flip_retries)
{
impl_simple->postponed_page_flip_datas =
g_list_append (impl_simple->postponed_page_flip_datas,
page_flip_data);
}
else
{
meta_kms_page_flip_data_flipped_in_impl (page_flip_data);
}
}
static void
meta_kms_impl_simple_discard_pending_page_flips (MetaKmsImpl *impl)
{
MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl);
GList *l;
if (!impl_simple->pending_page_flip_retries)
return;
for (l = impl_simple->pending_page_flip_retries; l; l = l->next)
{
RetryPageFlipData *retry_page_flip_data = l->data;
MetaKmsPageFlipData *page_flip_data;
page_flip_data = g_steal_pointer (&retry_page_flip_data->page_flip_data);
meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL);
retry_page_flip_data_free (retry_page_flip_data);
}
g_clear_pointer (&impl_simple->pending_page_flip_retries, g_list_free);
g_clear_pointer (&impl_simple->retry_page_flips_source,
g_source_destroy);
}
static void
meta_kms_impl_simple_finalize (GObject *object)
{
MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (object);
g_list_free_full (impl_simple->pending_page_flip_retries,
(GDestroyNotify) retry_page_flip_data_free);
g_list_free_full (impl_simple->postponed_page_flip_datas,
(GDestroyNotify) meta_kms_page_flip_data_unref);
g_list_free_full (impl_simple->postponed_mode_set_fallback_datas,
(GDestroyNotify) meta_kms_page_flip_data_unref);
g_clear_pointer (&impl_simple->mode_set_fallback_feedback_source,
g_source_destroy);
g_hash_table_destroy (impl_simple->cached_mode_sets);
G_OBJECT_CLASS (meta_kms_impl_simple_parent_class)->finalize (object);
}
static void static void
meta_kms_impl_simple_init (MetaKmsImplSimple *impl_simple) meta_kms_impl_simple_init (MetaKmsImplSimple *impl_simple)
{ {
impl_simple->cached_mode_sets =
g_hash_table_new_full (NULL,
NULL,
NULL,
(GDestroyNotify) cached_mode_set_free);
} }
static void static void
meta_kms_impl_simple_class_init (MetaKmsImplSimpleClass *klass) meta_kms_impl_simple_class_init (MetaKmsImplSimpleClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaKmsImplClass *impl_class = META_KMS_IMPL_CLASS (klass);
object_class->finalize = meta_kms_impl_simple_finalize;
impl_class->process_update = meta_kms_impl_simple_process_update;
impl_class->handle_page_flip_callback = meta_kms_impl_simple_handle_page_flip_callback;
impl_class->discard_pending_page_flips = meta_kms_impl_simple_discard_pending_page_flips;
} }

View File

@ -43,6 +43,28 @@ meta_kms_impl_get_kms (MetaKmsImpl *impl)
return priv->kms; return priv->kms;
} }
gboolean
meta_kms_impl_process_update (MetaKmsImpl *impl,
MetaKmsUpdate *update,
GError **error)
{
return META_KMS_IMPL_GET_CLASS (impl)->process_update (impl, update, error);
}
void
meta_kms_impl_handle_page_flip_callback (MetaKmsImpl *impl,
MetaKmsPageFlipData *page_flip_data)
{
META_KMS_IMPL_GET_CLASS (impl)->handle_page_flip_callback (impl,
page_flip_data);
}
void
meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl)
{
META_KMS_IMPL_GET_CLASS (impl)->discard_pending_page_flips (impl);
}
static void static void
meta_kms_impl_set_property (GObject *object, meta_kms_impl_set_property (GObject *object,
guint prop_id, guint prop_id,

View File

@ -21,6 +21,7 @@
#define META_KMS_IMPL_H #define META_KMS_IMPL_H
#include "backends/native/meta-kms-impl-device.h" #include "backends/native/meta-kms-impl-device.h"
#include "backends/native/meta-kms-page-flip-private.h"
#include "backends/native/meta-kms.h" #include "backends/native/meta-kms.h"
#define META_TYPE_KMS_IMPL (meta_kms_impl_get_type ()) #define META_TYPE_KMS_IMPL (meta_kms_impl_get_type ())
@ -30,8 +31,24 @@ G_DECLARE_DERIVABLE_TYPE (MetaKmsImpl, meta_kms_impl,
struct _MetaKmsImplClass struct _MetaKmsImplClass
{ {
GObjectClass parent_class; GObjectClass parent_class;
gboolean (* process_update) (MetaKmsImpl *impl,
MetaKmsUpdate *update,
GError **error);
void (* handle_page_flip_callback) (MetaKmsImpl *impl,
MetaKmsPageFlipData *page_flip_data);
void (* discard_pending_page_flips) (MetaKmsImpl *impl);
}; };
MetaKms * meta_kms_impl_get_kms (MetaKmsImpl *impl); MetaKms * meta_kms_impl_get_kms (MetaKmsImpl *impl);
gboolean meta_kms_impl_process_update (MetaKmsImpl *impl,
MetaKmsUpdate *update,
GError **error);
void meta_kms_impl_handle_page_flip_callback (MetaKmsImpl *impl,
MetaKmsPageFlipData *page_flip_data);
void meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl);
#endif /* META_KMS_IMPL_H */ #endif /* META_KMS_IMPL_H */

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2019 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_KMS_PAGE_FLIP_H
#define META_KMS_PAGE_FLIP_H
#include <glib.h>
#include "backends/native/meta-kms-types.h"
typedef struct _MetaKmsPageFlipData MetaKmsPageFlipData;
typedef void (* MetaPageFlipDataFeedbackFunc) (MetaKmsPageFlipData *page_flip_data);
MetaKmsPageFlipData * meta_kms_page_flip_data_new (MetaKmsImpl *impl,
MetaKmsCrtc *crtc,
const MetaKmsPageFlipFeedback *feedback,
gpointer user_data);
MetaKmsPageFlipData * meta_kms_page_flip_data_ref (MetaKmsPageFlipData *page_flip_data);
void meta_kms_page_flip_data_unref (MetaKmsPageFlipData *page_flip_data);
MetaKmsImpl * meta_kms_page_flip_data_get_kms_impl (MetaKmsPageFlipData *page_flip_data);
void meta_kms_page_flip_data_set_timings_in_impl (MetaKmsPageFlipData *page_flip_data,
unsigned int sequence,
unsigned int sec,
unsigned int usec);
void meta_kms_page_flip_data_flipped_in_impl (MetaKmsPageFlipData *page_flip_data);
void meta_kms_page_flip_data_mode_set_fallback_in_impl (MetaKmsPageFlipData *page_flip_data);
void meta_kms_page_flip_data_discard_in_impl (MetaKmsPageFlipData *page_flip_data,
const GError *error);
void meta_kms_page_flip_data_take_error (MetaKmsPageFlipData *page_flip_data,
GError *error);
#endif /* META_KMS_PAGE_FLIP_H */

View File

@ -0,0 +1,196 @@
/*
* Copyright (C) 2019 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "config.h"
#include "backends/native/meta-kms-page-flip-private.h"
#include "backends/native/meta-kms-impl.h"
#include "backends/native/meta-kms-private.h"
#include "backends/native/meta-kms-update.h"
struct _MetaKmsPageFlipData
{
int ref_count;
MetaKmsImpl *impl;
MetaKmsCrtc *crtc;
const MetaKmsPageFlipFeedback *feedback;
gpointer user_data;
unsigned int sequence;
unsigned int sec;
unsigned int usec;
GError *error;
};
MetaKmsPageFlipData *
meta_kms_page_flip_data_new (MetaKmsImpl *impl,
MetaKmsCrtc *crtc,
const MetaKmsPageFlipFeedback *feedback,
gpointer user_data)
{
MetaKmsPageFlipData *page_flip_data;
page_flip_data = g_new0 (MetaKmsPageFlipData , 1);
*page_flip_data = (MetaKmsPageFlipData) {
.ref_count = 1,
.impl = impl,
.crtc = crtc,
.feedback = feedback,
.user_data = user_data,
};
return page_flip_data;
}
MetaKmsPageFlipData *
meta_kms_page_flip_data_ref (MetaKmsPageFlipData *page_flip_data)
{
page_flip_data->ref_count++;
return page_flip_data;
}
void
meta_kms_page_flip_data_unref (MetaKmsPageFlipData *page_flip_data)
{
page_flip_data->ref_count--;
if (page_flip_data->ref_count == 0)
{
g_clear_error (&page_flip_data->error);
g_free (page_flip_data);
}
}
MetaKmsImpl *
meta_kms_page_flip_data_get_kms_impl (MetaKmsPageFlipData *page_flip_data)
{
return page_flip_data->impl;
}
static void
meta_kms_page_flip_data_flipped (MetaKms *kms,
gpointer user_data)
{
MetaKmsPageFlipData *page_flip_data = user_data;
meta_assert_not_in_kms_impl (kms);
page_flip_data->feedback->flipped (page_flip_data->crtc,
page_flip_data->sequence,
page_flip_data->sec,
page_flip_data->usec,
page_flip_data->user_data);
}
void
meta_kms_page_flip_data_set_timings_in_impl (MetaKmsPageFlipData *page_flip_data,
unsigned int sequence,
unsigned int sec,
unsigned int usec)
{
MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
meta_assert_in_kms_impl (kms);
page_flip_data->sequence = sequence;
page_flip_data->sec = sec;
page_flip_data->usec = usec;
}
void
meta_kms_page_flip_data_flipped_in_impl (MetaKmsPageFlipData *page_flip_data)
{
MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
meta_assert_in_kms_impl (kms);
meta_kms_queue_callback (kms,
meta_kms_page_flip_data_flipped,
meta_kms_page_flip_data_ref (page_flip_data),
(GDestroyNotify) meta_kms_page_flip_data_unref);
}
static void
meta_kms_page_flip_data_mode_set_fallback (MetaKms *kms,
gpointer user_data)
{
MetaKmsPageFlipData *page_flip_data = user_data;
meta_assert_not_in_kms_impl (kms);
page_flip_data->feedback->mode_set_fallback (page_flip_data->crtc,
page_flip_data->user_data);
}
void
meta_kms_page_flip_data_mode_set_fallback_in_impl (MetaKmsPageFlipData *page_flip_data)
{
MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
meta_assert_in_kms_impl (kms);
meta_kms_queue_callback (kms,
meta_kms_page_flip_data_mode_set_fallback,
meta_kms_page_flip_data_ref (page_flip_data),
(GDestroyNotify) meta_kms_page_flip_data_unref);
}
static void
meta_kms_page_flip_data_discard (MetaKms *kms,
gpointer user_data)
{
MetaKmsPageFlipData *page_flip_data = user_data;
meta_assert_not_in_kms_impl (kms);
page_flip_data->feedback->discarded (page_flip_data->crtc,
page_flip_data->user_data,
page_flip_data->error);
}
void
meta_kms_page_flip_data_take_error (MetaKmsPageFlipData *page_flip_data,
GError *error)
{
g_assert (!page_flip_data->error);
page_flip_data->error = error;
}
void
meta_kms_page_flip_data_discard_in_impl (MetaKmsPageFlipData *page_flip_data,
const GError *error)
{
MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
meta_assert_in_kms_impl (kms);
if (error)
meta_kms_page_flip_data_take_error (page_flip_data, g_error_copy (error));
meta_kms_queue_callback (kms,
meta_kms_page_flip_data_discard,
meta_kms_page_flip_data_ref (page_flip_data),
(GDestroyNotify) meta_kms_page_flip_data_unref);
}

View File

@ -27,6 +27,7 @@
#include "backends/meta-monitor-transform.h" #include "backends/meta-monitor-transform.h"
#include "backends/native/meta-kms-crtc.h" #include "backends/native/meta-kms-crtc.h"
#include "backends/native/meta-kms-impl-device.h" #include "backends/native/meta-kms-impl-device.h"
#include "backends/native/meta-kms-update-private.h"
struct _MetaKmsPlane struct _MetaKmsPlane
{ {
@ -53,6 +54,12 @@ struct _MetaKmsPlane
G_DEFINE_TYPE (MetaKmsPlane, meta_kms_plane, G_TYPE_OBJECT) G_DEFINE_TYPE (MetaKmsPlane, meta_kms_plane, G_TYPE_OBJECT)
MetaKmsDevice *
meta_kms_plane_get_device (MetaKmsPlane *plane)
{
return plane->device;
}
uint32_t uint32_t
meta_kms_plane_get_id (MetaKmsPlane *plane) meta_kms_plane_get_id (MetaKmsPlane *plane)
{ {
@ -65,6 +72,18 @@ meta_kms_plane_get_plane_type (MetaKmsPlane *plane)
return plane->type; return plane->type;
} }
void
meta_kms_plane_update_set_rotation (MetaKmsPlane *plane,
MetaKmsPlaneAssignment *plane_assignment,
MetaMonitorTransform transform)
{
g_return_if_fail (meta_kms_plane_is_transform_handled (plane, transform));
meta_kms_plane_assignment_set_plane_property (plane_assignment,
plane->rotation_prop_id,
plane->rotation_map[transform]);
}
gboolean gboolean
meta_kms_plane_is_transform_handled (MetaKmsPlane *plane, meta_kms_plane_is_transform_handled (MetaKmsPlane *plane,
MetaMonitorTransform transform) MetaMonitorTransform transform)

View File

@ -43,6 +43,8 @@ MetaKmsPlane * meta_kms_plane_new (MetaKmsPlaneType type,
drmModePlane *drm_plane, drmModePlane *drm_plane,
drmModeObjectProperties *drm_plane_props); drmModeObjectProperties *drm_plane_props);
MetaKmsDevice * meta_kms_plane_get_device (MetaKmsPlane *plane);
uint32_t meta_kms_plane_get_id (MetaKmsPlane *plane); uint32_t meta_kms_plane_get_id (MetaKmsPlane *plane);
MetaKmsPlaneType meta_kms_plane_get_plane_type (MetaKmsPlane *plane); MetaKmsPlaneType meta_kms_plane_get_plane_type (MetaKmsPlane *plane);
@ -61,4 +63,8 @@ gboolean meta_kms_plane_is_format_supported (MetaKmsPlane *plane,
gboolean meta_kms_plane_is_usable_with (MetaKmsPlane *plane, gboolean meta_kms_plane_is_usable_with (MetaKmsPlane *plane,
MetaKmsCrtc *crtc); MetaKmsCrtc *crtc);
void meta_kms_plane_update_set_rotation (MetaKmsPlane *plane,
MetaKmsPlaneAssignment *plane_assignment,
MetaMonitorTransform transform);
#endif /* META_KMS_PLANE_H */ #endif /* META_KMS_PLANE_H */

View File

@ -36,14 +36,17 @@ void meta_kms_queue_callback (MetaKms *kms,
gpointer user_data, gpointer user_data,
GDestroyNotify user_data_destroy); GDestroyNotify user_data_destroy);
int meta_kms_flush_callbacks (MetaKms *kms);
gboolean meta_kms_run_impl_task_sync (MetaKms *kms, gboolean meta_kms_run_impl_task_sync (MetaKms *kms,
MetaKmsImplTaskFunc func, MetaKmsImplTaskFunc func,
gpointer user_data, gpointer user_data,
GError **error); GError **error);
GSource * meta_kms_add_source_in_impl (MetaKms *kms, GSource * meta_kms_add_source_in_impl (MetaKms *kms,
GSourceFunc func, GSourceFunc func,
gpointer user_data); gpointer user_data,
GDestroyNotify user_data_destroy);
GSource * meta_kms_register_fd_in_impl (MetaKms *kms, GSource * meta_kms_register_fd_in_impl (MetaKms *kms,
int fd, int fd,

View File

@ -20,6 +20,8 @@
#ifndef META_KMS_IMPL_TYPES_H #ifndef META_KMS_IMPL_TYPES_H
#define META_KMS_IMPL_TYPES_H #define META_KMS_IMPL_TYPES_H
#include <stdint.h>
typedef struct _MetaKms MetaKms; typedef struct _MetaKms MetaKms;
typedef struct _MetaKmsDevice MetaKmsDevice; typedef struct _MetaKmsDevice MetaKmsDevice;
@ -27,9 +29,26 @@ typedef struct _MetaKmsPlane MetaKmsPlane;
typedef struct _MetaKmsCrtc MetaKmsCrtc; typedef struct _MetaKmsCrtc MetaKmsCrtc;
typedef struct _MetaKmsConnector MetaKmsConnector; typedef struct _MetaKmsConnector MetaKmsConnector;
typedef struct _MetaKmsUpdate MetaKmsUpdate;
typedef struct _MetaKmsPlaneAssignment MetaKmsPlaneAssignment;
typedef struct _MetaKmsModeSet MetaKmsModeSet;
typedef struct _MetaKmsPageFlipFeedback MetaKmsPageFlipFeedback;
typedef struct _MetaKmsImpl MetaKmsImpl; typedef struct _MetaKmsImpl MetaKmsImpl;
typedef struct _MetaKmsImplDevice MetaKmsImplDevice; typedef struct _MetaKmsImplDevice MetaKmsImplDevice;
/* 16:16 fixed point */
typedef int32_t MetaFixed16;
typedef struct _MetaFixed16Rectangle
{
MetaFixed16 x;
MetaFixed16 y;
MetaFixed16 width;
MetaFixed16 height;
} MetaFixed16Rectangle;
typedef enum _MetaKmsDeviceFlag typedef enum _MetaKmsDeviceFlag
{ {
META_KMS_DEVICE_FLAG_NONE = 0, META_KMS_DEVICE_FLAG_NONE = 0,

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2019 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_KMS_UPDATE_PRIVATE_H
#define META_KMS_UPDATE_PRIVATE_H
#include <glib.h>
#include <stdint.h>
#include "backends/native/meta-kms-types.h"
#include "backends/native/meta-kms-update.h"
typedef struct _MetaKmsProperty
{
uint32_t prop_id;
uint64_t value;
} MetaKmsProperty;
typedef struct _MetaKmsPlaneAssignment
{
MetaKmsCrtc *crtc;
MetaKmsPlane *plane;
uint32_t fb_id;
MetaFixed16Rectangle src_rect;
MetaFixed16Rectangle dst_rect;
GList *plane_properties;
} MetaKmsPlaneAssignment;
typedef struct _MetaKmsModeSet
{
MetaKmsCrtc *crtc;
GList *connectors;
drmModeModeInfo *drm_mode;
} MetaKmsModeSet;
typedef struct _MetaKmsConnectorProperty
{
MetaKmsDevice *device;
MetaKmsConnector *connector;
uint32_t prop_id;
uint64_t value;
} MetaKmsConnectorProperty;
typedef struct _MetaKmsPageFlip
{
MetaKmsCrtc *crtc;
const MetaKmsPageFlipFeedback *feedback;
gpointer user_data;
MetaKmsCustomPageFlipFunc custom_page_flip_func;
gpointer custom_page_flip_user_data;
} MetaKmsPageFlip;
void meta_kms_update_set_connector_property (MetaKmsUpdate *update,
MetaKmsConnector *connector,
uint32_t prop_id,
uint64_t value);
void meta_kms_plane_assignment_set_plane_property (MetaKmsPlaneAssignment *plane_assignment,
uint32_t prop_id,
uint64_t value);
GList * meta_kms_update_get_plane_assignments (MetaKmsUpdate *update);
GList * meta_kms_update_get_mode_sets (MetaKmsUpdate *update);
GList * meta_kms_update_get_page_flips (MetaKmsUpdate *update);
GList * meta_kms_update_get_connector_properties (MetaKmsUpdate *update);
gboolean meta_kms_update_has_mode_set (MetaKmsUpdate *update);
#endif /* META_KMS_UPDATE_PRIVATE_H */

View File

@ -0,0 +1,236 @@
/*
* Copyright (C) 2018 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "config.h"
#include "backends/native/meta-kms-update.h"
#include "backends/native/meta-kms-update-private.h"
#include "backends/meta-display-config-shared.h"
#include "backends/native/meta-kms-plane.h"
struct _MetaKmsUpdate
{
MetaPowerSave power_save;
GList *mode_sets;
GList *plane_assignments;
GList *page_flips;
GList *connector_properties;
};
static MetaKmsProperty *
meta_kms_property_new (uint32_t prop_id,
uint64_t value)
{
MetaKmsProperty *prop;
prop = g_new0 (MetaKmsProperty, 1);
*prop = (MetaKmsProperty) {
.prop_id = prop_id,
.value = value,
};
return prop;
}
static void
meta_kms_property_free (MetaKmsProperty *prop)
{
g_free (prop);
}
static void
meta_kms_plane_assignment_free (MetaKmsPlaneAssignment *plane_assignment)
{
g_list_free_full (plane_assignment->plane_properties,
(GDestroyNotify) meta_kms_property_free);
g_free (plane_assignment);
}
static void
meta_kms_mode_set_free (MetaKmsModeSet *mode_set)
{
g_free (mode_set->drm_mode);
g_list_free (mode_set->connectors);
g_free (mode_set);
}
MetaKmsPlaneAssignment *
meta_kms_update_assign_plane (MetaKmsUpdate *update,
MetaKmsCrtc *crtc,
MetaKmsPlane *plane,
uint32_t fb_id,
MetaFixed16Rectangle src_rect,
MetaFixed16Rectangle dst_rect)
{
MetaKmsPlaneAssignment *plane_assignment;
plane_assignment = g_new0 (MetaKmsPlaneAssignment, 1);
*plane_assignment = (MetaKmsPlaneAssignment) {
.crtc = crtc,
.plane = plane,
.fb_id = fb_id,
.src_rect = src_rect,
.dst_rect = dst_rect,
};
update->plane_assignments = g_list_prepend (update->plane_assignments,
plane_assignment);
return plane_assignment;
}
void
meta_kms_update_mode_set (MetaKmsUpdate *update,
MetaKmsCrtc *crtc,
GList *connectors,
drmModeModeInfo *drm_mode)
{
MetaKmsModeSet *mode_set;
mode_set = g_new0 (MetaKmsModeSet, 1);
*mode_set = (MetaKmsModeSet) {
.crtc = crtc,
.connectors = connectors,
.drm_mode = drm_mode ? g_memdup (drm_mode, sizeof *drm_mode) : NULL,
};
update->mode_sets = g_list_prepend (update->mode_sets, mode_set);
}
void
meta_kms_update_set_connector_property (MetaKmsUpdate *update,
MetaKmsConnector *connector,
uint32_t prop_id,
uint64_t value)
{
MetaKmsConnectorProperty *prop;
prop = g_new0 (MetaKmsConnectorProperty, 1);
*prop = (MetaKmsConnectorProperty) {
.connector = connector,
.prop_id = prop_id,
.value = value,
};
update->connector_properties = g_list_prepend (update->connector_properties,
prop);
}
void
meta_kms_update_page_flip (MetaKmsUpdate *update,
MetaKmsCrtc *crtc,
const MetaKmsPageFlipFeedback *feedback,
gpointer user_data)
{
MetaKmsPageFlip *page_flip;
page_flip = g_new0 (MetaKmsPageFlip, 1);
*page_flip = (MetaKmsPageFlip) {
.crtc = crtc,
.feedback = feedback,
.user_data = user_data,
};
update->page_flips = g_list_prepend (update->page_flips, page_flip);
}
void
meta_kms_update_custom_page_flip (MetaKmsUpdate *update,
MetaKmsCrtc *crtc,
const MetaKmsPageFlipFeedback *feedback,
gpointer user_data,
MetaKmsCustomPageFlipFunc custom_page_flip_func,
gpointer custom_page_flip_user_data)
{
MetaKmsPageFlip *page_flip;
page_flip = g_new0 (MetaKmsPageFlip, 1);
*page_flip = (MetaKmsPageFlip) {
.crtc = crtc,
.feedback = feedback,
.user_data = user_data,
.custom_page_flip_func = custom_page_flip_func,
.custom_page_flip_user_data = custom_page_flip_user_data,
};
update->page_flips = g_list_prepend (update->page_flips, page_flip);
}
void
meta_kms_plane_assignment_set_plane_property (MetaKmsPlaneAssignment *plane_assignment,
uint32_t prop_id,
uint64_t value)
{
MetaKmsProperty *plane_prop;
plane_prop = meta_kms_property_new (prop_id, value);
plane_assignment->plane_properties =
g_list_prepend (plane_assignment->plane_properties, plane_prop);
}
GList *
meta_kms_update_get_plane_assignments (MetaKmsUpdate *update)
{
return update->plane_assignments;
}
GList *
meta_kms_update_get_mode_sets (MetaKmsUpdate *update)
{
return update->mode_sets;
}
GList *
meta_kms_update_get_page_flips (MetaKmsUpdate *update)
{
return update->page_flips;
}
GList *
meta_kms_update_get_connector_properties (MetaKmsUpdate *update)
{
return update->connector_properties;
}
gboolean
meta_kms_update_has_mode_set (MetaKmsUpdate *update)
{
return !!update->mode_sets;
}
MetaKmsUpdate *
meta_kms_update_new (void)
{
return g_new0 (MetaKmsUpdate, 1);
}
void
meta_kms_update_free (MetaKmsUpdate *update)
{
g_list_free_full (update->plane_assignments,
(GDestroyNotify) meta_kms_plane_assignment_free);
g_list_free_full (update->mode_sets,
(GDestroyNotify) meta_kms_mode_set_free);
g_list_free_full (update->page_flips, g_free);
g_list_free_full (update->connector_properties, g_free);
g_free (update);
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2018 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_KMS_UPDATE_H
#define META_KMS_UPDATE_H
#include <glib-object.h>
#include <glib.h>
#include <stdint.h>
#include <xf86drmMode.h>
#include "backends/meta-monitor-transform.h"
#include "backends/native/meta-kms-types.h"
struct _MetaKmsPageFlipFeedback
{
void (* flipped) (MetaKmsCrtc *crtc,
unsigned int sequence,
unsigned int tv_sec,
unsigned int tv_usec,
gpointer user_data);
void (* mode_set_fallback) (MetaKmsCrtc *crtc,
gpointer user_data);
void (* discarded) (MetaKmsCrtc *crtc,
gpointer user_data,
const GError *error);
};
typedef int (* MetaKmsCustomPageFlipFunc) (gpointer custom_page_flip_data,
gpointer user_data);
MetaKmsUpdate * meta_kms_update_new (void);
void meta_kms_update_free (MetaKmsUpdate *update);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaKmsUpdate, meta_kms_update_free)
void meta_kms_update_mode_set (MetaKmsUpdate *update,
MetaKmsCrtc *crtc,
GList *connectors,
drmModeModeInfo *drm_mode);
MetaKmsPlaneAssignment * meta_kms_update_assign_plane (MetaKmsUpdate *update,
MetaKmsCrtc *crtc,
MetaKmsPlane *plane,
uint32_t fb_id,
MetaFixed16Rectangle src_rect,
MetaFixed16Rectangle dst_rect);
void meta_kms_update_page_flip (MetaKmsUpdate *update,
MetaKmsCrtc *crtc,
const MetaKmsPageFlipFeedback *feedback,
gpointer user_data);
void meta_kms_update_custom_page_flip (MetaKmsUpdate *update,
MetaKmsCrtc *crtc,
const MetaKmsPageFlipFeedback *feedback,
gpointer user_data,
MetaKmsCustomPageFlipFunc custom_page_flip_func,
gpointer custom_page_flip_user_data);
static inline MetaFixed16
meta_fixed_16_from_int (int16_t d)
{
return d * 65536;
}
static inline int16_t
meta_fixed_16_to_int (MetaFixed16 fixed)
{
return fixed / 65536;
}
#endif /* META_KMS_UPDATE_H */

View File

@ -25,6 +25,7 @@
#include "backends/native/meta-kms-device-private.h" #include "backends/native/meta-kms-device-private.h"
#include "backends/native/meta-kms-impl.h" #include "backends/native/meta-kms-impl.h"
#include "backends/native/meta-kms-impl-simple.h" #include "backends/native/meta-kms-impl-simple.h"
#include "backends/native/meta-kms-update-private.h"
#include "backends/native/meta-udev.h" #include "backends/native/meta-udev.h"
typedef struct _MetaKmsCallbackData typedef struct _MetaKmsCallbackData
@ -64,12 +65,86 @@ struct _MetaKms
GList *devices; GList *devices;
MetaKmsUpdate *pending_update;
GList *pending_callbacks; GList *pending_callbacks;
guint callback_source_id; guint callback_source_id;
}; };
G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT) G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT)
static void
meta_kms_update_states_in_impl (MetaKms *kms);
MetaKmsUpdate *
meta_kms_ensure_pending_update (MetaKms *kms)
{
if (!kms->pending_update)
kms->pending_update = meta_kms_update_new ();
return meta_kms_get_pending_update (kms);
}
MetaKmsUpdate *
meta_kms_get_pending_update (MetaKms *kms)
{
return kms->pending_update;
}
static gboolean
meta_kms_update_process_in_impl (MetaKmsImpl *impl,
gpointer user_data,
GError **error)
{
g_autoptr (MetaKmsUpdate) update = user_data;
gboolean ret;
ret = meta_kms_impl_process_update (impl, update, error);
if (meta_kms_update_has_mode_set (update))
meta_kms_update_states_in_impl (meta_kms_impl_get_kms (impl));
return ret;
}
static gboolean
meta_kms_post_update_sync (MetaKms *kms,
MetaKmsUpdate *update,
GError **error)
{
return meta_kms_run_impl_task_sync (kms,
meta_kms_update_process_in_impl,
update,
error);
}
gboolean
meta_kms_post_pending_update_sync (MetaKms *kms,
GError **error)
{
return meta_kms_post_update_sync (kms,
g_steal_pointer (&kms->pending_update),
error);
}
static gboolean
meta_kms_discard_pending_page_flips_in_impl (MetaKmsImpl *impl,
gpointer user_data,
GError **error)
{
meta_kms_impl_discard_pending_page_flips (impl);
return TRUE;
}
void
meta_kms_discard_pending_page_flips (MetaKms *kms)
{
meta_kms_run_impl_task_sync (kms,
meta_kms_discard_pending_page_flips_in_impl,
NULL,
NULL);
}
static void static void
meta_kms_callback_data_free (MetaKmsCallbackData *callback_data) meta_kms_callback_data_free (MetaKmsCallbackData *callback_data)
{ {
@ -78,11 +153,11 @@ meta_kms_callback_data_free (MetaKmsCallbackData *callback_data)
g_slice_free (MetaKmsCallbackData, callback_data); g_slice_free (MetaKmsCallbackData, callback_data);
} }
static gboolean static int
callback_idle (gpointer user_data) flush_callbacks (MetaKms *kms)
{ {
MetaKms *kms = user_data;
GList *l; GList *l;
int callback_count = 0;
for (l = kms->pending_callbacks; l; l = l->next) for (l = kms->pending_callbacks; l; l = l->next)
{ {
@ -90,11 +165,22 @@ callback_idle (gpointer user_data)
callback_data->callback (kms, callback_data->user_data); callback_data->callback (kms, callback_data->user_data);
meta_kms_callback_data_free (callback_data); meta_kms_callback_data_free (callback_data);
callback_count++;
} }
g_list_free (kms->pending_callbacks); g_list_free (kms->pending_callbacks);
kms->pending_callbacks = NULL; kms->pending_callbacks = NULL;
return callback_count;
}
static gboolean
callback_idle (gpointer user_data)
{
MetaKms *kms = user_data;
flush_callbacks (kms);
kms->callback_source_id = 0; kms->callback_source_id = 0;
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
@ -119,6 +205,17 @@ meta_kms_queue_callback (MetaKms *kms,
kms->callback_source_id = g_idle_add (callback_idle, kms); kms->callback_source_id = g_idle_add (callback_idle, kms);
} }
int
meta_kms_flush_callbacks (MetaKms *kms)
{
int callback_count;
callback_count = flush_callbacks (kms);
g_clear_handle_id (&kms->callback_source_id, g_source_remove);
return callback_count;
}
gboolean gboolean
meta_kms_run_impl_task_sync (MetaKms *kms, meta_kms_run_impl_task_sync (MetaKms *kms,
MetaKmsImplTaskFunc func, MetaKmsImplTaskFunc func,
@ -156,9 +253,10 @@ static GSourceFuncs simple_impl_source_funcs = {
}; };
GSource * GSource *
meta_kms_add_source_in_impl (MetaKms *kms, meta_kms_add_source_in_impl (MetaKms *kms,
GSourceFunc func, GSourceFunc func,
gpointer user_data) gpointer user_data,
GDestroyNotify user_data_destroy)
{ {
GSource *source; GSource *source;
MetaKmsSimpleImplSource *simple_impl_source; MetaKmsSimpleImplSource *simple_impl_source;
@ -170,7 +268,7 @@ meta_kms_add_source_in_impl (MetaKms *kms,
simple_impl_source = (MetaKmsSimpleImplSource *) source; simple_impl_source = (MetaKmsSimpleImplSource *) source;
simple_impl_source->kms = kms; simple_impl_source->kms = kms;
g_source_set_callback (source, func, user_data, NULL); g_source_set_callback (source, func, user_data, user_data_destroy);
g_source_attach (source, g_main_context_get_thread_default ()); g_source_attach (source, g_main_context_get_thread_default ());
return source; return source;
@ -245,14 +343,13 @@ meta_kms_in_impl_task (MetaKms *kms)
return kms->in_impl_task; return kms->in_impl_task;
} }
static gboolean static void
update_states_in_impl (MetaKmsImpl *impl, meta_kms_update_states_in_impl (MetaKms *kms)
gpointer user_data,
GError **error)
{ {
MetaKms *kms = user_data;
GList *l; GList *l;
meta_assert_in_kms_impl (kms);
for (l = kms->devices; l; l = l->next) for (l = kms->devices; l; l = l->next)
{ {
MetaKmsDevice *device = l->data; MetaKmsDevice *device = l->data;
@ -260,6 +357,16 @@ update_states_in_impl (MetaKmsImpl *impl,
meta_kms_impl_device_update_states (impl_device); meta_kms_impl_device_update_states (impl_device);
} }
}
static gboolean
update_states_in_impl (MetaKmsImpl *impl,
gpointer user_data,
GError **error)
{
MetaKms *kms = user_data;
meta_kms_update_states_in_impl (kms);
return TRUE; return TRUE;
} }

View File

@ -28,6 +28,15 @@
#define META_TYPE_KMS (meta_kms_get_type ()) #define META_TYPE_KMS (meta_kms_get_type ())
G_DECLARE_FINAL_TYPE (MetaKms, meta_kms, META, KMS, GObject) G_DECLARE_FINAL_TYPE (MetaKms, meta_kms, META, KMS, GObject)
MetaKmsUpdate * meta_kms_ensure_pending_update (MetaKms *kms);
MetaKmsUpdate * meta_kms_get_pending_update (MetaKms *kms);
gboolean meta_kms_post_pending_update_sync (MetaKms *kms,
GError **error);
void meta_kms_discard_pending_page_flips (MetaKms *kms);
MetaBackend * meta_kms_get_backend (MetaKms *kms); MetaBackend * meta_kms_get_backend (MetaKms *kms);
MetaKmsDevice * meta_kms_create_device (MetaKms *kms, MetaKmsDevice * meta_kms_create_device (MetaKms *kms,

View File

@ -54,6 +54,8 @@
#include "backends/native/meta-backend-native.h" #include "backends/native/meta-backend-native.h"
#include "backends/native/meta-crtc-kms.h" #include "backends/native/meta-crtc-kms.h"
#include "backends/native/meta-gpu-kms.h" #include "backends/native/meta-gpu-kms.h"
#include "backends/native/meta-kms-update.h"
#include "backends/native/meta-kms.h"
#include "backends/native/meta-launcher.h" #include "backends/native/meta-launcher.h"
#include "backends/native/meta-output-kms.h" #include "backends/native/meta-output-kms.h"
#include "backends/native/meta-renderer-native.h" #include "backends/native/meta-renderer-native.h"
@ -115,6 +117,11 @@ static void
meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
MetaPowerSave mode) MetaPowerSave mode)
{ {
MetaBackend *backend = meta_monitor_manager_get_backend (manager);
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
MetaKms *kms = meta_backend_native_get_kms (backend_native);
MetaKmsUpdate *kms_update;
g_autoptr (GError) error = NULL;
uint64_t state; uint64_t state;
GList *l; GList *l;
@ -135,12 +142,16 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
return; return;
} }
for (l = meta_backend_get_gpus (manager->backend); l; l = l->next) kms_update = meta_kms_ensure_pending_update (kms);
for (l = meta_backend_get_gpus (backend); l; l = l->next)
{ {
MetaGpuKms *gpu_kms = l->data; MetaGpuKms *gpu_kms = l->data;
meta_gpu_kms_set_power_save_mode (gpu_kms, state); meta_gpu_kms_set_power_save_mode (gpu_kms, state, kms_update);
} }
if (!meta_kms_post_pending_update_sync (kms, &error))
g_warning ("Failed to DPMS: %s", error->message);
} }
static void static void
@ -214,8 +225,6 @@ apply_crtc_assignments (MetaMonitorManager *manager,
meta_output_assign_crtc (output, crtc); meta_output_assign_crtc (output, crtc);
} }
} }
meta_crtc_kms_apply_transform (crtc);
} }
/* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE, /* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE,
because they weren't seen in the first loop) */ because they weren't seen in the first loop) */
@ -253,8 +262,6 @@ apply_crtc_assignments (MetaMonitorManager *manager,
output->is_primary = output_info->is_primary; output->is_primary = output_info->is_primary;
output->is_presentation = output_info->is_presentation; output->is_presentation = output_info->is_presentation;
output->is_underscanning = output_info->is_underscanning; output->is_underscanning = output_info->is_underscanning;
meta_output_kms_set_underscan (output);
} }
/* Disable outputs not mentioned in the list */ /* Disable outputs not mentioned in the list */

View File

@ -42,67 +42,42 @@ typedef struct _MetaOutputKms
MetaOutput parent; MetaOutput parent;
MetaKmsConnector *kms_connector; MetaKmsConnector *kms_connector;
drmModeConnector *connector;
uint32_t dpms_prop_id;
uint32_t underscan_prop_id;
uint32_t underscan_hborder_prop_id;
uint32_t underscan_vborder_prop_id;
} MetaOutputKms; } MetaOutputKms;
void MetaKmsConnector *
meta_output_kms_set_underscan (MetaOutput *output) meta_output_kms_get_kms_connector (MetaOutput *output)
{ {
MetaOutputKms *output_kms = output->driver_private; MetaOutputKms *output_kms = output->driver_private;
MetaGpu *gpu = meta_output_get_gpu (output);
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
MetaCrtc *crtc;
int kms_fd;
uint32_t connector_id;
if (!output_kms->underscan_prop_id) return output_kms->kms_connector;
}
void
meta_output_kms_set_underscan (MetaOutput *output,
MetaKmsUpdate *kms_update)
{
MetaOutputKms *output_kms = output->driver_private;
if (!output->supports_underscanning)
return; return;
crtc = meta_output_get_assigned_crtc (output); if (output->is_underscanning)
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
connector_id = output_kms->connector->connector_id;
if (output->is_underscanning && crtc && crtc->current_mode)
{ {
drmModeObjectSetProperty (kms_fd, connector_id, MetaCrtc *crtc;
DRM_MODE_OBJECT_CONNECTOR, uint64_t hborder, vborder;
output_kms->underscan_prop_id,
(uint64_t) 1);
if (output_kms->underscan_hborder_prop_id) crtc = meta_output_get_assigned_crtc (output);
{ hborder = MIN (128, (uint64_t) round (crtc->current_mode->width * 0.05));
uint64_t value; vborder = MIN (128, (uint64_t) round (crtc->current_mode->height * 0.05));
meta_kms_connector_set_underscanning (output_kms->kms_connector,
value = MIN (128, crtc->current_mode->width * 0.05); kms_update,
drmModeObjectSetProperty (kms_fd, connector_id, hborder,
DRM_MODE_OBJECT_CONNECTOR, vborder);
output_kms->underscan_hborder_prop_id,
value);
}
if (output_kms->underscan_vborder_prop_id)
{
uint64_t value;
value = MIN (128, crtc->current_mode->height * 0.05);
drmModeObjectSetProperty (kms_fd, connector_id,
DRM_MODE_OBJECT_CONNECTOR,
output_kms->underscan_vborder_prop_id,
value);
}
} }
else else
{ {
drmModeObjectSetProperty (kms_fd, connector_id, meta_kms_connector_unset_underscanning (output_kms->kms_connector,
DRM_MODE_OBJECT_CONNECTOR, kms_update);
output_kms->underscan_prop_id,
(uint64_t) 0);
} }
} }
@ -115,24 +90,15 @@ meta_output_kms_get_connector_id (MetaOutput *output)
} }
void void
meta_output_kms_set_power_save_mode (MetaOutput *output, meta_output_kms_set_power_save_mode (MetaOutput *output,
uint64_t state) uint64_t dpms_state,
MetaKmsUpdate *kms_update)
{ {
MetaOutputKms *output_kms = output->driver_private; MetaOutputKms *output_kms = output->driver_private;
MetaGpu *gpu = meta_output_get_gpu (output);
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
if (output_kms->dpms_prop_id != 0) meta_kms_connector_update_set_dpms_state (output_kms->kms_connector,
{ kms_update,
int fd; dpms_state);
fd = meta_gpu_kms_get_fd (gpu_kms);
if (drmModeObjectSetProperty (fd, output_kms->connector->connector_id,
DRM_MODE_OBJECT_CONNECTOR,
output_kms->dpms_prop_id, state) < 0)
g_warning ("Failed to set power save mode for output %s: %s",
output->name, strerror (errno));
}
} }
gboolean gboolean
@ -162,40 +128,6 @@ meta_output_kms_read_edid (MetaOutput *output)
return g_bytes_new_from_bytes (edid_data, 0, g_bytes_get_size (edid_data)); return g_bytes_new_from_bytes (edid_data, 0, g_bytes_get_size (edid_data));
} }
static void
find_connector_properties (MetaGpuKms *gpu_kms,
MetaOutput *output,
drmModeConnector *connector)
{
MetaOutputKms *output_kms = output->driver_private;
int fd;
int i;
fd = meta_gpu_kms_get_fd (gpu_kms);
for (i = 0; i < connector->count_props; i++)
{
drmModePropertyPtr prop = drmModeGetProperty (fd, connector->props[i]);
if (!prop)
continue;
if ((prop->flags & DRM_MODE_PROP_ENUM) &&
strcmp (prop->name, "DPMS") == 0)
output_kms->dpms_prop_id = prop->prop_id;
else if ((prop->flags & DRM_MODE_PROP_ENUM) &&
strcmp (prop->name, "underscan") == 0)
output_kms->underscan_prop_id = prop->prop_id;
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
strcmp (prop->name, "underscan hborder") == 0)
output_kms->underscan_hborder_prop_id = prop->prop_id;
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
strcmp (prop->name, "underscan vborder") == 0)
output_kms->underscan_vborder_prop_id = prop->prop_id;
drmModeFreeProperty (prop);
}
}
static void static void
meta_output_destroy_notify (MetaOutput *output) meta_output_destroy_notify (MetaOutput *output)
{ {
@ -344,7 +276,6 @@ init_output_modes (MetaOutput *output,
MetaOutput * MetaOutput *
meta_create_kms_output (MetaGpuKms *gpu_kms, meta_create_kms_output (MetaGpuKms *gpu_kms,
MetaKmsConnector *kms_connector, MetaKmsConnector *kms_connector,
drmModeConnector *connector,
MetaOutput *old_output, MetaOutput *old_output,
GError **error) GError **error)
{ {
@ -373,8 +304,6 @@ meta_create_kms_output (MetaGpuKms *gpu_kms,
output_kms->kms_connector = kms_connector; output_kms->kms_connector = kms_connector;
find_connector_properties (gpu_kms, output, connector);
connector_state = meta_kms_connector_get_current_state (kms_connector); connector_state = meta_kms_connector_get_current_state (kms_connector);
panel_orientation_transform = connector_state->panel_orientation_transform; panel_orientation_transform = connector_state->panel_orientation_transform;
@ -443,7 +372,8 @@ meta_create_kms_output (MetaGpuKms *gpu_kms,
output->suggested_x = connector_state->suggested_x; output->suggested_x = connector_state->suggested_x;
output->suggested_y = connector_state->suggested_y; output->suggested_y = connector_state->suggested_y;
output->hotplug_mode_update = connector_state->hotplug_mode_update; output->hotplug_mode_update = connector_state->hotplug_mode_update;
output->supports_underscanning = output_kms->underscan_prop_id != 0; output->supports_underscanning =
meta_kms_connector_is_underscanning_supported (kms_connector);
meta_output_parse_edid (output, connector_state->edid_data); meta_output_parse_edid (output, connector_state->edid_data);

View File

@ -27,21 +27,24 @@
#include "backends/native/meta-gpu-kms.h" #include "backends/native/meta-gpu-kms.h"
#include "backends/native/meta-kms-types.h" #include "backends/native/meta-kms-types.h"
void meta_output_kms_set_underscan (MetaOutput *output); void meta_output_kms_set_power_save_mode (MetaOutput *output,
uint64_t dpms_state,
MetaKmsUpdate *kms_update);
void meta_output_kms_set_power_save_mode (MetaOutput *output, void meta_output_kms_set_underscan (MetaOutput *output,
uint64_t state); MetaKmsUpdate *kms_update);
gboolean meta_output_kms_can_clone (MetaOutput *output, gboolean meta_output_kms_can_clone (MetaOutput *output,
MetaOutput *other_output); MetaOutput *other_output);
MetaKmsConnector * meta_output_kms_get_kms_connector (MetaOutput *output);
uint32_t meta_output_kms_get_connector_id (MetaOutput *output); uint32_t meta_output_kms_get_connector_id (MetaOutput *output);
GBytes * meta_output_kms_read_edid (MetaOutput *output); GBytes * meta_output_kms_read_edid (MetaOutput *output);
MetaOutput * meta_create_kms_output (MetaGpuKms *gpu_kms, MetaOutput * meta_create_kms_output (MetaGpuKms *gpu_kms,
MetaKmsConnector *kms_connector, MetaKmsConnector *kms_connector,
drmModeConnector *connector,
MetaOutput *old_output, MetaOutput *old_output,
GError **error); GError **error);

File diff suppressed because it is too large Load Diff

View File

@ -610,10 +610,15 @@ if have_native_backend
'backends/native/meta-kms-impl-simple.h', 'backends/native/meta-kms-impl-simple.h',
'backends/native/meta-kms-impl.c', 'backends/native/meta-kms-impl.c',
'backends/native/meta-kms-impl.h', 'backends/native/meta-kms-impl.h',
'backends/native/meta-kms-page-flip.c',
'backends/native/meta-kms-page-flip-private.h',
'backends/native/meta-kms-plane.c', 'backends/native/meta-kms-plane.c',
'backends/native/meta-kms-plane.h', 'backends/native/meta-kms-plane.h',
'backends/native/meta-kms-private.h', 'backends/native/meta-kms-private.h',
'backends/native/meta-kms-types.h', 'backends/native/meta-kms-types.h',
'backends/native/meta-kms-update-private.h',
'backends/native/meta-kms-update.c',
'backends/native/meta-kms-update.h',
'backends/native/meta-kms-utils.c', 'backends/native/meta-kms-utils.c',
'backends/native/meta-kms-utils.h', 'backends/native/meta-kms-utils.h',
'backends/native/meta-kms.c', 'backends/native/meta-kms.c',
@ -801,14 +806,6 @@ endif
subdir('meta') subdir('meta')
mutter_marshal = gnome.genmarshal('meta-marshal',
sources: ['meta-marshal.list'],
prefix: 'meta_marshal',
extra_args: ['--quiet'],
internal: true,
)
mutter_built_sources += mutter_marshal
mutter_built_sources += mutter_enum_types mutter_built_sources += mutter_enum_types
mutter_built_sources += mutter_version mutter_built_sources += mutter_version

View File

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